Skip to content

Commit

Permalink
mark: Fix offset and shorten-to
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-wolf committed Dec 23, 2023
1 parent e15d500 commit 3f694ec
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 42 deletions.
19 changes: 8 additions & 11 deletions src/mark.typ
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,17 @@
harpoon: style.harpoon,
)

drawables += mark.drawables
distance += mark.length
if not is-last {
distance += style.sep
} else if not style.reverse {
// The last mark with an inset needs to offset the
// distance, so that the path connects to the tip
distance -= mark.at("inset", default: 0)
}

// Shorten path to this mark
let inset = mark.at("inset", default: 0)
if style.shorten-to != none and (style.shorten-to == auto or i <= style.shorten-to) {
shorten-distance = distance
shorten-distance = distance + mark.length - inset
}

drawables += mark.drawables
distance += mark.length

// Add separator
distance += style.sep
}

return (
Expand Down
58 changes: 28 additions & 30 deletions src/path-util.typ
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@
/// - s (array): Path segment
/// -> float: Length of the segment in canvas units
#let _segment-length(s, samples: default-samples) = {
let (type, ..pts) = s
if type == "line" {
let (kind, ..pts) = s
if kind == "line" {
let len = 0
for i in range(1, pts.len()) {
len += vector.len(vector.sub(pts.at(i - 1), pts.at(i)))
}
return len
} else if type == "cubic" {
} else if kind == "cubic" {
return bezier.cubic-arclen(..pts, samples: samples)
} else {
panic("Invalid segment: " + type, s)
panic("Invalid segment: " + kind, s)
}
}

Expand Down Expand Up @@ -166,19 +166,11 @@
}
travelled += length
}
return if t >= 0 {
(index: if rev { 0 } else { segments.len() - 1 },
segment: segments.last(),
travelled: total,
distance: t - total,
length: lengths.last())
} else {
(index: if rev { segments.len() - 1 } else { 0 },
segment: segments.first(),
travelled: 0,
distance: t,
length: lengths.first())
}
return (index: if rev { 0 } else { segments.len() - 1 },
segment: segments.last(),
travelled: total,
distance: t,
length: lengths.last())
}

#let _extrapolated-point-on-segment(segment, distance, rev: false, samples: 100) = {
Expand Down Expand Up @@ -288,16 +280,26 @@

/// Shortens a segment by a given distance.
#let shorten-segment(segment, distance, mode: "CURVED", samples: default-samples) = {
let (type, ..s) = segment
if type == "line" {
let rev = distance < 0
let rev = distance < 0
if distance >= _segment-length(segment) {
return line-segment(if rev {
(segment-start(segment), segment-start(segment))
} else {
(segment-end(segment), segment-end(segment))
})
}

let (kind, ..s) = segment
if kind == "line" {
if rev {
distance *= -1
s = s.rev()
}
let (start, end, distance, length) = _points-between-distance(s, distance)
if length != 0 {
s = (vector.lerp(s.at(start), s.at(end), distance / length),) + s.slice(end)
}

s = (vector.lerp(s.at(start), s.at(end), distance / length),) + s.slice(end)
if rev {
s = s.rev()
}
Expand All @@ -308,7 +310,7 @@
bezier.cubic-shorten(..s, distance, samples: samples)
}
}
return (type,) + s
return (kind,) + s
}

/// Shortens a path's segments by the given distances. The start of the path is shortened first by moving the point along the line towards the end. The end of the path is then shortened in the same way. When a distance is 0 no other calculations are made.
Expand All @@ -320,16 +322,11 @@
#let shorten-path(segments, start-distance, end-distance, mode: "CURVED", samples: default-samples) = {
let total = length(segments)

// For empty paths, return a zero length line segment
if start-distance + end-distance >= total {
let pt = segment-start(segments.first())
return (line-segment((pt, pt)),)
}

if start-distance > 0 {
let (segment, distance, index, ..) = segment-at-t(
segments,
start-distance
start-distance,
clamp: true,
)
segments = segments.slice(index + 1)
segments.insert(0,
Expand All @@ -345,7 +342,8 @@
let (segment, distance, index, ..) = segment-at-t(
segments,
end-distance,
rev: true
rev: true,
clamp: true,
)
segments = segments.slice(0, index - 1)
segments.push(
Expand Down
Binary file modified tests/mark/multiple/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 29 additions & 1 deletion tests/mark/multiple/test.typ
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#set page(width: auto, height: auto)
#import "/src/lib.typ": *

#let l = (">", ">", ">",)
#let l = ("straight", "straight", "straight")

#box(stroke: 2pt + red, canvas({
import draw: *
Expand Down Expand Up @@ -55,3 +55,31 @@
arc((1,1), start: 180deg, stop: 360deg, anchor: "origin",
mark: (start: l, end: l, fill: red, stroke: blue))
}))

#box(stroke: 2pt + red, canvas({
import draw: *
line((-1,0), (0,1), (1,0),
mark: (start: l, end: l, fill: red, stroke: blue, shorten-to: 1))
bezier-through((-1,0), (0,-1), (1,0),
mark: (start: l, end: l, fill: red, stroke: blue, shorten-to: 1))
arc-through((-1,-1), (0,-2), (1,-1),
mark: (start: l, end: l, fill: red, stroke: blue, shorten-to: 1))
}))

// Test sep
#box(stroke: 2pt + red, canvas({
import draw: *
set-style(mark: (fill: white, shorten-to: 0))
line((-1,2), (1,2), mark: (end: ("o", "o", "o"), sep: 0.0))
line((-1,1), (1,1), mark: (end: ("o", "o", "o"), sep: 0.5))
line((-1,0), (1,0), mark: (end: ("o", "o", "o"), sep: 1.0))
}))

// Test offset
#box(stroke: 2pt + red, canvas({
import draw: *
set-style(mark: (fill: white, shorten-to: none))
line((-1,2), (1,2), mark: (end: ((symbol: "o", offset: 0.0), "o", "o")))
line((-1,1), (1,1), mark: (end: ((symbol: "o", offset: 0.5), "o", "o")))
line((-1,0), (1,0), mark: (end: ((symbol: "o", offset: 1.0), "o", "o")))
}))

0 comments on commit 3f694ec

Please sign in to comment.