Skip to content

Commit d91440f

Browse files
committed
Find closest point by name
1 parent bc95c80 commit d91440f

File tree

6 files changed

+63
-13
lines changed

6 files changed

+63
-13
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ package called `cetz-plot`.
2929
depth ordering and face culling of drawables. Ordering is enabled by default.
3030
- Closed `line` and `merge-path` elements now have a `"centroid"` anchor that
3131
is the calculated centroid of the (non self-intersecting!) shape.
32-
- Added `closest-point` for creating an anchor at the closest point between a
32+
- Added `find-closest-point` for creating an anchor at the closest point between a
3333
reference point and one or more elements.
3434

3535
## Marks

src/bezier.typ

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,14 @@
586586
return pts
587587
}
588588

589-
/// Find the closest point on a bezier to a given point
590-
/// by using a binary search along the curve.
589+
/// Find the closest point on a bezier to a given point.
590+
///
591+
/// - pt (vector): Reference point to find the closest point to
592+
/// - s (vector): Bezier start
593+
/// - e (vector): Bezier end
594+
/// - c1 (vector): Bezier control point 1
595+
/// - c2 (vector): Bezier control point 2
596+
/// - max-recursion (int): Max recursion depth
591597
#let cubic-closest-point(pt, s, e, c1, c2, max-recursion: 1) = {
592598
let probe(low, high, depth) = {
593599
let min = calc.inf

src/draw.typ

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#import "draw/grouping.typ": intersections, group, scope, anchor, copy-anchors, place-anchors, set-ctx, get-ctx, for-each-anchor, on-layer, place-marks, hide, floating, closest-point
1+
#import "draw/grouping.typ": intersections, group, scope, anchor, copy-anchors, place-anchors, set-ctx, get-ctx, for-each-anchor, on-layer, place-marks, hide, floating, find-closest-point
22
#import "draw/transformations.typ": set-transform, rotate, translate, scale, set-origin, move-to, set-viewport
33
#import "draw/styling.typ": set-style, fill, stroke
44
#import "draw/shapes.typ": circle, circle-through, arc, arc-through, mark, line, grid, content, rect, bezier, bezier-through, catmull, hobby, merge-path

src/draw/grouping.typ

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,24 +195,33 @@
195195
/// creates an anchor. Transformations insides the body are scoped and do
196196
/// not get applied outsides.
197197
///
198-
/// - name (string): Anchor name.
198+
/// - name (str): Anchor name.
199199
/// - reference-point (coordinate): Coordinate to find the closest point to.
200-
/// - body (element): One or more elements to consider. A least one is required. A function that accepts `ctx` and returns elements is also accepted.
201-
#let closest-point(name, reference-point, body) = {
200+
/// - body (element,str): One or more elements to consider. A least one is required. A function that accepts `ctx` and returns elements is also accepted. If a string is passed, the existing named element is used.
201+
#let find-closest-point(name, reference-point, body) = {
202202
import "/src/bezier.typ": cubic-closest-point
203203

204204
assert(type(name) == str,
205205
message: "Anchor name must be of type string, got " + repr(name))
206+
assert(type(body) in (array, function, str),
207+
message: "Expected body to be a list of elements, a callback or an elements name")
206208
coordinate.resolve-system(reference-point)
207209

208210
return (ctx => {
209211
let (_, pt) = coordinate.resolve(ctx, reference-point)
210212
pt = util.apply-transform(ctx.transform, pt)
211213

212-
let group-ctx = ctx
213-
group-ctx.groups.push(())
214-
let (ctx: group-ctx, drawables, bounds) = process.many(group-ctx, util.resolve-body(ctx, body))
215-
ctx.nodes += group-ctx.nodes
214+
let (sub-ctx, drawables, output-drawables) = if type(body) == str {
215+
let node = ctx.nodes.at(body)
216+
(ctx, node.drawables, false)
217+
} else {
218+
let group-ctx = ctx
219+
group-ctx.groups.push(())
220+
let node = process.many(group-ctx, util.resolve-body(ctx, body))
221+
(node.ctx, node.drawables, true)
222+
}
223+
224+
ctx.nodes += sub-ctx.nodes
216225

217226
let min = calc.inf
218227
let min-pt = none
@@ -269,8 +278,7 @@
269278
ctx: ctx,
270279
name: name,
271280
anchors: anchors,
272-
drawables: drawables,
273-
bounds: bounds
281+
drawables: if output-drawables { drawables } else { () },
274282
)
275283
},)
276284
}

tests/closest-point/ref/1.png

10.3 KB
Loading

tests/closest-point/test.typ

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#set page(width: auto, height: auto)
2+
#import "/tests/helper.typ": *
3+
4+
#test-case({
5+
import cetz.draw: *
6+
7+
group(name: "g", {
8+
rotate(10deg)
9+
rect((-1, -1), (1, 1), radius: .45)
10+
})
11+
12+
for i in range(0, 360, step: 10) {
13+
let pt = (i * 1deg, 2)
14+
15+
find-closest-point("test", pt, {
16+
rotate(10deg)
17+
hide(rect((-1, -1), (1, 1), radius: .45))
18+
})
19+
20+
line(pt, "test")
21+
circle(pt, radius: .1, fill: blue)
22+
}
23+
})
24+
25+
#test-case({
26+
import cetz.draw: *
27+
28+
group(name: "g", {
29+
rotate(10deg)
30+
rect((-1, -1), (1, 1), radius: .45)
31+
})
32+
33+
let pt = (2, 2)
34+
find-closest-point("test", pt, "g")
35+
line("test", pt)
36+
})

0 commit comments

Comments
 (0)