Skip to content

Commit

Permalink
intersection: Provide sort functions
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-wolf committed Nov 27, 2024
1 parent d717502 commit 13793f0
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 5 deletions.
13 changes: 12 additions & 1 deletion src/draw/grouping.typ
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,13 @@
/// - name (str): Name to prepend to the generated anchors. (Not to be confused with other `name` arguments that allow the use of anchor coordinates.)
/// - ..elements (elements,str): Elements and/or element names to calculate intersections with. Elements referred to by name are (unlike elements passed) not drawn by the intersections function!
/// - samples (int): Number of samples to use for non-linear path segments. A higher sample count can give more precise results but worse performance.
#let intersections(name, ..elements, samples: 10) = {
/// - sort (none,function): A function of the form `(context, array<vector>) -> array<vector>`
/// that gets called with the list of intersection points.
///
/// CeTZ provides the following sorting functions:
/// - sorting.points-by-distace(points, reference: (0, 0, 0))
/// - sorting.points-by-angle(points, reference: (0, 0, 0))
#let intersections(name, ..elements, samples: 10, sort: none) = {
samples = calc.clamp(samples, 2, 2500)

assert(type(name) == str and name != "",
Expand Down Expand Up @@ -169,6 +175,11 @@
}
}
}

if sort != none {
pts = (sort)(ctx, pts)
}

let anchors = (:)
for (i, pt) in pts.enumerate() {
anchors.insert(str(i), pt)
Expand Down
1 change: 1 addition & 0 deletions src/lib.typ
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#import "path-util.typ"
#import "mark.typ"
#import "mark-shapes.typ"
#import "sorting.typ"

// Libraries
#import "lib/palette.typ"
Expand Down
29 changes: 29 additions & 0 deletions src/sorting.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#import "/src/vector.typ"
#import "/src/util.typ"

/// Sort list of points by distance to a
/// reference point.
///
/// - points (array): List of points to sort
/// - reference (vec): Reference point
/// -> List of points
#let points-by-distance(ctx, points, reference: (0, 0, 0)) = {
let reference = util.apply-transform(ctx.transform, reference)
return points.sorted(key: pt => {
vector.dist(pt, reference)
})
}

/// Sort list of 2D points by angle to a
/// reference 2D point in CCW order.
/// Z component is ignored.
///
/// - points (array): List of points to sort
/// - reference (vec): Reference point
/// -> List of points
#let points-by-angle(ctx, points, reference: (0, 0, 0)) = {
let (rx, ry, ..) = util.apply-transform(ctx.transform, reference)
return points.sorted(key: ((px, py, ..)) => {
360deg - calc.atan2(rx - px, ry - py)
})
}
Binary file modified tests/intersection/ref/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 21 additions & 4 deletions tests/intersection/test.typ
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#set page(width: auto, height: auto)
#import "/src/lib.typ": *
#import "/tests/helper.typ": *

#let test(body) = canvas(length: 1cm, {
import draw: *
Expand Down Expand Up @@ -66,7 +67,7 @@
})
})

#box(stroke: 2pt + red, canvas({
#test-case({
import draw: *

intersections("i", {
Expand All @@ -76,9 +77,9 @@
line("a.default", "b.default", stroke: none)
})
line("i.0", "i.1", mark: (end: ">"))
}))
})

#box(stroke: 2pt + red, canvas({
#test-case({
import draw: *

circle((0,0), name: "a")
Expand All @@ -89,4 +90,20 @@
for-each-anchor("i", (name) => {
circle("i."+name, radius: .1, fill: red)
})
}))
})

#test-case(fn => {
import draw: *

let c = circle((1,1), name: "a", radius: 1.25)
let r = rect((0,0), (2,2), name: "b")
intersections("i", r, c, sort: fn)

for-each-anchor("i", (name) => {
content((), [#name], frame: "circle", fill: white)
})
}, args: (
none,
sorting.points-by-angle.with(reference: (1, 1)),
sorting.points-by-distance.with(reference: (0, 0.1)),
))

0 comments on commit 13793f0

Please sign in to comment.