cdt/
triangulate.rs

1use crate::{
2    contour::{Contour, ContourData},
3    Error, Point,
4    half::Half, hull::Hull,
5    indexes::{PointIndex, PointVec, EdgeIndex, HullIndex, EMPTY_EDGE},
6    predicates::{acute, orient2d, in_circle, centroid, distance2, pseudo_angle},
7};
8
9#[derive(Debug)]
10enum Walk {
11    Inside(EdgeIndex),
12    Done(EdgeIndex),
13}
14
15/// This `struct` contains all of the data needed to generate a (constrained)
16/// Delaunay triangulation of a set of input points and edges.  It is a
17/// **low-level** API; consider using the module-level functions if you don't
18/// need total control.
19pub struct Triangulation {
20    pub(crate) points: PointVec<Point>,    // Sorted in the constructor
21    angles: PointVec<f64>,          // pseudo-angles for each point
22    remap: PointVec<usize>,         // self.points[i] = input[self.remap[i]]
23    next: PointIndex,               // Progress of the triangulation
24    constrained: bool,
25
26    // If a point p terminates fixed edges, then endings[p] will be a tuple
27    // range into ending_data containing the starting points of those edges.
28    endings: PointVec<(usize, usize)>,
29    ending_data: Vec<PointIndex>,
30
31    // This stores the start of an edge (as a pseudoangle) as an index into
32    // the edges array
33    pub(crate) hull: Hull,
34    pub(crate) half: Half,
35}
36
37impl Triangulation {
38    /// Builds a complete triangulation from the given points
39    ///
40    /// # Errors
41    /// This may return [`Error::EmptyInput`], [`Error::InvalidInput`], or
42    /// [`Error::CannotInitialize`] if the input is invalid.
43    pub fn build(points: & [Point]) -> Result<Triangulation, Error> {
44        let mut t = Self::new(points)?;
45        t.run()?;
46        Ok(t)
47    }
48
49    /// Builds a complete triangulation from the given points and edges.
50    /// The points are a flat array of positions in 2D spaces; edges are
51    /// undirected and expressed as indexes into the points list.
52    ///
53    /// # Errors
54    /// This may return [`Error::EmptyInput`], [`Error::InvalidInput`],
55    /// [`Error::InvalidEdge`], or [`Error::CannotInitialize`] if the input is
56    /// invalid.
57    pub fn build_with_edges<'a, E>(points: &[Point], edges: E)
58        -> Result<Triangulation, Error>
59        where E: IntoIterator<Item=&'a (usize, usize)> + Copy
60    {
61        let mut t = Self::new_with_edges(points, edges)?;
62        t.run()?;
63        Ok(t)
64    }
65
66    /// Builds a complete triangulation from the given points and contours
67    /// (which are represented as indexes into the points array).
68    ///
69    /// # Errors
70    /// This may return [`Error::EmptyInput`], [`Error::InvalidInput`],
71    /// [`Error::InvalidEdge`], [`Error::OpenContour`] or
72    /// [`Error::CannotInitialize`] if the input is invalid.
73    pub fn build_from_contours<V>(points: &[Point], contours: &[V])
74        -> Result<Triangulation, Error>
75        where for<'b> &'b V: IntoIterator<Item=&'b usize>
76    {
77        let mut t = Self::new_from_contours(points, contours)?;
78        t.run()?;
79        Ok(t)
80    }
81
82    fn validate_input<'a, E>(points: &[Point], edges: E)
83        -> Result<(), Error>
84        where E: IntoIterator<Item=&'a (usize, usize)> + Copy
85    {
86        if points.is_empty() {
87            Err(Error::EmptyInput)
88        } else if points.iter().any(|p| p.0.is_nan() || p.0.is_infinite() ||
89                                        p.1.is_nan() || p.1.is_infinite()) {
90            Err(Error::InvalidInput)
91        } else if edges.into_iter().any(|e| e.0 >= points.len() ||
92                                            e.1 >= points.len() ||
93                                            e.0 == e.1) {
94            Err(Error::InvalidEdge)
95        } else if points.len() < 3 {
96            Err(Error::TooFewPoints)
97        } else {
98            Ok(())
99        }
100    }
101
102    /// Constructs a new triangulation of the given points.  The points are a
103    /// flat array of positions in 2D spaces; edges are undirected and expressed
104    /// as indexes into the `points` list.
105    ///
106    /// The triangulation is not actually run in this constructor; use
107    /// [`Triangulation::step`] or [`Triangulation::run`] to triangulate,
108    /// or [`Triangulation::build_with_edges`] to get a complete triangulation
109    /// right away.
110    ///
111    /// # Errors
112    /// This may return [`Error::EmptyInput`], [`Error::InvalidInput`],
113    /// [`Error::InvalidEdge`], or [`Error::CannotInitialize`] if the input is
114    /// invalid.
115    pub fn new_with_edges<'a, E>(points: &[Point], edges: E)
116        -> Result<Triangulation, Error>
117        where E: IntoIterator<Item=&'a (usize, usize)> + Copy
118    {
119        Self::validate_input(points, edges)?;
120
121        //  Picking the seed triangle and center point is tricky!
122        //
123        //  We want a center which is contained within the seed triangle,
124        //  and with the property that the seed triangle is the closest
125        //  three points when sorted by distance to the center.
126        //
127        //  The paper suggests using the center of the bounding box, but in
128        //  that case, you can end up with cases where the center is _outside_
129        //  of the initial seed triangle, which is awkward.
130        //
131        //  delaunator and its ports instead pick the circumcenter of a
132        //  triangle near the bbox center, which has the same issue.
133        //
134        //  Picking the centroid of the seed triangle instead of the
135        //  circumcenter can also lead to issues, as another point could be
136        //  closer, which will violate the condition that points are always
137        //  outside the hull when they are added to the triangulation.
138        //
139        //  We iterate, repeatedly picking a center and checking to see if the
140        //  conditions hold; otherwise, we pick a new center and try again.
141
142        // Start by picking a center which is at the center of the bbox
143        let (x_bounds, y_bounds) = Self::bbox(points);
144        let mut center = ((x_bounds.0 + x_bounds.1) / 2.0,
145                          (y_bounds.0 + y_bounds.1) / 2.0);
146
147        // The scratch buffer contains our points, their indexes, and a distance
148        // relative to the current center.  We leave distance unpopulated
149        // because it's calculated at the beginning of the loop below.
150        let mut scratch: Vec<(usize, f64)> = (0..points.len())
151            .map(|j| (j, distance2(center, points[j])))
152            .collect();
153
154        // Find the three closest points
155        let arr = min3(&scratch, &points);
156
157        // Pick out the triangle points, ensuring that they're clockwise
158        let pa = arr[0];
159        let mut pb = arr[1];
160        let mut pc = arr[2];
161        if orient2d(points[pa], points[pb], points[pc]) < 0.0 {
162            std::mem::swap(&mut pb, &mut pc);
163        }
164
165        // Pick this triangle's centroid as our starting point
166        center = centroid(points[pa], points[pb], points[pc]);
167
168        // Sort with a special comparison function that puts the first
169        // three keys at the start of the list, and uses partial_cmp
170        // otherwise.  The order of the first three keys is not
171        // guaranteed, which we fix up below.
172        scratch.sort_unstable_by(|k, r|
173            if k.0 == pa || k.0 == pb || k.0 == pc {
174                std::cmp::Ordering::Less
175            } else if r.0 == pa || r.0 == pb || r.0 == pc {
176                std::cmp::Ordering::Greater
177            } else {
178                // Compare by radius first, then break ties with pseudoangle
179                // This should be reproducible, i.e. two identical points should
180                // end up next to each other in the list, although with
181                // floating-point values, you _never know_.
182                match k.1.partial_cmp(&r.1).unwrap() {
183                    std::cmp::Ordering::Equal => {
184                        let pk = points[k.0];
185                        let pr = points[r.0];
186                        let ak = pseudo_angle((pk.0 - center.0, pk.1 - center.1));
187                        let ar = pseudo_angle((pr.0 - center.0, pr.1 - center.1));
188                        ak.partial_cmp(&ar).unwrap()
189                    },
190                    e => e,
191                }
192            });
193
194        // Sanity-check that our three target points are at the head of the
195        // list, as expected.
196        assert!((scratch[0].0 == pa) as u8 +
197                (scratch[1].0 == pa) as u8 +
198                (scratch[2].0 == pa) as u8 == 1);
199        assert!((scratch[0].0 == pb) as u8 +
200                (scratch[1].0 == pb) as u8 +
201                (scratch[2].0 == pb) as u8 == 1);
202        assert!((scratch[0].0 == pc) as u8 +
203                (scratch[1].0 == pc) as u8 +
204                (scratch[2].0 == pc) as u8 == 1);
205
206        // Apply sorting to initial three points, ignoring distance
207        // values at this point because they're unused.
208        scratch[0].0 = pa;
209        scratch[1].0 = pb;
210        scratch[2].0 = pc;
211
212        // These are the points used in the Triangulation struct
213        let mut sorted_points = PointVec::with_capacity(points.len());
214
215        // usize in original array -> PointIndex in sorted array
216        let mut map_forward = vec![PointIndex::empty(); points.len()];
217
218        // PointIndex in sorted array -> usize in original array
219        let mut map_reverse = PointVec::with_capacity(points.len());
220
221        for i in 0..scratch.len() {
222            // The first three points are guaranteed to be unique by the
223            // min3 selection function, so they have no dupe
224            let mut dupe = None;
225            let p = scratch[i];
226            if i >= 3 {
227                // Check each point against its nearest neighbor and the
228                // three original points, since they could be duplicates
229                // and may not be adjacent
230                for j in &[i - 1, 0, 1, 2] {
231                    let pa = points[scratch[*j].0];
232                    let pb = points[p.0];
233                    if (pa.0 - pb.0).abs() < f64::EPSILON &&
234                       (pa.1 - pb.1).abs() < f64::EPSILON
235                    {
236                        dupe = Some(scratch[*j].0);
237                        break;
238                    }
239                }
240            };
241            map_forward[p.0] = match dupe {
242                None => {
243                    sorted_points.push(points[p.0]);
244                    map_reverse.push(p.0)
245                },
246                Some(d) => {
247                    assert!(map_forward[d] != PointIndex::empty());
248                    map_forward[d]
249                },
250            };
251        }
252
253        ////////////////////////////////////////////////////////////////////////
254        let has_edges = edges.into_iter().count() > 0;
255        let mut out = Triangulation {
256            hull: Hull::new(sorted_points.len(), has_edges),
257            half: Half::new(sorted_points.len()),
258            constrained: has_edges,
259
260            remap: map_reverse,
261            next: PointIndex::new(0),
262            angles: PointVec::of(sorted_points.iter()
263                .map(|p| pseudo_angle((p.0 - center.0, p.1 - center.1)))
264                .collect()),
265
266            // Endings are assigned later
267            endings: PointVec::of(vec![(0,0); sorted_points.len()]),
268            ending_data: vec![],
269
270            points: sorted_points, // moved out here
271        };
272
273        let pa = out.next;
274        let pb = out.next + 1;
275        let pc = out.next + 2;
276        out.next += 3;
277        let e_ab = out.half.insert(pa, pb, pc,
278                                   EMPTY_EDGE, EMPTY_EDGE, EMPTY_EDGE);
279        assert!(e_ab == EdgeIndex::new(0));
280        let e_bc = out.half.next(e_ab);
281        let e_ca = out.half.prev(e_ab);
282
283        /*
284         *              a
285         *             / ^
286         *            /   \
287         *           V  f  \
288         *          b-------> c
289         */
290        out.hull.initialize(pa, out.angles[pa], e_ca);
291        out.hull.insert_bare(out.angles[pb], pb, e_ab);
292        out.hull.insert_bare(out.angles[pc], pc, e_bc);
293
294        ////////////////////////////////////////////////////////////////////////
295        // Iterate over edges, counting which points have a termination
296        let mut termination_count = PointVec::of(vec![0; out.points.len()]);
297        let edge_iter = || edges
298            .into_iter()
299            .map(|&(src, dst)| {
300                let src = map_forward[src];
301                let dst = map_forward[dst];
302                assert!(src != PointIndex::empty());
303                assert!(dst != PointIndex::empty());
304
305                if src > dst { (dst, src) } else { (src, dst) }
306            });
307        for (src, dst) in edge_iter() {
308            // Lock any edges that appear in the seed triangle.  Because the
309            // (src, dst) tuple is sorted, there are only three possible
310            // matches here.
311            if (src, dst) == (pa, pb) {
312                out.half.toggle_lock_sign(e_ab);
313            } else if (src, dst) == (pa, pc) {
314                out.half.toggle_lock_sign(e_ca);
315            } else if (src, dst) == (pb, pc) {
316                out.half.toggle_lock_sign(e_bc);
317            }
318            termination_count[dst] += 1;
319        }
320        // Ending data will be tightly packed into the ending_data array; each
321        // point stores its range into that array in self.endings[pt].  If the
322        // point has no endings, then the range is (n,n) for some value n.
323        let mut cumsum = 0;
324        for (dst, t) in termination_count.iter().enumerate() {
325            out.endings[PointIndex::new(dst)] = (cumsum, cumsum);
326            cumsum += t;
327        }
328        out.ending_data.resize(cumsum, PointIndex::new(0));
329        for (src, dst) in edge_iter() {
330            let t = &mut out.endings[dst].1;
331            out.ending_data[*t] = src;
332            *t += 1;
333        }
334
335        // ...and we're done!
336        Ok(out)
337    }
338
339    /// Constructs a new unconstrained triangulation
340    ///
341    /// The triangulation is not actually run in this constructor; use
342    /// [`Triangulation::step`] or [`Triangulation::run`] to triangulate,
343    /// or [`Triangulation::build`] to get a complete triangulation right away.
344    ///
345    /// # Errors
346    /// This may return [`Error::EmptyInput`], [`Error::InvalidInput`], or
347    /// [`Error::CannotInitialize`] if the input is invalid.
348    pub fn new(points: &[Point]) -> Result<Triangulation, Error> {
349        let edges: [(usize, usize); 0] = [];
350        Self::new_with_edges(points, &edges)
351    }
352
353    /// Triangulates a set of contours, given as indexed paths into the point
354    /// list.  Each contour must be closed (i.e. the last point in the contour
355    /// must equal the first point), otherwise [`Error::OpenContour`] will be
356    /// returned.
357    ///
358    /// The triangulation is not actually run in this constructor; use
359    /// [`Triangulation::step`] or [`Triangulation::run`] to triangulate,
360    /// or [`Triangulation::build_from_contours`] to get a complete
361    /// triangulation right away.
362    ///
363    /// # Errors
364    /// This may return [`Error::EmptyInput`], [`Error::InvalidInput`],
365    /// [`Error::InvalidEdge`], [`Error::OpenContour`] or
366    /// [`Error::CannotInitialize`] if the input is invalid.
367    pub fn new_from_contours<'a, V>(pts: &[Point], contours: &[V])
368        -> Result<Triangulation, Error>
369        where for<'b> &'b V: IntoIterator<Item=&'b usize>
370    {
371        let mut edges = Vec::new();
372        for c in contours {
373            let next = edges.len();
374            for (a, b) in c.into_iter().zip(c.into_iter().skip(1)) {
375                edges.push((*a, *b));
376            }
377            if let Some(start) = edges.get(next) {
378                if start.0 != edges.last().unwrap().1 {
379                    return Err(Error::OpenContour);
380                }
381            }
382        }
383        Self::new_with_edges(&pts, &edges)
384    }
385
386    /// Runs the triangulation algorithm until completion
387    ///
388    /// # Errors
389    /// This may return [`Error::PointOnFixedEdge`], [`Error::NoMorePoints`],
390    /// or [`Error::CrossingFixedEdge`] if those error conditions are met.
391    pub fn run(&mut self) -> Result<(), Error> {
392        while !self.done() {
393            self.step()?;
394        }
395        Ok(())
396    }
397
398    pub(crate) fn orient2d(&self, pa: PointIndex, pb: PointIndex, pc: PointIndex) -> f64 {
399        orient2d(self.points[pa], self.points[pb], self.points[pc])
400    }
401
402    fn acute(&self, pa: PointIndex, pb: PointIndex, pc: PointIndex) -> f64 {
403        acute(self.points[pa], self.points[pb], self.points[pc])
404    }
405
406    /// Checks whether the triangulation is done
407    pub fn done(&self) -> bool {
408        self.next == self.points.len() + 1
409    }
410
411    /// Walks the upper hull, making it convex.
412    /// This should only be called once from `finalize()`.
413    fn make_outer_hull_convex(&mut self) {
414        // Walk the hull from left to right, flattening any convex regions
415        assert!(self.next == self.points.len());
416        let mut start = self.hull.start();
417        let mut hl = start;
418        let mut hr = self.hull.right_hull(hl);
419        loop {
420            /*
421                ^
422                 \
423                  \el/hl
424                   \
425                    <-------------
426                        er/hr
427            */
428            let el = self.hull.edge(hl);
429            let er = self.hull.edge(hr);
430
431            let edge_l = self.half.edge(el);
432            let edge_r = self.half.edge(er);
433            assert!(edge_r.dst == edge_l.src);
434
435            // If this triangle on the hull is strictly convex, fill it
436            if self.orient2d(edge_l.dst, edge_l.src, edge_r.src) > 0.0 {
437                self.hull.erase(hr);
438                let new_edge = self.half.insert(
439                    edge_r.src, edge_l.dst, edge_l.src,
440                    el, er, EMPTY_EDGE);
441                self.hull.update(hl, new_edge);
442                self.legalize(self.half.next(new_edge));
443                self.legalize(self.half.prev(new_edge));
444
445                // Try stepping back in case this reveals another convex tri
446                hr = hl;
447                hl = self.hull.left_hull(hl);
448
449                // Record this as the start of the convex region
450                start = hl;
451            } else {
452                // Continue walking along the hull
453                let next = self.hull.right_hull(hr);
454                hl = hr;
455                hr = next;
456                if hl == start {
457                    break;
458                }
459            }
460        }
461    }
462
463    /// Finalizes the triangulation by making the outer hull convex (in the case
464    /// of unconstrained triangulation), or removing unattached triangles (for
465    /// CDT).
466    fn finalize(&mut self) {
467        assert!(self.next == self.points.len());
468
469        if self.constrained {
470            // For a constrained triangulation, flood fill and erase triangles
471            // that are outside the shape boundaries.
472            let h = self.hull.start();
473            let e = self.hull.edge(h);
474            self.half.flood_erase_from(e);
475        } else {
476            // For an unconstrained triangulation, make the outer hull convex
477            self.make_outer_hull_convex();
478        }
479
480        self.next += 1usize;
481    }
482
483    /// Checks that invariants of the algorithm are maintained. This is a slow
484    /// operation and should only be used for debugging.
485    ///
486    /// # Panics
487    /// Panics if invariants are not correct
488    pub fn check(&self) {
489        self.hull.check();
490        self.half.check();
491    }
492
493    /// Advances the triangulation by one step.
494    ///
495    /// # Errors
496    /// This may return [`Error::PointOnFixedEdge`], [`Error::NoMorePoints`],
497    /// or [`Error::CrossingFixedEdge`] if those error conditions are met.
498    pub fn step(&mut self) -> Result<(), Error> {
499        if self.done() {
500            return Err(Error::NoMorePoints);
501        } else if self.next == self.points.len() {
502            self.finalize();
503            return Ok(());
504        }
505
506        // Pick the next point in our pre-sorted array
507        let p = self.next;
508        self.next += 1usize;
509
510        // Find the hull edge which will be split by this point
511        let h_ab = self.hull.get(self.angles[p]);
512        let e_ab = self.hull.edge(h_ab);
513
514        /*
515         *              p [new point]
516         *             / ^
517         *            /   \
518         *           V  f  \
519         *          --------> [new edge]
520         *          b<------a [previous hull edge]
521         *              e
522         */
523        let edge = self.half.edge(e_ab);
524        let a = edge.src;
525        let b = edge.dst;
526        assert!(edge.next != EMPTY_EDGE);
527        assert!(edge.prev != EMPTY_EDGE);
528        assert!(edge.buddy == EMPTY_EDGE);
529
530        assert!(a != b);
531        assert!(a != p);
532        assert!(b != p);
533
534        let o = self.orient2d(b, a, p);
535        let h_p = if o <= 0.0 {
536            /*
537                    b<-------p<------a
538                     \      ^|      ^
539                      \      |     /
540                  next \     |    / prev
541                        \    |   /
542                         \   |  /
543                          \  |v/
544                           V |/
545                            c
546
547                Special case: if p is exactly on the line (or inside), then we
548                split the line instead of inserting a new triangle.
549            */
550            if edge.fixed() {
551                // TODO: this should only be checked if o == 0.0; otherwise,
552                // we should re-insert a-b with a-b-p being a third triangle
553                return Err(Error::PointOnFixedEdge(self.remap[p]));
554            }
555            assert!(edge.buddy == EMPTY_EDGE);
556            let edge_bc = self.half.edge(edge.next);
557            let edge_ca = self.half.edge(edge.prev);
558            let c = edge_bc.dst;
559            assert!(c == edge_ca.src);
560
561            let hull_right = self.hull.right_hull(h_ab);
562            let hull_left = self.hull.left_hull(h_ab);
563
564            self.half.erase(e_ab);
565
566            let e_pc = self.half.insert(p, c, a, edge_ca.buddy, EMPTY_EDGE, EMPTY_EDGE);
567            let e_cp = self.half.insert(c, p, b, EMPTY_EDGE, edge_bc.buddy, e_pc);
568
569            // Update the hull point at b to point to the new split edge
570            self.hull.update(h_ab, self.half.next(e_cp));
571
572            // Split the edge in the hull
573            let h_ap = self.hull.insert(
574                h_ab, self.angles[p], p, self.half.prev(e_pc));
575
576            // If either of the other triangle edges (in the now-deleted
577            // triangle) were attached to the hull, then patch them up.
578            if self.hull.edge(hull_right) == edge.prev {
579                self.hull.update(hull_right, self.half.next(e_pc));
580            }
581            if self.hull.edge(hull_left) == edge.next {
582                self.hull.update(hull_left, self.half.prev(e_cp));
583            }
584
585            self.legalize(self.half.prev(e_cp));
586            self.legalize(self.half.next(e_pc));
587            h_ap
588        } else {
589            let f = self.half.insert(b, a, p, EMPTY_EDGE, EMPTY_EDGE, e_ab);
590            assert!(o != 0.0);
591            assert!(o > 0.0);
592
593            // Replaces the previous item in the hull
594            self.hull.update(h_ab, self.half.prev(f));
595
596            let h_p = if self.angles[a] != self.angles[p] {
597                // Insert the new edge into the hull, using the previous
598                // HullIndex as a hint to avoid searching for its position.
599                let h_ap = self.hull.insert(
600                    h_ab, self.angles[p], p, self.half.next(f));
601                self.legalize(f);
602                h_ap
603            } else {
604                /*  Rare case when p and a are in a perfect vertical line:
605                 *
606                 *  We already inserted the left triangle and attached p-b to
607                 *  the hull index.  We insert a bonus right triangle here and
608                 *  attach c-p to to p's hull index, rather than splitting a-b
609                 *  in the hull.
610                 *
611                 *                 /p [new point]
612                 *               /  | ^
613                 *             /    |   \
614                 *           V  f   |  g  \
615                 *          -------->------>\
616                 *          b<------a<------c [previous hull edge]
617                 *              e
618                 */
619                let h_ca = self.hull.right_hull(h_ab);
620                let e_ca = self.hull.edge(h_ca);
621                let edge_ca = self.half.edge(e_ca);
622                assert!(a == edge_ca.dst);
623                let c = edge_ca.src;
624                let g = self.half.insert(a, c, p,
625                    EMPTY_EDGE, self.half.next(f), e_ca);
626
627                // h_ca has the same X position as c-p, so we update the same
628                // slot in the hull, then move the point in the look-up table.
629                self.hull.update(h_ca, self.half.next(g));
630                self.hull.move_point(a, p);
631
632                // Legalize the two new triangle edges
633                self.legalize(f);
634                self.legalize(g);
635                h_ca
636            };
637
638            // Check and fill acute angles
639            self.check_acute_left(p, h_p);
640            self.check_acute_right(p, h_p);
641            h_p
642        };
643
644        // Finally, we check whether this point terminates any edges that are
645        // locked in the triangulation (the "constrainted" part of Constrained
646        // Delaunay Triangulation).
647        let (start, end) = self.endings[p];
648        for i in start..end {
649            self.handle_fixed_edge(h_p, p, self.ending_data[i])?;
650        }
651
652        Ok(())
653    }
654
655    fn check_acute_left(&mut self, p: PointIndex, h_p: HullIndex) {
656        /* Search for sharp angles on the left side.
657         *
658         *      q       p [new point]
659         *     / ^    e/ ^
660         *    /   \   /   \
661         *   /     \ V     \
662         *          b------->
663         */
664        let mut h_b = h_p;
665        loop {
666            // Move one edge to the left.  In the first iteration of the loop,
667            // h_b will be pointing at the b->p edge.
668            h_b = self.hull.left_hull(h_b);
669            let e_pb = self.hull.edge(h_b);
670            let edge_pb = self.half.edge(e_pb);
671            let b = edge_pb.dst;
672
673            // Pick out the next item in the list
674            let h_q = self.hull.left_hull(h_b);
675            let e_bq = self.hull.edge(h_q);
676            let edge_bq = self.half.edge(e_bq);
677            let q = edge_bq.dst;
678
679            // If we're building a constrained triangulation, then we force the
680            // outer hull to be convex, so each point-to-point connection
681            // is guaranteed to stay within the triangulation.  This is slightly
682            // less efficient than the acute check, but dramatically simplifies
683            // the code for fixing edges.
684            //
685            // For unconstrained triangulations, we check that the inner angle
686            // is less that pi/2, per Zalik '05.
687            if (!self.constrained && self.acute(p, b, q) <= 0.0) ||
688                self.orient2d(p, b, q) >= 0.0
689            {
690                break;
691            }
692
693            // Friendship ended with q-b-p
694            self.hull.erase(h_b);
695
696            // Now p-q is my new friend
697            let e_pq = self.half.insert(p, q, b, e_bq, e_pb, EMPTY_EDGE);
698            self.hull.update(h_q, e_pq);
699            h_b = h_p;
700
701            // Then legalize from the two new triangle edges (bp and qb)
702            self.legalize(self.half.next(e_pq));
703            self.legalize(self.half.prev(e_pq));
704        }
705    }
706
707    fn check_acute_right(&mut self, p: PointIndex, h_p: HullIndex) {
708        /*  Rightward equivalent of check_acute_left
709         *         p        q
710         *        / ^      / \
711         *       /   \e   /   \
712         *      V     \  v     \
713         *     -------->a       \
714         */
715        let mut h_a = h_p;
716        loop {
717            // Move one edge to the left.  In the first iteration of the loop,
718            // h_a will be pointing at the p->a edge.
719            let e_ap = self.hull.edge(h_a);
720            let edge_ap = self.half.edge(e_ap);
721            let a = edge_ap.src;
722            assert!(a != p);
723
724            // Scoot over by one to look at the a-q edge
725            h_a = self.hull.right_hull(h_a);
726            let e_qa = self.hull.edge(h_a);
727            let edge_qa = self.half.edge(e_qa);
728            let q = edge_qa.src;
729
730            // Same check as above
731            if (!self.constrained && self.acute(p, a, q) <= 0.0)  ||
732                self.orient2d(p, a, q) <= 0.0
733            {
734                break;
735            }
736
737            self.hull.erase(h_a);
738            let edge_qp = self.half.insert(q, p, a, e_ap, e_qa, EMPTY_EDGE);
739            self.hull.update(h_p, edge_qp);
740            h_a = h_p;
741
742            // Then legalize from the two new triangle edges (bp and qb)
743            self.legalize(self.half.next(edge_qp));
744            self.legalize(self.half.prev(edge_qp));
745        }
746    }
747
748    /// Finds which mode to begin walking through the triangulation when
749    /// inserting a fixed edge.  h is a [`HullIndex`] equivalent to the `src`
750    /// point, and `dst` is the destination of the new fixed edge.
751    fn find_hull_walk_mode(&self, h: HullIndex, src: PointIndex, dst: PointIndex)
752        -> Result<Walk, Error> {
753        /*  We've just built a triangle that contains a fixed edge, and need
754            to walk through the triangulation and implement that edge.
755
756            The only thing we know going in is that point src is on the hull of
757            the triangulation with HullIndex h.
758
759            We start by finding the triangle a->src->b which contains the edge
760            src->dst, e.g.
761
762                     src
763                     / :^
764                    / :  \
765                   /  :   \h
766                  /  :     \
767                 V   :      \
768                b---:------->a
769                    :
770                   dst
771
772            Because the triangulation is convex, we know that this triangle
773            exists; we can't escape the triangulation.
774        */
775        let e_right = self.hull.edge(h);
776        let h_left = self.hull.left_hull(h);
777        let e_left = self.hull.edge(h_left);
778
779        // Note that e_right-e_left may be a wedge that contains multiple
780        // triangles (for example, this would be the case if there was an edge
781        // flip of b->a)
782        let wedge_left = self.half.edge(e_left).dst;
783        let wedge_right = self.half.edge(e_right).src;
784
785        // If the fixed edge is directly attached to src, then we can declare
786        // that we're done right away (and the caller will lock the edge)
787        if dst == wedge_left {
788            return Ok(Walk::Done(e_left));
789        } else if dst == wedge_right {
790            return Ok(Walk::Done(e_right));
791        }
792
793        // Otherwise, check the winding to see which side we're on.
794        let o_left = self.orient2d(src, wedge_left, dst);
795        let o_right = self.orient2d(src, dst, wedge_right);
796
797        // For now, we don't handle cases where fixed edges have coincident
798        // points that are not the start/end of the fixed edge.
799        if o_left == 0.0 {
800            return Err(Error::PointOnFixedEdge(self.remap[wedge_left]));
801        } else if o_right == 0.0 {
802            return Err(Error::PointOnFixedEdge(self.remap[wedge_right]));
803        }
804
805        // Walk the inside of the wedge until we find the
806        // subtriangle which captures the p-src line.
807        let mut index_a_src = self.half.edge(e_left).prev;
808
809        loop {
810            let edge_a_src = self.half.edge(index_a_src);
811            let a = edge_a_src.src;
812            if a == dst {
813                /* Lucky break: the src point is one of the edges directly
814                   within the wedge, e.g.:
815                          src
816                         / ^\
817                        /  | \
818                       /   |  \
819                      /    |   \
820                     V     |    \
821                    ------>a------ (a == dst)
822                */
823                return Ok(Walk::Done(index_a_src));
824            }
825
826            // Keep walking through the fan
827            let intersected_index = edge_a_src.prev;
828
829            let o = self.orient2d(src, dst, a);
830            // If we've found the intersection point, then we return the new
831            // (inner) edge.  The walking loop will transition to Left or Right
832            // if this edge doesn't have a buddy.
833            if o > 0.0 {
834                /*
835                          src
836                         /:^\
837                        / :| \
838                       /  :|  \
839                      /  : |   \
840                     V   : |    \
841                    ----:->a------
842                        :
843                       dst
844                */
845                // We may exit either into another interior triangle or
846                // leave the triangulation and walk the hull, but we don't
847                // need to decide that right now.
848                return Ok(Walk::Inside(intersected_index));
849            } else if o < 0.0 {
850                /*  Sorry, Mario; your src-dst line is in another triangle
851
852                          src
853                         / ^:\
854                        /  |: \
855                       /   | : \
856                      /    | :  \
857                     V     |  :  \
858                    ------>a--:---
859                              :
860                              dst
861
862                    (so keep going through the triangle)
863                */
864                let buddy = edge_a_src.buddy;
865
866                // We can't have walked out of the wedge, because otherwise
867                // o_right would be < 0.0 and we wouldn't be in this branch
868                if buddy == EMPTY_EDGE {
869                    return Err(Error::WedgeEscape);
870                }
871                index_a_src = self.half.edge(buddy).prev;
872            } else {
873                // If we hit a vertex, exactly, then return an error
874                return Err(Error::PointOnFixedEdge(self.remap[a]));
875            }
876        }
877    }
878
879    fn walk_fill(&mut self, src: PointIndex, dst: PointIndex, mut e: EdgeIndex) -> Result<(), Error> {
880        let mut steps_left = Contour::new_pos(src, ContourData::None);
881        let mut steps_right = Contour::new_neg(src, ContourData::None);
882
883        /*
884         * We start inside a triangle, then escape it right away:
885                     src
886                     / :^
887                    / :  \
888                 hl/  :   \hr
889                  /  :     \
890                 V   :  e   \
891                b---:------->a
892                    :
893                   dst
894         */
895        let edge_ba = self.half.edge(e);
896        let e_ac = edge_ba.next;
897        let e_cb = edge_ba.prev;
898        let edge_ac = self.half.edge(e_ac);
899        let edge_cb = self.half.edge(e_cb);
900
901        // Delete this triangle from the triangulation; it will be
902        // reconstructed later in a more perfect form.
903        self.half.erase(e);
904
905        steps_left.push(self, edge_ba.src,
906            if edge_cb.buddy != EMPTY_EDGE {
907                ContourData::Buddy(edge_cb.buddy)
908            } else {
909                let hl = self.hull.index_of(edge_cb.dst);
910                assert!(self.hull.edge(hl) == e_cb);
911                ContourData::Hull(hl, edge_cb.sign)
912            });
913        steps_right.push(self, edge_ba.dst,
914            if edge_ac.buddy != EMPTY_EDGE {
915                ContourData::Buddy(edge_ac.buddy)
916            } else {
917                let hr = self.hull.index_of(edge_ac.dst);
918                assert!(self.hull.edge(hr) == e_ac);
919                ContourData::Hull(hr, edge_ac.sign)
920            });
921
922        // Exit this triangle, either onto the hull or continuing inside
923        // the triangulation.
924        if edge_ba.fixed() {
925            return Err(Error::CrossingFixedEdge);
926        }
927        assert!(edge_ba.buddy != EMPTY_EDGE);
928        e = edge_ba.buddy;
929
930        loop {
931            /*            src
932                         :
933                   b<--:-------a
934                    \ :  e     ^
935                     :\      /
936                    :   v  /
937                   :     c
938                  dst
939             */
940            let edge_ab = self.half.edge(e);
941            let e_bc = edge_ab.next;
942            let e_ca = edge_ab.prev;
943            let edge_bc = self.half.edge(e_bc);
944            let edge_ca = self.half.edge(e_ca);
945            let c = edge_bc.dst;
946
947            // Erase this triangle from the triangulation before
948            // pushing vertices to the contours, which could create
949            // new triangles.  At this point, you're not allowed to use
950            // self.half for any of the triangle edges, which is why
951            // we stored them all above.
952            self.half.erase(e);
953
954            // Handle the termination case, if c is the destination
955            if c == dst {
956                // The left (above) contour is either on the hull
957                // (if no buddy is present) or inside the triangulation
958                let e_dst_src = steps_left.push(self, c,
959                    if edge_bc.buddy == EMPTY_EDGE {
960                        let h = self.hull.index_of(edge_bc.dst);
961                        assert!(self.hull.edge(h) == e_bc);
962                        ContourData::Hull(h, edge_bc.sign)
963                    } else {
964                        ContourData::Buddy(edge_bc.buddy)
965                    }).expect("Failed to create fixed edge");
966
967                // This better have terminated the triangulation of
968                // the upper contour with a dst-src edge
969                assert!(self.half.edge(e_dst_src).dst == src);
970                assert!(self.half.edge(e_dst_src).src == dst);
971
972                // The other contour will finish up with the other
973                // half of the fixed edge as its buddy.  This edge
974                // could also be on the hull, so we do the same check
975                // as above.
976                let e_src_dst = steps_right.push(self, c,
977                    if edge_ca.buddy == EMPTY_EDGE {
978                        let h = self.hull.index_of(edge_ca.dst);
979                        assert!(self.hull.edge(h) == e_ca);
980                        ContourData::Hull(h, edge_ca.sign)
981                    } else {
982                        ContourData::Buddy(edge_ca.buddy)
983                    })
984                    .expect("Failed to create second fixed edge");
985
986                // Similarly, this better have terminated the
987                // triangulation of the lower contour.
988                assert!(self.half.edge(e_src_dst).src == src);
989                assert!(self.half.edge(e_src_dst).dst == dst);
990
991                self.half.link(e_src_dst, e_dst_src);
992                self.half.toggle_lock_sign(e_src_dst); // locks both sides
993
994                break;
995            }
996
997            let o_psc = self.orient2d(src, dst, c);
998            e = if o_psc > 0.0 {
999                // Store the c-a edge as our buddy, and exit via b-c
1000                // (unless c-a is the 0th edge, which has no buddy)
1001                steps_right.push(self, c,
1002                    if edge_ca.buddy == EMPTY_EDGE {
1003                        let h = self.hull.index_of(edge_ca.dst);
1004                        assert!(self.hull.edge(h) == e_ca);
1005                        ContourData::Hull(h, edge_ca.sign)
1006                    } else {
1007                        ContourData::Buddy(edge_ca.buddy)
1008                    });
1009
1010                // Exit the triangle, either onto the hull or staying
1011                // in the triangulation
1012                if edge_bc.fixed() {
1013                    return Err(Error::CrossingFixedEdge);
1014                }
1015                assert!(edge_bc.buddy != EMPTY_EDGE);
1016                edge_bc.buddy
1017            } else if o_psc < 0.0 {
1018                /*         src
1019                            :
1020                       b<-- :-a
1021                        |  : ^
1022                        |  :/
1023                        | :/
1024                        | :
1025                        V/:
1026                        c dst
1027                 */
1028                // Store the b-c edge as our buddy and exit via c-a,
1029                //
1030                // (c-b may be a hull edge, so we check for that)
1031                steps_left.push(self, c,
1032                    if edge_bc.buddy == EMPTY_EDGE {
1033                        let h = self.hull.index_of(edge_bc.dst);
1034                        assert!(self.hull.edge(h) == e_bc);
1035                        ContourData::Hull(h, edge_bc.sign)
1036                    } else {
1037                        ContourData::Buddy(edge_bc.buddy)
1038                    });
1039
1040                if edge_ca.fixed() {
1041                    return Err(Error::CrossingFixedEdge);
1042                }
1043                assert!(edge_ca.buddy != EMPTY_EDGE);
1044                edge_ca.buddy
1045            } else {
1046                return Err(Error::PointOnFixedEdge(self.remap[c]));
1047            }
1048        }
1049        Ok(())
1050    }
1051
1052    fn handle_fixed_edge(&mut self, h: HullIndex, src: PointIndex, dst: PointIndex) -> Result<(), Error> {
1053        match self.find_hull_walk_mode(h, src, dst)? {
1054            // Easy mode: the fixed edge is directly connected to the new
1055            // point, so we lock it and return immediately.
1056            Walk::Done(e) => { self.half.toggle_lock_sign(e); Ok(()) },
1057
1058            // Otherwise, we're guaranteed to be inside the triangulation,
1059            // because the hull is convex by construction.
1060            Walk::Inside(e) => self.walk_fill(src, dst, e),
1061        }
1062    }
1063
1064    pub(crate) fn legalize(&mut self, e_ab: EdgeIndex) {
1065        /* We're given this
1066         *            c
1067         *          /  ^
1068         *         /    \
1069         *        /      \
1070         *       /        \
1071         *      V     e    \
1072         *     a----------->\
1073         *     \<-----------b
1074         *      \    f     ^
1075         *       \        /
1076         *        \      /
1077         *         \    /
1078         *          V  /
1079         *           d
1080         *  We check whether d is within the circumcircle of abc.
1081         *  If so, then we flip the edge and recurse based on the triangles
1082         *  across from edges ad and db.
1083         *
1084         *  This function may be called with a half-empty edge, e.g. while
1085         *  recursing; in that case, then return immediately.
1086         */
1087        let edge = self.half.edge(e_ab);
1088        if edge.fixed() || edge.buddy == EMPTY_EDGE {
1089            return;
1090        }
1091        let a = edge.src;
1092        let b = edge.dst;
1093        let c = self.half.edge(self.half.next(e_ab)).dst;
1094
1095        let e_ba = edge.buddy;
1096        let e_ad = self.half.next(e_ba);
1097        let d = self.half.edge(e_ad).dst;
1098
1099        if in_circle(self.points[a], self.points[b], self.points[c],
1100                     self.points[d]) > 0.0
1101        {
1102            let e_db = self.half.prev(e_ba);
1103
1104            self.half.swap(e_ab);
1105            self.legalize(e_ad);
1106            self.legalize(e_db);
1107        }
1108    }
1109
1110    /// Calculates a bounding box, returning `((xmin, xmax), (ymin, ymax))`
1111    pub(crate) fn bbox(points: &[Point]) -> ((f64, f64), (f64, f64)) {
1112        let (mut xmin, mut xmax) = (std::f64::INFINITY, -std::f64::INFINITY);
1113        let (mut ymin, mut ymax) = (std::f64::INFINITY, -std::f64::INFINITY);
1114        for (px, py) in points.iter() {
1115            xmin = px.min(xmin);
1116            ymin = py.min(ymin);
1117            xmax = px.max(xmax);
1118            ymax = py.max(ymax);
1119        }
1120        ((xmin, xmax), (ymin, ymax))
1121    }
1122
1123    /// Returns all of the resulting triangles, as indexes into the original
1124    /// `points` array from the constructor.
1125    pub fn triangles(&self) -> impl Iterator<Item=(usize, usize, usize)> + '_ {
1126        self.half.iter_triangles()
1127            .map(move |(a, b, c)|
1128                (self.remap[a], self.remap[b], self.remap[c]))
1129    }
1130
1131    /// Checks whether the given point is inside or outside the triangulation.
1132    /// This is extremely inefficient, and should only be used for debugging
1133    /// or unit tests.
1134    pub fn inside(&self, p: Point) -> bool {
1135        self.half.iter_triangles()
1136            .any(|(a, b, c)| {
1137                orient2d(self.points[a], self.points[b], p) >= 0.0 &&
1138                orient2d(self.points[b], self.points[c], p) >= 0.0 &&
1139                orient2d(self.points[c], self.points[a], p) >= 0.0
1140            })
1141    }
1142
1143    /// Writes the current state of the triangulation to an SVG file,
1144    /// without debug visualizations.
1145    pub fn save_svg(&self, filename: &str) -> std::io::Result<()> {
1146        std::fs::write(filename, self.to_svg(false))
1147    }
1148
1149    /// Writes the current state of the triangulation to an SVG file,
1150    /// including the upper hull as a debugging visualization.
1151    pub fn save_debug_svg(&self, filename: &str) -> std::io::Result<()> {
1152        std::fs::write(filename, self.to_svg(true))
1153    }
1154
1155    /// Converts the current state of the triangulation to an SVG.  When `debug`
1156    /// is true, includes the upper hull and to-be-fixed edges; otherwise, just
1157    /// shows points, triangles, and fixed edges from the half-edge graph.
1158    pub fn to_svg(&self, debug: bool) -> String {
1159        let (x_bounds, y_bounds) = Self::bbox(&self.points);
1160        let scale = 800.0 /
1161            (x_bounds.1 - x_bounds.0).max(y_bounds.1 - y_bounds.0);
1162        let line_width = 2.0;
1163        let dx = |x| { scale * (x - x_bounds.0) + line_width};
1164        let dy = |y| { scale * (y_bounds.1 - y) + line_width};
1165
1166         let mut out = String::new();
1167         // Put a dummy rectangle in the SVG so that rsvg-convert doesn't clip
1168         out.push_str(&format!(
1169            r#"<svg viewbox="auto" xmlns="http://www.w3.org/2000/svg" width="{}" height="{}">
1170    <rect x="0" y="0" width="{}" height="{}"
1171     style="fill:rgb(0,0,0)" />"#,
1172            scale * (x_bounds.1 - x_bounds.0) + line_width*2.0,
1173            scale * (y_bounds.1 - y_bounds.0) + line_width*2.0,
1174            dx(x_bounds.1) + line_width,
1175            dy(y_bounds.0) + line_width));
1176
1177        // Draw endings in green (they will be overdrawn in white if they're
1178        // included in the triangulation).
1179        if debug {
1180            for (p, (start, end)) in self.endings.iter().enumerate() {
1181                for i in *start..*end {
1182                    let dst = PointIndex::new(p);
1183                    let src = self.ending_data[i];
1184                     out.push_str(&format!(
1185                        r#"
1186            <line x1="{}" y1="{}" x2="{}" y2="{}"
1187             style="stroke:rgb(0,255,0)"
1188             stroke-width="{}" stroke-linecap="round" />"#,
1189                        dx(self.points[src].0),
1190                        dy(self.points[src].1),
1191                        dx(self.points[dst].0),
1192                        dy(self.points[dst].1),
1193                        line_width));
1194                }
1195            }
1196        }
1197
1198         // Push every edge into the SVG
1199         for (pa, pb, fixed) in self.half.iter_edges() {
1200             out.push_str(&format!(
1201                r#"
1202    <line x1="{}" y1="{}" x2="{}" y2="{}"
1203     style="{}"
1204     stroke-width="{}"
1205     stroke-linecap="round" />"#,
1206                dx(self.points[pa].0),
1207                dy(self.points[pa].1),
1208                dx(self.points[pb].0),
1209                dy(self.points[pb].1),
1210                if fixed { "stroke:rgb(255,255,255)" }
1211                    else { "stroke:rgb(255,0,0)" },
1212                line_width))
1213         }
1214
1215         if debug {
1216             for e in self.hull.values() {
1217                 let edge = self.half.edge(e);
1218                 let (pa, pb) = (edge.src, edge.dst);
1219                 out.push_str(&format!(
1220                    r#"
1221        <line x1="{}" y1="{}" x2="{}" y2="{}"
1222         style="stroke:rgb(255,255,0)"
1223         stroke-width="{}" stroke-dasharray="{}"
1224         stroke-linecap="round" />"#,
1225                    dx(self.points[pa].0),
1226                    dy(self.points[pa].1),
1227                    dx(self.points[pb].0),
1228                    dy(self.points[pb].1),
1229                    line_width, line_width * 2.0))
1230             }
1231         }
1232
1233         for p in self.points.iter() {
1234             out.push_str(&format!(
1235                r#"
1236        <circle cx="{}" cy="{}" r="{}" style="fill:rgb(255,128,128)" />"#,
1237                dx(p.0), dy(p.1), line_width));
1238        }
1239
1240        out.push_str("\n</svg>");
1241        out
1242    }
1243}
1244
1245// Finds the three points in the given buffer with the lowest score, returning
1246// then in order (so that out[0] is closest)
1247//
1248// This is faster than sorting an entire array each time.
1249fn min3(buf: &[(usize, f64)], points: &[(f64, f64)]) -> [usize; 3] {
1250    let mut array = [(0, std::f64::INFINITY); 3];
1251    for &(p, score) in buf.iter() {
1252        if score < array[0].1 {
1253            array[0] = (p, score);
1254        }
1255    }
1256    for &(p, score) in buf.iter() {
1257        if score < array[1].1 {
1258            // If there is one point picked already, then don't
1259            // pick it again, since that will be doomed to be colinear.
1260            let p0 = points[array[0].0];
1261            if (p0.0 - points[p].0).abs() >= std::f64::EPSILON ||
1262               (p0.1 - points[p].1).abs() >= std::f64::EPSILON
1263            {
1264                array[1] = (p, score);
1265            }
1266        }
1267    }
1268    for &(p, score) in buf.iter() {
1269        if score < array[2].1 {
1270            let p0 = points[array[0].0];
1271            let p1 = points[array[1].0];
1272            if orient2d(p0, p1, points[p]).abs() > std::f64::EPSILON {
1273                array[2] = (p, score);
1274            }
1275        }
1276    }
1277
1278    let mut out = [0usize; 3];
1279    for (i, a) in array.iter().enumerate() {
1280        out[i] = a.0;
1281    }
1282    // TODO: return a reasonable error if all inputs are colinear or duplicates
1283    out
1284}
1285
1286#[cfg(test)]
1287mod tests {
1288    use super::*;
1289
1290    #[test]
1291    fn simple_triangle() {
1292        let pts = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)];
1293        let t = Triangulation::build(&pts[0..]).expect("Could not construct");
1294        assert!(t.inside((0.5, 0.5)));
1295    }
1296
1297    #[test]
1298    fn duplicate_point() {
1299        let points = vec![
1300            (0.0, 0.0),
1301            (1.0, 0.0),
1302            (1.1, 1.1),
1303            (1.1, 1.1),
1304            (0.0, 1.0),
1305        ];
1306        let edges = vec![
1307            (0, 1),
1308            (1, 2),
1309            (3, 4),
1310            (4, 0),
1311        ];
1312        let t = Triangulation::build_with_edges(&points, &edges);
1313        assert!(!t.is_err());
1314        assert!(t.unwrap().inside((0.5, 0.5)));
1315    }
1316
1317    #[test]
1318    fn simple_circle() {
1319        let mut edges = Vec::new();
1320        let mut points = Vec::new();
1321        const N: usize = 22;
1322        for i in 0..N {
1323            let a = (i as f64) / (N as f64) * core::f64::consts::PI * 2.0;
1324            let x = a.cos();
1325            let y = a.sin();
1326            points.push((x, y));
1327            edges.push((i, (i + 1) % N));
1328        }
1329        let t = Triangulation::build_with_edges(&points, &edges)
1330            .expect("Could not build triangulation");
1331        assert!(t.inside((0.0, 0.0)));
1332        assert!(!t.inside((1.01, 0.0)));
1333    }
1334
1335    #[test]
1336    fn dupe_start() {
1337        let points = vec![
1338            // Duplicate nearest points
1339            (0.5, 0.5),
1340            (0.5, 0.5),
1341            (0.5, 0.6),
1342            (0.6, 0.5),
1343            (0.5, 0.4),
1344
1345            // Force the center to be at 0.5, 0.5
1346            (0.0, 0.0),
1347            (1.0, 0.0),
1348            (1.0, 1.0),
1349            (0.0, 1.0),
1350        ];
1351        let edges = vec![
1352            (1, 2),
1353            (2, 3),
1354            (3, 4),
1355            (4, 0),
1356        ];
1357        let t = Triangulation::build_with_edges(&points, &edges)
1358            .expect("Could not build triangulation");
1359        assert!(t.inside((0.55, 0.5)));
1360        assert!(!t.inside((0.45, 0.5)));
1361    }
1362
1363    #[test]
1364    fn colinear_start() {
1365        let points = vec![
1366            // Force the center to be at 0.5, 0.5
1367            (0.0, 0.0),
1368            (1.0, 0.0),
1369            (1.0, 1.0),
1370            (0.0, 1.0),
1371
1372            // Threee colinear points
1373            (0.5, 0.4),
1374            (0.5, 0.5),
1375            (0.5, 0.6),
1376            (0.6, 0.5),
1377        ];
1378        let edges = vec![
1379            (4, 5),
1380            (5, 6),
1381            (6, 7),
1382            (7, 4),
1383        ];
1384        let t = Triangulation::build_with_edges(&points, &edges)
1385            .expect("Could not build triangulation");
1386        assert!(t.inside((0.55, 0.5)));
1387        assert!(!t.inside((0.45, 0.5)));
1388    }
1389
1390    #[test]
1391    fn fuzzy_circle() {
1392        let mut edges = Vec::new();
1393        let mut points = Vec::new();
1394        const N: usize = 32;
1395        for i in 0..N {
1396            let a = (i as f64) / (N as f64) * core::f64::consts::PI * 2.0;
1397            let x = a.cos();
1398            let y = a.sin();
1399            points.push((x, y));
1400            edges.push((i, (i + 1) % N));
1401        }
1402        const M: usize = 32;
1403
1404        use std::iter::repeat_with;
1405        use rand::{Rng, SeedableRng};
1406        use itertools::Itertools;
1407
1408        // Use a ChaCha RNG to be reproducible across platforms
1409        let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(12345);
1410        points.extend(repeat_with(|| rng.gen_range(-1.0..1.0))
1411            .tuple_windows()
1412            .filter(|(x, y): &(f64, f64)| (x*x + y*y).sqrt() < 0.95)
1413            .take(M));
1414
1415        let t = Triangulation::build_with_edges(&points, &edges)
1416            .expect("Could not build triangulation");
1417        assert!(t.inside((0.0, 0.0)));
1418        assert!(!t.inside((1.01, 0.0)));
1419    }
1420
1421    #[test]
1422    fn spiral_circle() {
1423        let mut edges = Vec::new();
1424        let mut points = Vec::new();
1425        const N: usize = 16;
1426        for i in 0..N {
1427            let a = (i as f64) / (N as f64) * core::f64::consts::PI * 2.0;
1428            let x = a.cos();
1429            let y = a.sin();
1430            points.push((x, y));
1431            edges.push((i, (i + 1) % N));
1432        }
1433        const M: usize = 32;
1434        for i in 0..(2*M) {
1435            let a = (i as f64) / (M as f64) * core::f64::consts::PI * 2.0;
1436            let scale = (i as f64 + 1.1).powf(0.2);
1437            let x = a.cos() / scale;
1438            let y = a.sin() / scale;
1439            points.push((x, y));
1440        }
1441
1442        let t = Triangulation::build_with_edges(&points, &edges)
1443            .expect("Could not build triangulation");
1444        assert!(t.inside((0.0, 0.0)));
1445        assert!(!t.inside((1.01, 0.0)));
1446    }
1447
1448    #[test]
1449    fn nested_circles() {
1450        let mut edges = Vec::new();
1451        let mut points = Vec::new();
1452        const N: usize = 32;
1453        for i in 0..N {
1454            let a = (i as f64) / (N as f64) * core::f64::consts::PI * 2.0;
1455            let x = a.cos();
1456            let y = a.sin();
1457            points.push((x, y));
1458            edges.push((i, (i + 1) % N));
1459        }
1460        for i in 0..N {
1461            let a = (i as f64) / (N as f64) * core::f64::consts::PI * 2.0;
1462            let x = a.cos() / 2.0;
1463            let y = a.sin() / 2.0;
1464            points.push((x, y));
1465            edges.push((N + i, N + (i + 1) % N));
1466        }
1467
1468        let t = Triangulation::build_with_edges(&points, &edges)
1469            .expect("Could not build triangulation");
1470        assert!(!t.inside((0.0, 0.0)));
1471        assert!(!t.inside((1.01, 0.0)));
1472        assert!(t.inside((0.75, 0.0)));
1473        assert!(t.inside((0.0, 0.8)));
1474    }
1475
1476    #[test]
1477    fn grid() {
1478        let mut points = Vec::new();
1479        const N: usize = 32;
1480        for i in 0..N {
1481            for j in 0..N {
1482                points.push((i as f64, j as f64));
1483            }
1484        }
1485        let t = Triangulation::build(&points)
1486            .expect("Could not build triangulation");
1487        t.check();
1488    }
1489
1490    #[test]
1491    fn grid_with_fixed_circle() {
1492        let mut edges = Vec::new();
1493        let mut points = Vec::new();
1494        const N: usize = 32;
1495        for i in 0..N {
1496            let a = (i as f64) / (N as f64) * core::f64::consts::PI * 2.0;
1497            let x = a.cos() * 0.9;
1498            let y = a.sin() * 0.9;
1499            points.push((x, y));
1500            edges.push((i, (i + 1) % N));
1501        }
1502        const M: usize = 32;
1503        for i in 0..M {
1504            for j in 0..M {
1505                points.push((i as f64 / M as f64 * 2.0 - 1.0,
1506                             j as f64 / M as f64 * 2.0 - 1.0));
1507            }
1508        }
1509        let t = Triangulation::build_with_edges(&points, &edges)
1510            .expect("Could not build triangulation");
1511        t.check();
1512    }
1513
1514    #[test]
1515    fn new_from_contours() {
1516        let t = Triangulation::build_from_contours::<Vec<usize>>(
1517            &[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)], &vec![]);
1518        assert!(t.is_ok());
1519
1520        let t = Triangulation::build_from_contours(
1521            &[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)], &[vec![]]);
1522        assert!(t.is_ok());
1523
1524        let t = Triangulation::build_from_contours(
1525            &[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)], &[vec![0]]);
1526        assert!(t.is_ok());
1527
1528        let t = Triangulation::build_from_contours(
1529            &[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)], &[vec![0, 1]]);
1530        assert!(t.is_err());
1531        if let Err(e) = t {
1532            assert!(e == Error::OpenContour);
1533        }
1534    }
1535}