@@ -7,7 +7,7 @@ use crate::epsilons::Epsilons;
7
7
use crate :: line_segment:: { line_segment_intersection, line_segments_intersect} ;
8
8
use crate :: line_segment_aabb:: line_segment_aabb_intersect;
9
9
use crate :: math:: lerp;
10
- use crate :: path_segment:: { path_segment_bounding_box, sample_path_segment_at, split_segment_at, PathSegment } ;
10
+ use crate :: path_segment:: { get_end_point , get_start_point , path_segment_bounding_box, sample_path_segment_at, split_segment_at, PathSegment } ;
11
11
use crate :: vector:: { vectors_equal, Vector } ;
12
12
13
13
#[ derive( Clone ) ]
@@ -65,7 +65,17 @@ pub fn segments_equal(seg0: &PathSegment, seg1: &PathSegment, point_epsilon: f64
65
65
match ( * seg0, * seg1) {
66
66
( PathSegment :: Line ( start0, end0) , PathSegment :: Line ( start1, end1) ) => vectors_equal ( start0, start1, point_epsilon) && vectors_equal ( end0, end1, point_epsilon) ,
67
67
( PathSegment :: Cubic ( p00, p01, p02, p03) , PathSegment :: Cubic ( p10, p11, p12, p13) ) => {
68
- vectors_equal ( p00, p10, point_epsilon) && vectors_equal ( p01, p11, point_epsilon) && vectors_equal ( p02, p12, point_epsilon) && vectors_equal ( p03, p13, point_epsilon)
68
+ let start_and_end_equal = vectors_equal ( p00, p10, point_epsilon) && vectors_equal ( p03, p13, point_epsilon) ;
69
+
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 ) ;
73
+ let angles_equal = ( direction1 - p00) . angle_to ( direction2 - p00) . abs ( ) < point_epsilon * 4. ;
74
+ if angles_equal {
75
+ eprintln ! ( "deduplicating {:?} {:?} because the angles are equal" , seg0, seg1) ;
76
+ }
77
+
78
+ start_and_end_equal && ( parameter_equal || angles_equal)
69
79
}
70
80
( PathSegment :: Quadratic ( p00, p01, p02) , PathSegment :: Quadratic ( p10, p11, p12) ) => {
71
81
vectors_equal ( p00, p10, point_epsilon) && vectors_equal ( p01, p11, point_epsilon) && vectors_equal ( p02, p12, point_epsilon)
@@ -123,6 +133,8 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
123
133
// dbg!("checking pairs");
124
134
125
135
if pairs. len ( ) > 1000 {
136
+ // TODO: check for intersections of the start/end points. If the two lines overlap, return split points for the start/end points. Use a binary search to check where the points are on the line.
137
+ return dbg ! ( calculate_overlap_intersections( seg0, seg1, eps) ) ;
126
138
return vec ! [ ] ;
127
139
}
128
140
@@ -179,6 +191,90 @@ pub fn path_segment_intersection(seg0: &PathSegment, seg1: &PathSegment, endpoin
179
191
params
180
192
}
181
193
194
+ fn calculate_overlap_intersections ( seg0 : & PathSegment , seg1 : & PathSegment , eps : & Epsilons ) -> Vec < [ f64 ; 2 ] > {
195
+ let start0 = get_start_point ( seg0) ;
196
+ let end0 = get_end_point ( seg0) ;
197
+ let start1 = get_start_point ( seg1) ;
198
+ let end1 = get_end_point ( seg1) ;
199
+
200
+ let mut intersections = Vec :: new ( ) ;
201
+
202
+ // Check start0 against seg1
203
+ if let Some ( t1) = find_point_on_segment ( seg1, start0, eps) {
204
+ intersections. push ( [ 0.0 , t1] ) ;
205
+ }
206
+
207
+ // Check end0 against seg1
208
+ if let Some ( t1) = find_point_on_segment ( seg1, end0, eps) {
209
+ intersections. push ( [ 1.0 , t1] ) ;
210
+ }
211
+
212
+ // Check start1 against seg0
213
+ if let Some ( t0) = find_point_on_segment ( seg0, start1, eps) {
214
+ intersections. push ( [ t0, 0.0 ] ) ;
215
+ }
216
+
217
+ // Check end1 against seg0
218
+ if let Some ( t0) = find_point_on_segment ( seg0, end1, eps) {
219
+ intersections. push ( [ t0, 1.0 ] ) ;
220
+ }
221
+
222
+ // Remove duplicates and sort intersections
223
+ intersections. sort_unstable_by ( |a, b| a[ 0 ] . partial_cmp ( & b[ 0 ] ) . unwrap ( ) ) ;
224
+ intersections. dedup_by ( |a, b| vectors_equal ( Vector :: new ( a[ 0 ] , a[ 1 ] ) , Vector :: new ( b[ 0 ] , b[ 1 ] ) , eps. param ) ) ;
225
+
226
+ // Handle special cases
227
+ if intersections. is_empty ( ) {
228
+ // Check if segments are identical
229
+ if vectors_equal ( start0, start1, eps. point ) && vectors_equal ( end0, end1, eps. point ) {
230
+ return vec ! [ [ 0.0 , 0.0 ] , [ 1.0 , 1.0 ] ] ;
231
+ }
232
+ } else if intersections. len ( ) > 2 {
233
+ // Keep only the first and last intersection points
234
+ intersections = vec ! [ intersections[ 0 ] , intersections[ intersections. len( ) - 1 ] ] ;
235
+ }
236
+
237
+ intersections
238
+ }
239
+
240
+ fn find_point_on_segment ( seg : & PathSegment , point : Vector , eps : & Epsilons ) -> Option < f64 > {
241
+ let start = 0.0 ;
242
+ let end = 1.0 ;
243
+ let mut t = 0.5 ;
244
+
245
+ for _ in 0 ..32 {
246
+ // Limit iterations to prevent infinite loops
247
+ let current_point = sample_path_segment_at ( seg, t) ;
248
+
249
+ if vectors_equal ( current_point, point, eps. point ) {
250
+ return Some ( t) ;
251
+ }
252
+
253
+ let start_point = sample_path_segment_at ( seg, start) ;
254
+ let end_point = sample_path_segment_at ( seg, end) ;
255
+
256
+ let dist_start = ( point - start_point) . length_squared ( ) ;
257
+ let dist_end = ( point - end_point) . length_squared ( ) ;
258
+ let dist_current = ( point - current_point) . length_squared ( ) ;
259
+
260
+ if dist_current < dist_start && dist_current < dist_end {
261
+ return Some ( t) ;
262
+ }
263
+
264
+ if dist_start < dist_end {
265
+ t = ( start + t) / 2.0 ;
266
+ } else {
267
+ t = ( t + end) / 2.0 ;
268
+ }
269
+
270
+ if ( end - start) < eps. param {
271
+ break ;
272
+ }
273
+ }
274
+
275
+ None
276
+ }
277
+
182
278
#[ cfg( test) ]
183
279
mod test {
184
280
use super :: * ;
0 commit comments