flo_curves/bezier/path/graph_path/
path_collision.rs

1#![allow(clippy::nonminimal_bool)]              // Don't think clippy's suggestion is more readable as it's kind of a double-negative: purpose of if statement is a bit unclear anyway here...
2
3use super::{GraphPath, GraphEdge, GraphEdgeRef, GraphPathPoint, GraphPathEdge};
4use crate::bezier::curve::*;
5use crate::bezier::intersection::*;
6use crate::geo::*;
7use crate::consts::*;
8
9use smallvec::*;
10
11use std::mem;
12use std::ops::Range;
13use std::cmp::Ordering;
14
15///
16/// Struct describing a collision between two edges
17///
18#[derive(Clone, Copy, Debug)]
19struct Collision {
20    /// The first edge in the collision
21    edge_1: GraphEdgeRef,
22
23    /// The second edge in the collision
24    edge_2: GraphEdgeRef,
25
26    /// The location on edge1 of the collision
27    edge_1_t: f64,
28
29    /// The location on edge2 of the collision
30    edge_2_t: f64
31}
32
33impl<Point: Coordinate+Coordinate2D, Label: Copy> GraphPath<Point, Label> {
34    /// 
35    /// True if the t value is effectively at the start of the curve
36    /// 
37    #[inline]
38    fn t_is_zero(t: f64) -> bool { t <= 0.0 }
39
40    ///
41    /// True if the t value is effective at the end of the curve
42    /// 
43    #[inline]
44    fn t_is_one(t: f64) -> bool { t >= 1.0 }
45
46    ///
47    /// Retrieves the ordered graph edges for a range of points
48    ///
49    fn get_ordered_edges(&self, points: Range<usize>) -> Vec<GraphEdge<'_, Point, Label>> {
50        let mut ordered_edges = points.into_iter()
51            .flat_map(|point_idx| (0..self.points[point_idx].forward_edges.len()).into_iter().map(move |edge_idx| (point_idx, edge_idx)))
52            .map(|(point_idx, edge_idx)| GraphEdgeRef { start_idx: point_idx, edge_idx: edge_idx, reverse: false })
53            .map(|edge_ref| GraphEdge::new(self, edge_ref))
54            .collect::<Vec<_>>();
55
56        ordered_edges.sort_by(|edge1, edge2| {
57            let bb1 = edge1.get_bounding_box::<Bounds<_>>();
58            let bb2 = edge2.get_bounding_box::<Bounds<_>>();
59
60            bb1.min().x().partial_cmp(&bb2.min().x()).unwrap_or(Ordering::Equal)
61        });
62
63        ordered_edges
64    }
65
66    ///
67    /// Returns the 'snapped' version of two points when they're close enough
68    ///
69    #[inline]
70    fn snap_points(p1: &Point, p2: &Point) -> Point {
71        Point::from_components(&[(p1.x() + p2.x())/2.0, (p1.y() + p2.y())/2.0])
72    }
73
74    ///
75    /// True if points p1 and p2 are near to each other
76    ///
77    #[inline]
78    fn point_is_near(p1: &Point, p2: &Point, max_distance_squared: f64) -> bool {
79        let offset              = *p1 - *p2;
80        let squared_distance    = offset.dot(&offset);
81
82        squared_distance <= max_distance_squared
83    }
84
85    ///
86    /// Finds the self collisions in a range
87    ///
88    fn find_self_collisions(&self, points: Range<usize>, accuracy: f64) -> Vec<Collision> {
89        // Sort the edges into min_x order
90        let ordered_edges = self.get_ordered_edges(points);
91
92        // Find the collisions
93        let mut collisions = vec![];
94
95        for (src_curve, tgt_curve) in sweep_self(ordered_edges.iter()) {
96            // Find any collisions between the two edges (to the required accuracy)
97            let mut edge_collisions = curve_intersects_curve_clip(src_curve, tgt_curve, accuracy);
98            if edge_collisions.is_empty() { continue; }
99
100            // Remove any pairs of collisions that are too close together
101            remove_and_round_close_collisions(&mut edge_collisions, src_curve, tgt_curve);
102
103            // Turn into collisions, filtering out the collisions that occur at the ends (where one edge joins another).
104            // For cases where we get a collision at the end of an edge, wait for the one at the beginning of the next one
105            let edge_collisions = edge_collisions.into_iter()
106                .filter(|(src_t, tgt_t)| !(Self::t_is_one(*src_t) || Self::t_is_one(*tgt_t) || (Self::t_is_zero(*src_t) && Self::t_is_zero(*tgt_t))))
107                .map(|(src_t, tgt_t)| {
108                    Collision {
109                        edge_1:     src_curve.edge,
110                        edge_2:     tgt_curve.edge,
111                        edge_1_t:   src_t,
112                        edge_2_t:   tgt_t
113                    }
114                })
115                .map(|mut collision| {
116                    // If the collision is at the end of the edge, move it to the start of the following edge
117                    if Self::t_is_one(collision.edge_1_t) {
118                        collision.edge_1    = self.following_edge_ref(collision.edge_1);
119                        collision.edge_1_t  = 0.0;
120                    }
121
122                    if Self::t_is_one(collision.edge_2_t) {
123                        collision.edge_2    = self.following_edge_ref(collision.edge_2);
124                        collision.edge_2_t  = 0.0;
125                    }
126
127                    collision
128                });
129
130            // Add to the results
131            collisions.extend(edge_collisions);
132        }
133
134        // Check all edges for self-collisions
135        for edge in ordered_edges {
136            // Colliding edge against itself
137            if let Some((t1, t2)) = find_self_intersection_point(&edge, accuracy) {
138                if !(t1 <= 0.0 && t2 >= 1.0) && !(t1 >= 1.0 && t2 <= 0.0) {
139                    collisions.push(Collision {
140                        edge_1:     edge.edge,
141                        edge_2:     edge.edge,
142                        edge_1_t:   t1,
143                        edge_2_t:   t2
144                    });
145                }
146            }
147        }
148
149        collisions
150    }
151
152    ///
153    /// Finds any collisions that might exist between two ranges of points
154    ///
155    fn find_collisions(&self, collide_from: Range<usize>, collide_to: Range<usize>, accuracy: f64) -> Vec<Collision> {
156        if collide_from == collide_to {
157            return self.find_self_collisions(collide_from, accuracy);
158        }
159
160        // Order the edges for the two sides that are going to be collided
161        let collide_src = self.get_ordered_edges(collide_from);
162        let collide_tgt = self.get_ordered_edges(collide_to);
163
164        // Perform a sweep to find any collisions
165        let mut collisions = vec![];
166
167        for (src_curve, tgt_curve) in sweep_against(collide_src.iter(), collide_tgt.iter()) {
168            // Find any collisions between the two edges (to the required accuracy)
169            let mut edge_collisions = curve_intersects_curve_clip(src_curve, tgt_curve, accuracy);
170            if edge_collisions.is_empty() { continue; }
171
172            // Remove any pairs of collisions that are too close together
173            remove_and_round_close_collisions(&mut edge_collisions, src_curve, tgt_curve);
174
175            // Turn into collisions, filtering out the collisions that occur at the ends (where one edge joins another).
176            // For cases where we get a collision at the end of an edge, wait for the one at the beginning of the next one
177            let edge_collisions = edge_collisions.into_iter()
178                .filter(|(src_t, tgt_t)| !(Self::t_is_zero(*src_t) && Self::t_is_zero(*tgt_t)))
179                .map(|(src_t, tgt_t)| {
180                    Collision {
181                        edge_1:     src_curve.edge,
182                        edge_2:     tgt_curve.edge,
183                        edge_1_t:   src_t,
184                        edge_2_t:   tgt_t
185                    }
186                })
187                .map(|mut collision| {
188                    // If the collision is at the end of the edge, move it to the start of the following edge
189                    if Self::t_is_one(collision.edge_1_t) {
190                        collision.edge_1    = self.following_edge_ref(collision.edge_1);
191                        collision.edge_1_t  = 0.0;
192                    }
193
194                    if Self::t_is_one(collision.edge_2_t) {
195                        collision.edge_2    = self.following_edge_ref(collision.edge_2);
196                        collision.edge_2_t  = 0.0;
197                    }
198
199                    collision
200                });
201
202            // Add to the results
203            collisions.extend(edge_collisions);
204        }
205
206        collisions
207    }
208
209    ///
210    /// Adds any new points that will be required to divide the edges with the specified set of collisions
211    ///
212    fn create_collision_points(&mut self, collisions: Vec<Collision>) -> Vec<(Collision, usize)> {
213        // Create new points for each collision
214        let mut collision_points = vec![];
215        collision_points.reserve(collisions.len());
216
217        for collision in collisions.into_iter() {
218            // Determine the index of the point where this collision occurs is
219            let point_idx = if Self::t_is_zero(collision.edge_1_t) {
220                // Re-use the existing start point for edge1
221                collision.edge_1.start_idx
222            } else if Self::t_is_zero(collision.edge_2_t) {
223                // Re-use the existing start point for edge2
224                collision.edge_2.start_idx
225            } else {
226                // Create a new point
227                let edge            = self.get_edge(collision.edge_1);
228                let new_point_pos   = edge.point_at_pos(collision.edge_1_t);
229                let new_point_idx   = self.points.len();
230
231                self.points.push(GraphPathPoint {
232                    position:       new_point_pos,
233                    forward_edges:  smallvec![],
234                    connected_from: smallvec![]
235                });
236
237                new_point_idx
238            };
239
240            // Store in the list of collision points
241            collision_points.push((collision, point_idx));
242        }
243
244        collision_points
245    }
246
247    ///
248    /// Given a list of collisions and the point where they end, organizes them by edge
249    /// 
250    /// Return type is a vector of edges for each point, where each edge is a list of collisions, as 't' value on the edge and the
251    /// index of the end point
252    ///
253    fn organize_collisions_by_edge(&self, collisions: Vec<(Collision, usize)>) -> Vec<Option<SmallVec<[SmallVec<[(f64, usize); 2]>; 2]>>> {
254        // Initially there are no collisions for any point
255        let mut points: Vec<Option<SmallVec<[SmallVec<[(f64, usize); 2]>; 2]>>> = vec![None; self.num_points()];
256
257        // Iterate through the collisions and store them per edge. Every collision affects two edges
258        for (collision, end_point_idx) in collisions.iter() {
259            // First edge
260            let point   = points[collision.edge_1.start_idx].get_or_insert_with(|| smallvec![smallvec![]; self.points[collision.edge_1.start_idx].forward_edges.len()]);
261            let edge    = &mut point[collision.edge_1.edge_idx];
262
263            edge.push((collision.edge_1_t, *end_point_idx));
264
265            // Second edge
266            let point   = points[collision.edge_2.start_idx].get_or_insert_with(|| smallvec![smallvec![]; self.points[collision.edge_2.start_idx].forward_edges.len()]);
267            let edge    = &mut point[collision.edge_2.edge_idx];
268
269            edge.push((collision.edge_2_t, *end_point_idx));
270        }
271
272        points
273    }
274
275    ///
276    /// Searches two ranges of points in this object and detects collisions between them, subdividing the edges
277    /// and creating branch points at the appropriate places.
278    /// 
279    /// collide_from must indicate indices lower than collide_to
280    /// 
281    /// Returns true if any collisions were found
282    /// 
283    pub (crate) fn detect_collisions(&mut self, collide_from: Range<usize>, collide_to: Range<usize>, accuracy: f64) -> bool {
284        // Find all of the collision points
285        let all_collisions      = self.find_collisions(collide_from, collide_to, accuracy);
286        if all_collisions.is_empty() {
287            let collided_at_point = self.combine_overlapping_points(accuracy);
288            self.remove_all_very_short_edges();
289            return collided_at_point;
290        }
291
292        // Add in any extra points that are required by the collisions we found
293        let all_collisions      = self.create_collision_points(all_collisions);
294
295        // Organize the collisions by edge
296        let collisions_by_edge  = self.organize_collisions_by_edge(all_collisions);
297
298        // Limit to just points with collisions
299        let collisions_by_point = collisions_by_edge.into_iter()
300            .enumerate()
301            .filter_map(|(point_idx, collisions)| collisions.map(|collisions| (point_idx, collisions)));
302
303        // Actually divide the edges by collision
304        for (point_idx, edge_collisions) in collisions_by_point {
305            for (edge_idx, mut collisions) in edge_collisions.into_iter().enumerate() {
306                // Skip edges with no collisions
307                if collisions.is_empty() { continue; }
308
309                self.check_following_edge_consistency();
310
311                // Create a copy of the edge. Our future edges will all have the same kind and label as the edge that's being divided
312                let edge    = self.get_edge(GraphEdgeRef { start_idx: point_idx, edge_idx: edge_idx, reverse: false });
313                let kind    = edge.kind();
314                let label   = edge.label();
315                let edge    = Curve::from_curve(&edge);
316
317                // Sort collisions by t value
318                collisions.sort_by(|(t1, _end_point_idx1), (t2, _end_point_idx2)| {
319                    if t1 < t2 {
320                        Ordering::Less
321                    } else if t1 > t2 {
322                        Ordering::Greater
323                    } else {
324                        Ordering::Equal
325                    }
326                });
327
328                // We'll progressively split bits from the edge
329                let mut remaining_edge          = edge;
330                let mut remaining_t             = 1.0;
331                let final_point_idx             = self.points[point_idx].forward_edges[edge_idx].end_idx;
332                let final_following_edge_idx    = self.points[point_idx].forward_edges[edge_idx].following_edge_idx;
333                let mut last_point_idx          = point_idx;
334                let mut previous_edge           = None;
335                let mut found_collisions        = false;
336
337                // Iterate through the collisions (skipping any at t=0)
338                let mut collisions      = collisions.into_iter()
339                    .filter(|(t, _)| !Self::t_is_zero(*t));
340
341                // First collision is special as we need to edit the existing edge instead of adding a new one
342                if let Some((t, end_point_idx)) = collisions.next() {
343                    // Subdivide the edge
344                    let (next_edge, new_remaining_edge) = remaining_edge.subdivide::<Curve<_>>(t);
345                    let following_edge_idx      = self.points[end_point_idx].forward_edges.len();
346                    let (cp1, cp2)              = next_edge.control_points();
347
348                    test_assert!(next_edge.start_point().is_near_to(&self.points[point_idx].position, 0.1));
349                    test_assert!(next_edge.end_point().is_near_to(&self.points[end_point_idx].position, 0.1));
350
351                    // Update the control points and end point index
352                    let old_edge                = &mut self.points[point_idx].forward_edges[edge_idx];
353
354                    old_edge.cp1                = cp1;
355                    old_edge.cp2                = cp2;
356                    old_edge.end_idx            = end_point_idx;
357                    old_edge.following_edge_idx = following_edge_idx;
358                    old_edge.invalidate_cache();
359
360                    // Move on to the next edge
361                    previous_edge               = Some((point_idx, edge_idx));
362                    remaining_t                 = 1.0-t;
363                    remaining_edge              = new_remaining_edge;
364                    last_point_idx              = end_point_idx;
365                    found_collisions            = true;
366                }
367
368                // Deal with the rest of the collisions
369                for (t, end_point_idx) in collisions {
370                    // Point the previous edge at the new edge we're adding
371                    let new_edge_idx = self.points[last_point_idx].forward_edges.len();
372                    if let Some((point_idx, edge_idx)) = previous_edge {
373                        self.points[point_idx].forward_edges[edge_idx].following_edge_idx = new_edge_idx;
374                    }
375
376                    // Subdivide the remaining edge
377                    let t2                      = (t - (1.0-remaining_t))/remaining_t;
378                    let (next_edge, new_remaining_edge) = remaining_edge.subdivide::<Curve<_>>(t2);
379                    let (cp1, cp2)              = next_edge.control_points();
380
381                    test_assert!(next_edge.start_point().is_near_to(&self.points[last_point_idx].position, 0.1));
382                    test_assert!(next_edge.end_point().is_near_to(&self.points[end_point_idx].position, 0.1));
383
384                    // Add the new edge to the previous point
385                    let new_edge                = GraphPathEdge::new(kind, (cp1, cp2), end_point_idx, label, 0);
386                    self.points[last_point_idx].forward_edges.push(new_edge);
387
388                    // Move on to the next edge
389                    previous_edge               = Some((last_point_idx, new_edge_idx));
390                    remaining_t                 = 1.0-t;
391                    remaining_edge              = new_remaining_edge;
392                    last_point_idx              = end_point_idx;
393                    found_collisions            = true;
394                }
395
396                // Provided there was at least one collision (ie, not just one at t=0), add the final edge
397                if found_collisions {
398                    // Point the previous edge at the new edge we're adding
399                    let new_edge_idx = self.points[last_point_idx].forward_edges.len();
400                    if let Some((point_idx, edge_idx)) = previous_edge {
401                        self.points[point_idx].forward_edges[edge_idx].following_edge_idx = new_edge_idx;
402                    }
403
404                    // This edge ends where the original edge ended
405                    let end_point_idx       = final_point_idx;
406                    let following_edge_idx  = final_following_edge_idx;
407                    let (cp1, cp2)          = remaining_edge.control_points();
408
409                    test_assert!(remaining_edge.start_point().is_near_to(&self.points[last_point_idx].position, 0.1));
410                    test_assert!(remaining_edge.end_point().is_near_to(&self.points[end_point_idx].position, 0.1));
411
412                    // Add to the final point
413                    let final_edge          =  GraphPathEdge::new(kind, (cp1, cp2), end_point_idx, label, following_edge_idx);
414                    self.points[last_point_idx].forward_edges.push(final_edge);
415                }
416            }
417        }
418
419        // Finish up by checking that we haven't broken consistency
420        self.check_following_edge_consistency();
421
422        self.recalculate_reverse_connections();
423        self.combine_overlapping_points(accuracy);
424        self.remove_all_very_short_edges();
425
426        self.check_following_edge_consistency();
427
428        true
429    }
430
431    ///
432    /// Finds points that are within accuracy distance of each other (for accuracy < 1.0)
433    ///
434    /// Return value is a list of nearby points
435    ///
436    fn sweep_for_nearby_points(&mut self, accuracy: f64) -> impl Iterator<Item=(usize, usize)> {
437        // Structure to attach a bounding box to a point within this graph: this limits us as to the maximum distance we can use as it's used for sweeping
438        struct PointArea<'a, Point, Label>(&'a GraphPath<Point, Label>, usize);
439
440        impl<'a, Point: Coordinate+Coordinate2D, Label> PointArea<'a, Point, Label> {
441            #[inline]
442            fn pos(&self) -> &Point {
443                let PointArea(graph, point_idx) = self;
444
445                &graph.points[*point_idx].position
446            }
447
448            #[inline]
449            fn idx(&self) -> usize {
450                let PointArea(_graph, point_idx) = self;
451
452                *point_idx
453            }
454        }
455
456        impl<'a, Point: Coordinate+Coordinate2D, Label> Geo for PointArea<'a, Point, Label> {
457            type Point = Point;
458        }
459
460        impl<'a, Point: Coordinate+Coordinate2D, Label> HasBoundingBox for PointArea<'a, Point, Label> {
461            fn get_bounding_box<Bounds: BoundingBox<Point=Self::Point>>(&self) -> Bounds {
462                let PointArea(graph, point_idx) = self;
463
464                let point   = &graph.points[*point_idx];
465                let lower   = Point::from_components(&[point.position.x()-1.0, point.position.y()-1.0]);
466                let upper   = Point::from_components(&[point.position.x()+1.0, point.position.y()+1.0]);
467
468                Bounds::from_min_max(lower, upper)
469            }
470        }
471
472        // Collect all of the points in the graph, and order them by min_x
473        let mut all_points = (0..self.points.len()).into_iter()
474            .map(|idx| PointArea(self, idx))
475            .collect::<Vec<_>>();
476        all_points.sort_by(|point1, point2| {
477            let x1 = point1.pos().x();
478            let x2 = point2.pos().x();
479
480            x1.partial_cmp(&x2).unwrap_or(Ordering::Equal)
481        });
482
483        // Sweep to find the points that might be colliding
484        let min_distance_squared    = accuracy * accuracy;
485        let colliding_points        = sweep_self(all_points.iter())
486            .filter(|(point1, point2)| {
487                if point1.idx() == point2.idx() {
488                    // A point cannot overlap itself
489                    false
490                } else {
491                    // Work out the distances between the points and 
492                    let p1                  = point1.pos();
493                    let p2                  = point2.pos();
494
495                    let (x1, y1)            = (p1.x(), p1.y());
496                    let (x2, y2)            = (p2.x(), p2.y());
497                    let (dx, dy)            = (x2-x1, y2-y1);
498
499                    let distance_squared    = dx*dx + dy*dy;
500
501                    distance_squared < min_distance_squared
502                }
503            });
504
505        // Result is the indexes of the points that are 'close enough' to collide
506        colliding_points
507            .map(|(point1, point2)| {
508                (point1.idx(), point2.idx())
509            })
510            .collect::<Vec<_>>()
511            .into_iter()
512    }
513
514    ///
515    /// Finds any points that have approximately the same coordinates and combines them
516    /// 
517    /// Accuracy indicates the maximum difference in the x or y coordinate for two points to be considered the same.
518    ///
519    #[inline(never)]
520    pub fn combine_overlapping_points(&mut self, accuracy: f64) -> bool {
521        // Move any points that are connected by an edge and very close to each other on top of each other
522        for point_idx in 0..self.points.len() {
523            for edge_idx in 0..(self.points[point_idx].forward_edges.len()) {
524                let end_point_idx   = self.points[point_idx].forward_edges[edge_idx].end_idx;
525                if end_point_idx == point_idx {
526                    // A point is always close to itself, so we don't want to try to move it in this case
527                    continue;
528                }
529
530                let start_point     = &self.points[point_idx].position;
531                let end_point       = &self.points[end_point_idx].position;
532
533                if start_point.is_near_to(end_point, accuracy) {
534                    self.points[end_point_idx].position = self.points[point_idx].position;
535                }
536            }
537        }
538
539        // Find the points that are close enough to collide
540        let mut nearby_points = self.sweep_for_nearby_points(accuracy);
541
542        if let Some(nearby_point) = nearby_points.next() {
543            // Remap points according to whatever is nearest
544            let min_distance_squared    = accuracy * accuracy;
545            let mut remapped_points     = (0..self.points.len())
546                .into_iter()
547                .map(|idx| (idx, None))         // Target index (= point index if not remapped and new position, or None if unmoved)
548                .collect::<Vec<(_, Option<Point>)>>();
549
550            let mut nearby_point        = nearby_point;
551            loop {
552                // Index is of two points that are close enough to overlap
553                let (p1_orig_idx, p2_orig_idx) = nearby_point;
554                debug_assert!(p1_orig_idx != p2_orig_idx);                  // Guaranteed by the implementation of sweep_for_nearby_points()
555
556                // Point may be remapped
557                let (p1_idx, p1_pos)    = &remapped_points[p1_orig_idx];
558                let (p2_idx, p2_pos)    = &remapped_points[p2_orig_idx];
559
560                // To prevent averaging a whole bunch of points down to the same point because they're all close together, we re-check the distance if the one of the two close points has already been remapped
561                let moved               = p1_pos.is_some() || p2_pos.is_some();
562
563                let p1_pos              = if let Some(pos) = p1_pos { *pos } else { self.points[*p1_idx].position };
564                let p2_pos              = if let Some(pos) = p2_pos { *pos } else { self.points[*p2_idx].position };
565
566                if !moved || Self::point_is_near(&p1_pos, &p2_pos, min_distance_squared) {
567                    // Remap both points to a common target position
568                    let pos         = Self::snap_points(&p1_pos, &p2_pos);
569                    let remap_idx   = usize::min(*p1_idx, *p2_idx);
570
571                    remapped_points[p1_orig_idx] = (remap_idx, Some(pos));
572                    remapped_points[p2_orig_idx] = (remap_idx, Some(pos));
573                }
574
575                // Fetch the next point or stop
576                if let Some(next_point) = nearby_points.next() {
577                    nearby_point = next_point;
578                } else {
579                    break;
580                }
581            }
582
583            // Remap every point and the edges (we can tell remapped points by looking at the new position)
584            let mut following_edge_idx_offset = vec![0; self.points.len()];
585
586            for original_idx in 0..self.points.len() {
587                if let (new_idx, Some(new_pos)) = &remapped_points[original_idx] {
588                    // This point has been moved
589                    self.points[original_idx].position = *new_pos;
590
591                    // If this is the target point, then don't move any edges
592                    if *new_idx == original_idx { continue; }
593
594                    // Trace the new index to its final point (which is the point still mapped to itself: this should always exist because we always prefer the lowest point)
595                    let mut new_idx = *new_idx;
596                    loop {
597                        let (next_idx, _)   = &remapped_points[new_idx];
598                        let next_idx        = *next_idx;
599
600                        if next_idx == new_idx {
601                            break;
602                        } else {
603                            remapped_points[original_idx].0 = next_idx;
604                            new_idx = next_idx;
605                        }
606                    }
607
608                    // Move the edges into the new index
609                    let forward_edges   = mem::take(&mut self.points[original_idx].forward_edges);
610                    let connected_from  = mem::take(&mut self.points[original_idx].connected_from);
611
612                    following_edge_idx_offset[original_idx] = self.points[new_idx].forward_edges.len();
613
614                    self.points[new_idx].forward_edges.extend(forward_edges.into_iter());
615                    self.points[new_idx].connected_from.extend(connected_from.into_iter());
616                }
617            }
618
619            // Remap the target points (we should no longer need to follow points to the end as )
620            for point in self.points.iter_mut() {
621                // Remap the edges
622                for edge in point.forward_edges.iter_mut() {
623                    let new_end_idx = remapped_points[edge.end_idx].0;
624
625                    if new_end_idx != edge.end_idx {
626                        let following_edge_idx_offset   = following_edge_idx_offset[edge.end_idx];
627
628                        edge.end_idx                    = new_end_idx;
629                        edge.following_edge_idx         += following_edge_idx_offset;
630                    }
631                }
632
633                // Remap the 'connected from' points
634                let mut remapped = false;
635                for connected_from_idx in point.connected_from.iter_mut() {
636                    let new_connected_from_idx = remapped_points[*connected_from_idx].0;
637
638                    if new_connected_from_idx != *connected_from_idx {
639                        *connected_from_idx = new_connected_from_idx;
640                        remapped            = true;
641                    }
642                }
643
644                // If we introduced duplicates, remove them
645                if remapped {
646                    point.connected_from.sort_unstable();
647                    point.connected_from.dedup();
648                }
649            }
650
651            true
652        } else {
653            // No overlap
654            false
655        }
656    }
657
658    ///
659    /// Checks that the following edges are consistent
660    ///
661    #[cfg(any(test, feature="extra_checks"))]
662    pub (crate) fn check_following_edge_consistency(&self) {
663        let mut used_edges = vec![vec![]; self.points.len()];
664
665        for point_idx in 0..(self.points.len()) {
666            let point = &self.points[point_idx];
667
668            for edge_idx in 0..(point.forward_edges.len()) {
669                let edge = &point.forward_edges[edge_idx];
670
671                test_assert!(edge.end_idx < self.points.len());
672                test_assert!(edge.following_edge_idx < self.points[edge.end_idx].forward_edges.len());
673                test_assert!(!used_edges[edge.end_idx].contains(&edge.following_edge_idx));
674
675                used_edges[edge.end_idx].push(edge.following_edge_idx);
676            }
677        }
678    }
679
680    #[cfg(not(any(test, feature="extra_checks")))]
681    pub (crate) fn check_following_edge_consistency(&self) {
682
683    }
684}
685
686///
687/// Removes any pairs of collisions that are closer than `CLOSE_DISTANCE` apart, and also rounds the 
688/// first and last collisions to 0.0 and 1.0
689/// 
690/// When colliding two bezier curves we want to avoid subdividing excessively to produce very small 
691/// sections as they have a tendency to produce extra collisions due to floating point or root finding
692/// errors.
693///
694fn remove_and_round_close_collisions<C: BezierCurve>(collisions: &mut SmallVec<[(f64, f64); 8]>, src: &C, tgt: &C)
695where
696    C::Point: Coordinate+Coordinate2D 
697{
698    // Nothing to do if there are no collisions
699    if collisions.is_empty() {
700        return;
701    }
702
703    // Work out the positions of each point
704    let mut positions = collisions.iter().map(|(t1, _t2)| src.point_at_pos(*t1)).collect::<Vec<_>>();
705
706    // Find any pairs of points that are too close together
707    let mut collision_idx = 0;
708    while collision_idx+1 < collisions.len() {
709        // Just remove both of these if they are too close together (as each collision crosses the curve once, removing collisions in pairs means that there'll still be at least one collision left if the curves actually end up crossing over)
710        if positions[collision_idx].is_near_to(&positions[collision_idx+1], CLOSE_DISTANCE) {
711            if (collisions[collision_idx].0 - collisions[collision_idx+1].0).abs() < SMALL_T_DISTANCE
712                && (collisions[collision_idx].1 - collisions[collision_idx+1].1).abs() < SMALL_T_DISTANCE {
713                collisions.remove(collision_idx); positions.remove(collision_idx);
714                collisions.remove(collision_idx); positions.remove(collision_idx);
715            } else {
716                collision_idx += 1;
717            }
718        } else {
719            collision_idx += 1;
720        }
721    }
722    
723    // If the first point or the last point is close to the end of the source or target curve, clip to 0 or 1
724    if !collisions.is_empty() {
725        // Get the start/end points of the source and target
726        let src_start   = src.start_point();
727        let src_end     = src.end_point();
728        let tgt_start   = tgt.start_point();
729        let tgt_end     = tgt.end_point();
730
731        // Snap collisions to 0.0 or 1.0 if they're very close to the start or end of either curve
732        for collision_idx in 0..collisions.len() {
733            // Snap the source side
734            if collisions[collision_idx].0 > 0.0 && collisions[collision_idx].0 < 1.0 {
735                if src_start.is_near_to(&positions[collision_idx], CLOSE_DISTANCE) && collisions[collision_idx].0 < SMALL_T_DISTANCE {
736                    collisions[collision_idx].0 = 0.0;
737                }
738
739                if src_end.is_near_to(&positions[collision_idx], CLOSE_DISTANCE) && collisions[collision_idx].0 > 1.0-SMALL_T_DISTANCE {
740                    collisions[collision_idx].0 = 1.0;
741                }
742            }
743
744            // Snap the target side
745            if collisions[collision_idx].1 > 0.0 && collisions[collision_idx].1 < 1.0 && collisions[collision_idx].1 < SMALL_T_DISTANCE {
746                if tgt_start.is_near_to(&positions[collision_idx], CLOSE_DISTANCE) {
747                    collisions[collision_idx].1 = 0.0;
748                }
749
750                if tgt_end.is_near_to(&positions[collision_idx], CLOSE_DISTANCE) && collisions[collision_idx].1 > 1.0-SMALL_T_DISTANCE {
751                    collisions[collision_idx].1 = 1.0;
752                }
753            }
754        }
755    }
756}