Skip to content

Commit 7797809

Browse files
committed
Replace functions in path segment with methods and add documentation
1 parent c2f7a4b commit 7797809

File tree

12 files changed

+713
-403
lines changed

12 files changed

+713
-403
lines changed

libraries/path-bool/src/aabb.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
//
33
// SPDX-License-Identifier: MIT
44

5-
use crate::vector::Vector;
5+
use glam::DVec2;
66

77
#[derive(Clone, Copy, Debug, PartialEq)]
8-
pub struct AaBb {
8+
pub(crate) struct AaBb {
99
pub top: f64,
1010
pub right: f64,
1111
pub bottom: f64,
1212
pub left: f64,
1313
}
1414

15-
pub fn bounding_boxes_overlap(a: &AaBb, b: &AaBb) -> bool {
15+
pub(crate) fn bounding_boxes_overlap(a: &AaBb, b: &AaBb) -> bool {
1616
a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom
1717
}
1818

19-
pub fn merge_bounding_boxes(a: Option<AaBb>, b: &AaBb) -> AaBb {
19+
pub(crate) fn merge_bounding_boxes(a: Option<AaBb>, b: &AaBb) -> AaBb {
2020
match a {
2121
Some(a) => AaBb {
2222
top: a.top.min(b.top),
@@ -28,7 +28,7 @@ pub fn merge_bounding_boxes(a: Option<AaBb>, b: &AaBb) -> AaBb {
2828
}
2929
}
3030

31-
pub fn extend_bounding_box(bounding_box: Option<AaBb>, point: Vector) -> AaBb {
31+
pub(crate) fn extend_bounding_box(bounding_box: Option<AaBb>, point: DVec2) -> AaBb {
3232
match bounding_box {
3333
Some(bb) => AaBb {
3434
top: bb.top.min(point.y),
@@ -45,12 +45,11 @@ pub fn extend_bounding_box(bounding_box: Option<AaBb>, point: Vector) -> AaBb {
4545
}
4646
}
4747

48-
#[inline(never)]
49-
pub fn bounding_box_max_extent(bounding_box: &AaBb) -> f64 {
48+
pub(crate) fn bounding_box_max_extent(bounding_box: &AaBb) -> f64 {
5049
(bounding_box.right - bounding_box.left).max(bounding_box.bottom - bounding_box.top)
5150
}
5251

53-
pub fn bounding_box_around_point(point: Vector, padding: f64) -> AaBb {
52+
pub(crate) fn bounding_box_around_point(point: DVec2, padding: f64) -> AaBb {
5453
AaBb {
5554
top: point.y - padding,
5655
right: point.x + padding,
@@ -59,7 +58,7 @@ pub fn bounding_box_around_point(point: Vector, padding: f64) -> AaBb {
5958
}
6059
}
6160

62-
pub fn expand_bounding_box(bounding_box: &AaBb, padding: f64) -> AaBb {
61+
pub(crate) fn expand_bounding_box(bounding_box: &AaBb, padding: f64) -> AaBb {
6362
AaBb {
6463
top: bounding_box.top - padding,
6564
right: bounding_box.right + padding,

libraries/path-bool/src/intersection_path_segment.rs

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
//
33
// SPDX-License-Identifier: MIT
44

5+
use glam::DVec2;
6+
57
use crate::aabb::{bounding_box_max_extent, bounding_boxes_overlap, AaBb};
68
use crate::epsilons::Epsilons;
79
use crate::line_segment::{line_segment_intersection, line_segments_intersect};
810
use crate::line_segment_aabb::line_segment_aabb_intersect;
911
use crate::math::lerp;
10-
use crate::path_segment::{get_end_point, get_start_point, path_segment_bounding_box, sample_path_segment_at, split_segment_at, PathSegment};
11-
use crate::vector::{vectors_equal, Vector};
12+
use crate::path_segment::PathSegment;
1213

1314
#[derive(Clone)]
1415
struct IntersectionSegment {
@@ -20,26 +21,26 @@ struct IntersectionSegment {
2021

2122
#[inline(never)]
2223
fn subdivide_intersection_segment(int_seg: &IntersectionSegment) -> [IntersectionSegment; 2] {
23-
let (seg0, seg1) = split_segment_at(&int_seg.seg, 0.5);
24+
let (seg0, seg1) = int_seg.seg.split_at(0.5);
2425
let mid_param = (int_seg.start_param + int_seg.end_param) / 2.0;
2526
[
2627
IntersectionSegment {
2728
seg: seg0,
2829
start_param: int_seg.start_param,
2930
end_param: mid_param,
30-
bounding_box: path_segment_bounding_box(&seg0),
31+
bounding_box: seg0.bounding_box(),
3132
},
3233
IntersectionSegment {
3334
seg: seg1,
3435
start_param: mid_param,
3536
end_param: int_seg.end_param,
36-
bounding_box: path_segment_bounding_box(&seg1),
37+
bounding_box: seg1.bounding_box(),
3738
},
3839
]
3940
}
4041

4142
#[inline(never)]
42-
fn path_segment_to_line_segment(seg: &PathSegment) -> [Vector; 2] {
43+
fn path_segment_to_line_segment(seg: &PathSegment) -> [DVec2; 2] {
4344
match seg {
4445
PathSegment::Line(start, end) => [*start, *end],
4546
PathSegment::Cubic(start, _, _, end) => [*start, *end],
@@ -63,13 +64,13 @@ fn intersection_segments_overlap(seg0: &IntersectionSegment, seg1: &Intersection
6364
#[inline(never)]
6465
pub fn segments_equal(seg0: &PathSegment, seg1: &PathSegment, point_epsilon: f64) -> bool {
6566
match (*seg0, *seg1) {
66-
(PathSegment::Line(start0, end0), PathSegment::Line(start1, end1)) => vectors_equal(start0, start1, point_epsilon) && vectors_equal(end0, end1, point_epsilon),
67+
(PathSegment::Line(start0, end0), PathSegment::Line(start1, end1)) => start0.abs_diff_eq(start1, point_epsilon) && end0.abs_diff_eq(end1, point_epsilon),
6768
(PathSegment::Cubic(p00, p01, p02, p03), PathSegment::Cubic(p10, p11, p12, p13)) => {
68-
let start_and_end_equal = vectors_equal(p00, p10, point_epsilon) && vectors_equal(p03, p13, point_epsilon);
69+
let start_and_end_equal = p00.abs_diff_eq(p10, point_epsilon) && p03.abs_diff_eq(p13, point_epsilon);
6970

70-
let parameter_equal = vectors_equal(p01, p11, point_epsilon) && vectors_equal(p02, p12, point_epsilon);
71-
let direction1 = sample_path_segment_at(seg0, 0.1);
72-
let direction2 = sample_path_segment_at(seg1, 0.1);
71+
let parameter_equal = p01.abs_diff_eq(p11, point_epsilon) && p02.abs_diff_eq(p12, point_epsilon);
72+
let direction1 = seg0.sample_at(0.1);
73+
let direction2 = seg1.sample_at(0.1);
7374
let angles_equal = (direction1 - p00).angle_to(direction2 - p00).abs() < point_epsilon * 4.;
7475
if angles_equal {
7576
// eprintln!("deduplicating {:?} {:?} because the angles are equal", seg0, seg1);
@@ -78,16 +79,16 @@ pub fn segments_equal(seg0: &PathSegment, seg1: &PathSegment, point_epsilon: f64
7879
start_and_end_equal && (parameter_equal || angles_equal)
7980
}
8081
(PathSegment::Quadratic(p00, p01, p02), PathSegment::Quadratic(p10, p11, p12)) => {
81-
vectors_equal(p00, p10, point_epsilon) && vectors_equal(p01, p11, point_epsilon) && vectors_equal(p02, p12, point_epsilon)
82+
p00.abs_diff_eq(p10, point_epsilon) && p01.abs_diff_eq(p11, point_epsilon) && p02.abs_diff_eq(p12, point_epsilon)
8283
}
8384
(PathSegment::Arc(p00, rx0, ry0, angle0, large_arc0, sweep0, p01), PathSegment::Arc(p10, rx1, ry1, angle1, large_arc1, sweep1, p11)) => {
84-
vectors_equal(p00, p10, point_epsilon) &&
85+
p00.abs_diff_eq(p10, point_epsilon) &&
8586
(rx0 - rx1).abs() < point_epsilon &&
8687
(ry0 - ry1).abs() < point_epsilon &&
8788
(angle0 - angle1).abs() < point_epsilon && // TODO: Phi can be anything if rx = ry. Also, handle rotations by Pi/2.
8889
large_arc0 == large_arc1 &&
8990
sweep0 == sweep1 &&
90-
vectors_equal(p01, p11, point_epsilon)
91+
p01.abs_diff_eq(p11, point_epsilon)
9192
}
9293
_ => false,
9394
}
@@ -111,13 +112,13 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
111112
seg: *seg0,
112113
start_param: 0.0,
113114
end_param: 1.0,
114-
bounding_box: path_segment_bounding_box(seg0),
115+
bounding_box: seg0.bounding_box(),
115116
},
116117
IntersectionSegment {
117118
seg: *seg1,
118119
start_param: 0.0,
119120
end_param: 1.0,
120-
bounding_box: path_segment_bounding_box(seg1),
121+
bounding_box: seg1.bounding_box(),
121122
},
122123
)];
123124
let mut next_pairs = Vec::new();
@@ -188,10 +189,10 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
188189
}
189190

190191
fn calculate_overlap_intersections(seg0: &PathSegment, seg1: &PathSegment, eps: &Epsilons) -> Vec<[f64; 2]> {
191-
let start0 = get_start_point(seg0);
192-
let end0 = get_end_point(seg0);
193-
let start1 = get_start_point(seg1);
194-
let end1 = get_end_point(seg1);
192+
let start0 = seg0.start();
193+
let end0 = seg0.end();
194+
let start1 = seg1.start();
195+
let end1 = seg1.end();
195196

196197
let mut intersections = Vec::new();
197198

@@ -217,12 +218,12 @@ fn calculate_overlap_intersections(seg0: &PathSegment, seg1: &PathSegment, eps:
217218

218219
// Remove duplicates and sort intersections
219220
intersections.sort_unstable_by(|a, b| a[0].partial_cmp(&b[0]).unwrap());
220-
intersections.dedup_by(|a, b| vectors_equal(Vector::new(a[0], a[1]), Vector::new(b[0], b[1]), eps.param));
221+
intersections.dedup_by(|a, b| DVec2::from(*a).abs_diff_eq(DVec2::from(*b), eps.param));
221222

222223
// Handle special cases
223224
if intersections.is_empty() {
224225
// Check if segments are identical
225-
if vectors_equal(start0, start1, eps.point) && vectors_equal(end0, end1, eps.point) {
226+
if (start0.abs_diff_eq(start1, eps.point)) && end0.abs_diff_eq(end1, eps.point) {
226227
return vec![[0.0, 0.0], [1.0, 1.0]];
227228
}
228229
} else if intersections.len() > 2 {
@@ -233,21 +234,21 @@ fn calculate_overlap_intersections(seg0: &PathSegment, seg1: &PathSegment, eps:
233234
intersections
234235
}
235236

236-
fn find_point_on_segment(seg: &PathSegment, point: Vector, eps: &Epsilons) -> Option<f64> {
237+
fn find_point_on_segment(seg: &PathSegment, point: DVec2, eps: &Epsilons) -> Option<f64> {
237238
let start = 0.0;
238239
let end = 1.0;
239240
let mut t = 0.5;
240241

241242
for _ in 0..32 {
242243
// Limit iterations to prevent infinite loops
243-
let current_point = sample_path_segment_at(seg, t);
244+
let current_point = seg.sample_at(t);
244245

245-
if vectors_equal(current_point, point, eps.point) {
246+
if current_point.abs_diff_eq(point, eps.point) {
246247
return Some(t);
247248
}
248249

249-
let start_point = sample_path_segment_at(seg, start);
250-
let end_point = sample_path_segment_at(seg, end);
250+
let start_point = seg.sample_at(start);
251+
let end_point = seg.sample_at(end);
251252

252253
let dist_start = (point - start_point).length_squared();
253254
let dist_end = (point - end_point).length_squared();

libraries/path-bool/src/lib.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ mod line_segment_aabb;
66
mod math;
77
mod path;
88
mod path_boolean;
9+
#[cfg(feature = "parsing")]
910
mod path_command;
1011
mod path_cubic_segment_self_intersection;
12+
#[cfg(feature = "parsing")]
1113
mod path_data;
1214
mod path_segment;
1315
mod quad_tree;
14-
mod vector;
1516
#[cfg(test)]
1617
mod visual_tests;
1718

1819
pub use intersection_path_segment::path_segment_intersection;
19-
pub use path_boolean::{path_boolean, FillRule, PathBooleanOperation, EPS};
20+
pub use path_boolean::{path_boolean, BooleanError, FillRule, PathBooleanOperation, EPS};
21+
#[cfg(feature = "parsing")]
2022
pub use path_data::{path_from_path_data, path_to_path_data};
2123
pub use path_segment::PathSegment;
2224

@@ -30,16 +32,8 @@ mod test {
3032

3133
#[test]
3234
fn square() {
33-
// let a = path_from_path_data(
34-
// "M 39,20 A 19,19 0 0 1 20,39 19,19 0 0 1 1,20 19,19 0 0 1 20,1 19,19 0 0 1 39,20 Z",
35-
// );
36-
// let b = path_from_path_data(
37-
// "M 47,28 A 19,19 0 0 1 28,47 19,19 0 0 1 9,28 19,19 0 0 1 28,9 19,19 0 0 1 47,28 Z",
38-
// );
3935
let a = path_from_path_data("M 10 10 L 50 10 L 30 40 Z");
4036
let b = path_from_path_data("M 20 30 L 60 30 L 60 50 L 20 50 Z");
41-
// let a = path_from_path_data("M 0 0 L 10 0 L 5 10 Z");
42-
// let b = path_from_path_data("M 0 5 L 10 5 L 5 15 Z");
4337
let union = path_boolean(
4438
&a,
4539
path_boolean::FillRule::NonZero,

libraries/path-bool/src/line_segment.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
//
33
// SPDX-License-Identifier: MIT
44

5-
use crate::vector::Vector;
5+
use glam::DVec2;
66

7-
pub type LineSegment = [Vector; 2];
7+
pub type LineSegment = [DVec2; 2];
88

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

libraries/path-bool/src/line_segment_aabb.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn out_code(x: f64, y: f64, bounding_box: &AaBb) -> u8 {
2929
code
3030
}
3131

32-
pub fn line_segment_aabb_intersect(seg: LineSegment, bounding_box: &AaBb) -> bool {
32+
pub(crate) fn line_segment_aabb_intersect(seg: LineSegment, bounding_box: &AaBb) -> bool {
3333
let [mut p0, mut p1] = seg;
3434

3535
let mut outcode0 = out_code(p0.x, p0.y, bounding_box);

libraries/path-bool/src/math.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// TODO(@TrueDoctor) check math
66

7-
use crate::vector::Vector;
7+
use glam::DVec2;
88
pub use std::f64::consts::PI;
99

1010
pub fn lin_map(value: f64, in_min: f64, in_max: f64, out_min: f64, out_max: f64) -> f64 {
@@ -15,11 +15,7 @@ pub fn lerp(a: f64, b: f64, t: f64) -> f64 {
1515
a + (b - a) * t
1616
}
1717

18-
pub fn deg2rad(deg: f64) -> f64 {
19-
(deg / 180.0) * PI
20-
}
21-
22-
pub fn vector_angle(u: Vector, v: Vector) -> f64 {
18+
pub fn vector_angle(u: DVec2, v: DVec2) -> f64 {
2319
const EPS: f64 = 1e-12;
2420

2521
let sign = u.x * v.y - u.y * v.x;

libraries/path-bool/src/path.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,20 @@ use glam::DVec2;
66

77
use crate::path_command::{to_absolute_commands, AbsolutePathCommand, PathCommand};
88
use crate::path_segment::PathSegment;
9-
use crate::vector::{vectors_equal, Vector};
109

1110
pub type Path = Vec<PathSegment>;
1211

13-
fn reflect_control_point(point: Vector, control_point: Vector) -> Vector {
12+
fn reflect_control_point(point: DVec2, control_point: DVec2) -> DVec2 {
1413
point * 2.0 - control_point
1514
}
1615

1716
pub fn path_from_commands<I>(commands: I) -> impl Iterator<Item = PathSegment>
1817
where
1918
I: IntoIterator<Item = PathCommand>,
2019
{
21-
let mut first_point: Option<Vector> = None;
22-
let mut last_point: Option<Vector> = None;
23-
let mut last_control_point: Option<Vector> = None;
20+
let mut first_point: Option<DVec2> = None;
21+
let mut last_point: Option<DVec2> = None;
22+
let mut last_control_point: Option<DVec2> = None;
2423

2524
to_absolute_commands(commands).filter_map(move |cmd| match cmd {
2625
AbsolutePathCommand::M(point) => {
@@ -95,13 +94,13 @@ pub fn path_to_commands<'a, I>(segments: I, eps: f64) -> impl Iterator<Item = Pa
9594
where
9695
I: IntoIterator<Item = &'a PathSegment> + 'a,
9796
{
98-
let mut last_point: Option<Vector> = None;
97+
let mut last_point: Option<DVec2> = None;
9998

10099
segments.into_iter().flat_map(move |seg| {
101-
let start = crate::path_segment::get_start_point(seg);
100+
let start = seg.start();
102101
let mut commands = Vec::new();
103102

104-
if last_point.map_or(true, |lp| !vectors_equal(start, lp, eps)) {
103+
if last_point.map_or(true, |lp| !start.abs_diff_eq(lp, eps)) {
105104
commands.push(PathCommand::Absolute(AbsolutePathCommand::M(start)));
106105
}
107106

0 commit comments

Comments
 (0)