Skip to content

Commit b19ec45

Browse files
committed
Add intersection benchmark
1 parent 06e00c6 commit b19ec45

File tree

7 files changed

+75
-4
lines changed

7 files changed

+75
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2+
use glam::DVec2;
3+
use path_bool::*;
4+
5+
pub fn criterion_benchmark(crit: &mut Criterion) {
6+
crit.bench_function("intersect 1", |bench| bench.iter(|| path_segment_intersection(&a(), &b(), true, &EPS)));
7+
crit.bench_function("intersect 2", |bench| bench.iter(|| path_segment_intersection(&c(), &d(), true, &EPS)));
8+
}
9+
10+
criterion_group!(benches, criterion_benchmark);
11+
criterion_main!(benches);
12+
13+
fn a() -> PathSegment {
14+
PathSegment::Cubic(
15+
DVec2::new(458.37027, 572.165771),
16+
DVec2::new(428.525848, 486.720093),
17+
DVec2::new(368.618805, 467.485992),
18+
DVec2::new(273.0, 476.0),
19+
)
20+
}
21+
fn b() -> PathSegment {
22+
PathSegment::Cubic(DVec2::new(273.0, 476.0), DVec2::new(419.0, 463.0), DVec2::new(481.741198, 514.692273), DVec2::new(481.333333, 768.0))
23+
}
24+
fn c() -> PathSegment {
25+
PathSegment::Cubic(DVec2::new(273.0, 476.0), DVec2::new(107.564178, 490.730591), DVec2::new(161.737915, 383.575775), DVec2::new(0.0, 340.0))
26+
}
27+
fn d() -> PathSegment {
28+
PathSegment::Cubic(DVec2::new(0.0, 340.0), DVec2::new(161.737914, 383.575765), DVec2::new(107.564182, 490.730587), DVec2::new(273.0, 476.0))
29+
}

libraries/path-bool/src/aabb.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub fn extend_bounding_box(bounding_box: Option<AaBb>, point: Vector) -> AaBb {
4545
}
4646
}
4747

48+
#[inline(never)]
4849
pub fn bounding_box_max_extent(bounding_box: &AaBb) -> f64 {
4950
(bounding_box.right - bounding_box.left).max(bounding_box.bottom - bounding_box.top)
5051
}

libraries/path-bool/src/intersection_path_segment.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct IntersectionSegment {
1818
bounding_box: AaBb,
1919
}
2020

21+
#[inline(never)]
2122
fn subdivide_intersection_segment(int_seg: &IntersectionSegment) -> [IntersectionSegment; 2] {
2223
let (seg0, seg1) = split_segment_at(&int_seg.seg, 0.5);
2324
let mid_param = (int_seg.start_param + int_seg.end_param) / 2.0;
@@ -37,6 +38,7 @@ fn subdivide_intersection_segment(int_seg: &IntersectionSegment) -> [Intersectio
3738
]
3839
}
3940

41+
#[inline(never)]
4042
fn path_segment_to_line_segment(seg: &PathSegment) -> [Vector; 2] {
4143
match seg {
4244
PathSegment::Line(start, end) => [*start, *end],
@@ -46,6 +48,7 @@ fn path_segment_to_line_segment(seg: &PathSegment) -> [Vector; 2] {
4648
}
4749
}
4850

51+
#[inline(never)]
4952
fn intersection_segments_overlap(seg0: &IntersectionSegment, seg1: &IntersectionSegment) -> bool {
5053
match (&seg0.seg, &seg1.seg) {
5154
(PathSegment::Line(start0, end0), PathSegment::Line(start1, end1)) => {
@@ -57,6 +60,7 @@ fn intersection_segments_overlap(seg0: &IntersectionSegment, seg1: &Intersection
5760
}
5861
}
5962

63+
#[inline(never)]
6064
pub fn segments_equal(seg0: &PathSegment, seg1: &PathSegment, point_epsilon: f64) -> bool {
6165
match (*seg0, *seg1) {
6266
(PathSegment::Line(start0, end0), PathSegment::Line(start1, end1)) => vectors_equal(start0, start1, point_epsilon) && vectors_equal(end0, end1, point_epsilon),
@@ -80,8 +84,6 @@ pub fn segments_equal(seg0: &PathSegment, seg1: &PathSegment, point_epsilon: f64
8084
}
8185

8286
pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoints: bool, eps: &Epsilons) -> Vec<[f64; 2]> {
83-
eprintln!("intersecting:");
84-
dbg!(seg0, seg1);
8587
// dbg!(&seg0, &seg1, endpoints);
8688
if let (PathSegment::Line(start0, end0), PathSegment::Line(start1, end1)) = (seg0, seg1) {
8789
if let Some(st) = line_segment_intersection([*start0, *end0], [*start1, *end1], eps.param) {
@@ -116,6 +118,7 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
116118

117119
while !pairs.is_empty() {
118120
next_pairs.clear();
121+
dbg!("checking pairs");
119122

120123
for (seg0, seg1) in pairs.iter() {
121124
if segments_equal(&seg0.seg, &seg1.seg, eps.point) {
@@ -130,6 +133,7 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
130133
let line_segment0 = path_segment_to_line_segment(&seg0.seg);
131134
let line_segment1 = path_segment_to_line_segment(&seg1.seg);
132135
if let Some(st) = line_segment_intersection(line_segment0, line_segment1, eps.param) {
136+
dbg!("pushing param");
133137
params.push([lerp(seg0.start_param, seg0.end_param, st.0), lerp(seg1.start_param, seg1.end_param, st.1)]);
134138
}
135139
} else {
@@ -165,3 +169,36 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
165169

166170
params
167171
}
172+
173+
#[cfg(test)]
174+
mod test {
175+
use super::*;
176+
use glam::DVec2;
177+
178+
#[test]
179+
fn intersect_cubic_slow_first() {
180+
path_segment_intersection(&a(), &b(), true, &crate::EPS);
181+
}
182+
#[test]
183+
fn intersect_cubic_slow_second() {
184+
path_segment_intersection(&c(), &d(), true, &crate::EPS);
185+
}
186+
187+
fn a() -> PathSegment {
188+
PathSegment::Cubic(
189+
DVec2::new(458.37027, 572.165771),
190+
DVec2::new(428.525848, 486.720093),
191+
DVec2::new(368.618805, 467.485992),
192+
DVec2::new(273.0, 476.0),
193+
)
194+
}
195+
fn b() -> PathSegment {
196+
PathSegment::Cubic(DVec2::new(273.0, 476.0), DVec2::new(419.0, 463.0), DVec2::new(481.741198, 514.692273), DVec2::new(481.333333, 768.0))
197+
}
198+
fn c() -> PathSegment {
199+
PathSegment::Cubic(DVec2::new(273.0, 476.0), DVec2::new(107.564178, 490.730591), DVec2::new(161.737915, 383.575775), DVec2::new(0.0, 340.0))
200+
}
201+
fn d() -> PathSegment {
202+
PathSegment::Cubic(DVec2::new(0.0, 340.0), DVec2::new(161.737914, 383.575765), DVec2::new(107.564182, 490.730587), DVec2::new(273.0, 476.0))
203+
}
204+
}

libraries/path-bool/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ mod vector;
1515
#[cfg(test)]
1616
mod visual_tests;
1717

18-
pub use path_boolean::{path_boolean, FillRule, PathBooleanOperation};
18+
pub use intersection_path_segment::path_segment_intersection;
19+
pub use path_boolean::{path_boolean, FillRule, PathBooleanOperation, EPS};
1920
pub use path_data::{path_from_path_data, path_to_path_data};
21+
pub use path_segment::PathSegment;
2022

2123
#[cfg(test)]
2224
mod test {

libraries/path-bool/src/line_segment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub type LineSegment = [Vector; 2];
88

99
const COLLINEAR_EPS: f64 = f64::EPSILON * 64.0;
1010

11+
#[inline(never)]
1112
pub fn line_segment_intersection([p1, p2]: LineSegment, [p3, p4]: LineSegment, eps: f64) -> Option<(f64, f64)> {
1213
// https://en.wikipedia.org/wiki/Intersection_(geometry)#Two_line_segments
1314

libraries/path-bool/src/path_boolean.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub enum FillRule {
4444
const INTERSECTION_TREE_DEPTH: usize = 8;
4545
const POINT_TREE_DEPTH: usize = 8;
4646

47-
const EPS: Epsilons = Epsilons {
47+
pub const EPS: Epsilons = Epsilons {
4848
point: 1e-6,
4949
linear: 1e-4,
5050
param: 1e-8,

0 commit comments

Comments
 (0)