-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathintersection.rs
More file actions
84 lines (76 loc) · 3.63 KB
/
Copy pathintersection.rs
File metadata and controls
84 lines (76 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use super::path::*;
use super::to_curves::*;
use super::super::curve::*;
use super::super::intersection::*;
use super::super::super::geo::*;
use super::super::super::line::*;
///
/// Determines the intersections of a path and a line
///
/// Intersections are returned as the path section index, the 't' parameter along that curve and the 't' value along the line:
/// ie: `(path_point_idx, curve_t, line_t)`.
///
pub fn path_intersects_line<'a, Path: BezierPath, L: Line<Point=Path::Point>>(path: &'a Path, line: &'a L) -> impl 'a+Iterator<Item=(usize, f64, f64)>
where
Path::Point: 'a+Coordinate2D,
{
path_to_curves::<_, Curve<_>>(path)
.enumerate()
.flat_map(move |(section_id, curve)| curve_intersects_line(&curve, line).into_iter().map(move |(t, s, _pos)| (section_id, t, s)))
}
///
/// Determines the intersections of a path and a ray.
///
/// Return value is `(path_point_idx, curve_t, line_t)`. Ray intersections differ from line intersections
/// in that there's no requirement for the result to be within the bounds of the supplied line (so any match in the direction of the line is
/// returned).
///
/// It's possible to filter for matches that occur after the start of the line by looking for results with an `s` value >= 0
///
pub fn path_intersects_ray<'a, Path: BezierPath, L: Line<Point=Path::Point>>(path: &'a Path, line: &'a L) -> impl 'a+Iterator<Item=(usize, f64, f64)>
where
Path::Point: 'a+Coordinate2D,
{
path_to_curves::<_, Curve<_>>(path)
.enumerate()
.flat_map(move |(section_id, curve)| curve_intersects_ray(&curve, line).into_iter().map(move |(t, s, _pos)| (section_id, t, s)))
}
///
/// Finds the points where a path intersects another path
///
/// Intersections are returned as (segment index, t-value), in pairs indicating the position on the first path
/// and the position on the second path. Intersections are unordered by default.
///
/// The accuracy value indicates the maximum errors that's permitted for an intersection: the bezier curve
/// intersection algorithm is approximate.
///
pub fn path_intersects_path<'a, Path: BezierPath>(path1: &'a Path, path2: &'a Path, accuracy: f64) -> Vec<((usize, f64), (usize, f64))>
where
Path::Point: 'a+Coordinate2D,
{
// Convert both paths to sections: also compute the bounding boxes for quick rejection of sections with no intersections
let path1_sections = path_to_curves::<_, Curve<_>>(path1)
.enumerate()
.map(|(section_id, curve)| (section_id, curve, curve.bounding_box::<Bounds<_>>()));
let path2_sections = path_to_curves::<_, Curve<_>>(path2)
.enumerate()
.map(|(section_id, curve)| (section_id, curve, curve.bounding_box::<Bounds<_>>()))
.collect::<Vec<_>>();
// Start generating the result
let mut result = vec![];
// Compare the sections in path1 to the sections in path2
// We iterate over path1 once...
for (p1_section_id, p1_curve, p1_curve_bounds) in path1_sections {
// But repeatedly interate over path2
for (p2_section_id, p2_curve, p2_curve_bounds) in path2_sections.iter() {
// Only search for intersections if these two sections have overlapping bounding boxes
if p1_curve_bounds.overlaps(p2_curve_bounds) {
// Determine the intersections (if any) between these two curves
let intersections = curve_intersects_curve_clip(&p1_curve, p2_curve, accuracy);
// Combine with the section IDs to generate the results
result.extend(intersections.into_iter().map(|(t1, t2)| ((p1_section_id, t1), (*p2_section_id, t2)) ));
}
}
}
result
}