earcutr/
lib.rs

1use itertools::Itertools;
2use std::{cmp, iter, ops};
3
4static DIM: usize = 2;
5static NULL: usize = 0;
6
7#[cfg(test)]
8mod tests;
9
10#[doc(hidden)]
11pub mod legacy;
12
13pub use legacy::deviation;
14pub use legacy::flatten;
15
16type LinkedListNodeIndex = usize;
17type VerticesIndex = usize;
18
19pub trait Float: num_traits::float::Float {}
20
21impl<T> Float for T where T: num_traits::float::Float {}
22
23#[derive(Debug, PartialEq, Copy, Clone)]
24#[non_exhaustive]
25pub enum Error {
26    Unknown,
27}
28
29impl std::fmt::Display for Error {
30    fn fmt(&self, mut f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        match self {
32            Error::Unknown => write!(&mut f, "Unknown error"),
33        }
34    }
35}
36
37impl std::error::Error for Error {}
38
39#[derive(Clone, Copy, Debug, PartialEq)]
40struct Coord<T: Float> {
41    x: T,
42    y: T,
43}
44
45impl<T: Float> Coord<T> {
46    // z-order of a point given coords and inverse of the longer side of
47    // data bbox
48    #[inline(always)]
49    fn zorder(&self, invsize: T) -> Result<i32, Error> {
50        // coords are transformed into non-negative 15-bit integer range
51        // stored in two 32bit ints, which are combined into a single 64 bit int.
52        let x: i64 = num_traits::cast::<T, i64>(self.x * invsize).ok_or(Error::Unknown)?;
53        let y: i64 = num_traits::cast::<T, i64>(self.y * invsize).ok_or(Error::Unknown)?;
54        let mut xy: i64 = x << 32 | y;
55
56        // todo ... big endian?
57        xy = (xy | (xy << 8)) & 0x00FF00FF00FF00FF;
58        xy = (xy | (xy << 4)) & 0x0F0F0F0F0F0F0F0F;
59        xy = (xy | (xy << 2)) & 0x3333333333333333;
60        xy = (xy | (xy << 1)) & 0x5555555555555555;
61
62        Ok(((xy >> 32) | (xy << 1)) as i32)
63    }
64}
65
66#[derive(Clone, Copy, Debug)]
67struct LinkedListNode<T: Float> {
68    /// vertex index in flat one-d array of 64bit float coords
69    vertices_index: VerticesIndex,
70    /// vertex
71    coord: Coord<T>,
72    /// previous vertex node in a polygon ring
73    prev_linked_list_node_index: LinkedListNodeIndex,
74    /// next vertex node in a polygon ring
75    next_linked_list_node_index: LinkedListNodeIndex,
76    /// z-order curve value
77    z: i32,
78    /// previous node in z-order
79    prevz_idx: LinkedListNodeIndex,
80    /// next node in z-order
81    nextz_idx: LinkedListNodeIndex,
82    /// indicates whether this is a steiner point
83    is_steiner_point: bool,
84    /// index within LinkedLists vector that holds all nodes
85    idx: LinkedListNodeIndex,
86}
87
88impl<T: Float> LinkedListNode<T> {
89    fn new(i: VerticesIndex, coord: Coord<T>, idx: LinkedListNodeIndex) -> LinkedListNode<T> {
90        LinkedListNode {
91            vertices_index: i,
92            coord,
93            prev_linked_list_node_index: NULL,
94            next_linked_list_node_index: NULL,
95            z: 0,
96            nextz_idx: NULL,
97            prevz_idx: NULL,
98            is_steiner_point: false,
99            idx,
100        }
101    }
102
103    // check if two points are equal
104    fn xy_eq(&self, other: LinkedListNode<T>) -> bool {
105        self.coord == other.coord
106    }
107
108    fn prev_linked_list_node(&self, linked_list_nodes: &LinkedLists<T>) -> LinkedListNode<T> {
109        linked_list_nodes.nodes[self.prev_linked_list_node_index]
110    }
111
112    fn next_linked_list_node(&self, linked_list_nodes: &LinkedLists<T>) -> LinkedListNode<T> {
113        linked_list_nodes.nodes[self.next_linked_list_node_index]
114    }
115}
116
117pub struct LinkedLists<T: Float> {
118    nodes: Vec<LinkedListNode<T>>,
119    invsize: T,
120    min: Coord<T>,
121    max: Coord<T>,
122    usehash: bool,
123}
124
125struct Vertices<'a, T: Float>(&'a [T]);
126
127impl<'a, T: Float> Vertices<'a, T> {
128    fn is_empty(&'a self) -> bool {
129        self.0.is_empty()
130    }
131
132    fn len(&'a self) -> usize {
133        self.0.len()
134    }
135
136    fn signed_area(&self, start: VerticesIndex, end: VerticesIndex) -> T {
137        let i = (start..end).step_by(DIM);
138        let j = (start..end).cycle().skip((end - DIM) - start).step_by(DIM);
139        let zero = T::zero();
140        i.zip(j).fold(zero, |s, (i, j)| {
141            s + (self.0[j] - self.0[i]) * (self.0[i + 1] + self.0[j + 1])
142        })
143    }
144}
145
146// Note: none of the following macros work for Left-Hand-Side of assignment.
147macro_rules! next {
148    ($ll:expr,$idx:expr) => {
149        $ll.nodes[$ll.nodes[$idx].next_linked_list_node_index]
150    };
151}
152macro_rules! nextref {
153    ($ll:expr,$idx:expr) => {
154        &$ll.nodes[$ll.nodes[$idx].next_linked_list_node_index]
155    };
156}
157macro_rules! prev {
158    ($ll:expr,$idx:expr) => {
159        $ll.nodes[$ll.nodes[$idx].prev_linked_list_node_index]
160    };
161}
162macro_rules! prevref {
163    ($ll:expr,$idx:expr) => {
164        &$ll.nodes[$ll.nodes[$idx].prev_linked_list_node_index]
165    };
166}
167
168impl<T: Float> LinkedLists<T> {
169    fn iter(&self, r: ops::Range<LinkedListNodeIndex>) -> NodeIterator<T> {
170        NodeIterator::new(self, r.start, r.end)
171    }
172
173    fn iter_pairs(&self, r: ops::Range<LinkedListNodeIndex>) -> NodePairIterator<T> {
174        NodePairIterator::new(self, r.start, r.end)
175    }
176
177    fn insert_node(
178        &mut self,
179        i: VerticesIndex,
180        coord: Coord<T>,
181        last: Option<LinkedListNodeIndex>,
182    ) -> LinkedListNodeIndex {
183        let mut p = LinkedListNode::new(i, coord, self.nodes.len());
184        match last {
185            None => {
186                p.next_linked_list_node_index = p.idx;
187                p.prev_linked_list_node_index = p.idx;
188            }
189            Some(last) => {
190                p.next_linked_list_node_index = self.nodes[last].next_linked_list_node_index;
191                p.prev_linked_list_node_index = last;
192                let lastnextidx = self.nodes[last].next_linked_list_node_index;
193                self.nodes[lastnextidx].prev_linked_list_node_index = p.idx;
194                self.nodes[last].next_linked_list_node_index = p.idx;
195            }
196        }
197        let result = p.idx;
198        self.nodes.push(p);
199        result
200    }
201    fn remove_node(&mut self, p_idx: LinkedListNodeIndex) {
202        let pi = self.nodes[p_idx].prev_linked_list_node_index;
203        let ni = self.nodes[p_idx].next_linked_list_node_index;
204        let pz = self.nodes[p_idx].prevz_idx;
205        let nz = self.nodes[p_idx].nextz_idx;
206        self.nodes[pi].next_linked_list_node_index = ni;
207        self.nodes[ni].prev_linked_list_node_index = pi;
208        self.nodes[pz].nextz_idx = nz;
209        self.nodes[nz].prevz_idx = pz;
210    }
211    fn new(size_hint: usize) -> LinkedLists<T> {
212        let mut ll = LinkedLists {
213            nodes: Vec::with_capacity(size_hint),
214            invsize: T::zero(),
215            min: Coord {
216                x: T::max_value(),
217                y: T::max_value(),
218            },
219            max: Coord {
220                x: T::min_value(),
221                y: T::min_value(),
222            },
223            usehash: true,
224        };
225        // ll.nodes[0] is the NULL node. For example usage, see remove_node()
226        ll.nodes.push(LinkedListNode {
227            vertices_index: 0,
228            coord: Coord {
229                x: T::zero(),
230                y: T::zero(),
231            },
232            prev_linked_list_node_index: 0,
233            next_linked_list_node_index: 0,
234            z: 0,
235            nextz_idx: 0,
236            prevz_idx: 0,
237            is_steiner_point: false,
238            idx: 0,
239        });
240        ll
241    }
242
243    // interlink polygon nodes in z-order
244    fn index_curve(&mut self, start: LinkedListNodeIndex) -> Result<(), Error> {
245        let invsize = self.invsize;
246        let mut p = start;
247        loop {
248            if self.nodes[p].z == 0 {
249                self.nodes[p].z = self.nodes[p].coord.zorder(invsize)?;
250            }
251            self.nodes[p].prevz_idx = self.nodes[p].prev_linked_list_node_index;
252            self.nodes[p].nextz_idx = self.nodes[p].next_linked_list_node_index;
253            p = self.nodes[p].next_linked_list_node_index;
254            if p == start {
255                break;
256            }
257        }
258
259        let pzi = self.nodes[start].prevz_idx;
260        self.nodes[pzi].nextz_idx = NULL;
261        self.nodes[start].prevz_idx = NULL;
262        self.sort_linked(start);
263        Ok(())
264    }
265
266    // find a bridge between vertices that connects hole with an outer ring
267    // and and link it
268    fn eliminate_hole(
269        &mut self,
270        hole_idx: LinkedListNodeIndex,
271        outer_node_idx: LinkedListNodeIndex,
272    ) {
273        let test_idx = find_hole_bridge(self, hole_idx, outer_node_idx);
274        let b = split_bridge_polygon(self, test_idx, hole_idx);
275        let ni = self.nodes[b].next_linked_list_node_index;
276        filter_points(self, b, Some(ni));
277    }
278
279    // Simon Tatham's linked list merge sort algorithm
280    // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
281    fn sort_linked(&mut self, mut list: LinkedListNodeIndex) {
282        let mut p;
283        let mut q;
284        let mut e;
285        let mut nummerges;
286        let mut psize;
287        let mut qsize;
288        let mut insize = 1;
289        let mut tail;
290
291        loop {
292            p = list;
293            list = NULL;
294            tail = NULL;
295            nummerges = 0;
296
297            while p != NULL {
298                nummerges += 1;
299                q = p;
300                psize = 0;
301                while q != NULL && psize < insize {
302                    psize += 1;
303                    q = self.nodes[q].nextz_idx;
304                }
305                qsize = insize;
306
307                while psize > 0 || (qsize > 0 && q != NULL) {
308                    if psize > 0 && (qsize == 0 || q == NULL || self.nodes[p].z <= self.nodes[q].z)
309                    {
310                        e = p;
311                        p = self.nodes[p].nextz_idx;
312                        psize -= 1;
313                    } else {
314                        e = q;
315                        q = self.nodes[q].nextz_idx;
316                        qsize -= 1;
317                    }
318
319                    if tail != NULL {
320                        self.nodes[tail].nextz_idx = e;
321                    } else {
322                        list = e;
323                    }
324
325                    self.nodes[e].prevz_idx = tail;
326                    tail = e;
327                }
328
329                p = q;
330            }
331
332            self.nodes[tail].nextz_idx = NULL;
333            insize *= 2;
334            if nummerges <= 1 {
335                break;
336            }
337        }
338    }
339
340    // add new nodes to an existing linked list.
341    fn add_contour(
342        &mut self,
343        vertices: &Vertices<T>,
344        start: VerticesIndex,
345        end: VerticesIndex,
346        clockwise: bool,
347    ) -> Result<(LinkedListNodeIndex, LinkedListNodeIndex), Error> {
348        if start > vertices.len() || end > vertices.len() || vertices.is_empty() {
349            return Err(Error::Unknown);
350        }
351
352        if end < DIM || end - DIM < start {
353            return Err(Error::Unknown);
354        }
355
356        if end < DIM {
357            return Err(Error::Unknown);
358        }
359
360        let mut lastidx = None;
361        let mut leftmost_idx = None;
362        let mut contour_minx = T::max_value();
363
364        let clockwise_iter = vertices.0[start..end].iter().copied().enumerate();
365
366        let mut iter_body = |x_index: usize, x: T, y_index: usize, y: T| {
367            lastidx = Some(self.insert_node((start + x_index) / DIM, Coord { x, y }, lastidx));
368            if contour_minx > x {
369                contour_minx = x;
370                leftmost_idx = lastidx
371            };
372            if self.usehash {
373                self.min.y = vertices.0[y_index].min(self.min.y);
374                self.max.x = vertices.0[x_index].max(self.max.x);
375                self.max.y = vertices.0[y_index].max(self.max.y);
376            }
377        };
378
379        if clockwise == (vertices.signed_area(start, end) > T::zero()) {
380            for ((x_index, x), (y_index, y)) in clockwise_iter.tuples() {
381                iter_body(x_index, x, y_index, y);
382            }
383        } else {
384            for ((y_index, y), (x_index, x)) in clockwise_iter.rev().tuples() {
385                iter_body(x_index, x, y_index, y);
386            }
387        }
388
389        self.min.x = contour_minx.min(self.min.x);
390
391        if self.nodes[lastidx.unwrap()].xy_eq(*nextref!(self, lastidx.unwrap())) {
392            self.remove_node(lastidx.unwrap());
393            lastidx = Some(self.nodes[lastidx.unwrap()].next_linked_list_node_index);
394        }
395        Ok((lastidx.unwrap(), leftmost_idx.unwrap()))
396    }
397
398    // check if a diagonal between two polygon nodes is valid (lies in
399    // polygon interior)
400    fn is_valid_diagonal(&self, a: &LinkedListNode<T>, b: &LinkedListNode<T>) -> bool {
401        next!(self, a.idx).vertices_index != b.vertices_index
402            && prev!(self, a.idx).vertices_index != b.vertices_index
403            && !intersects_polygon(self, *a, *b)
404            && locally_inside(self, a, b)
405            && locally_inside(self, b, a)
406            && middle_inside(self, a, b)
407    }
408}
409
410struct NodeIterator<'a, T: Float> {
411    cur: LinkedListNodeIndex,
412    end: LinkedListNodeIndex,
413    ll: &'a LinkedLists<T>,
414    pending_result: Option<&'a LinkedListNode<T>>,
415}
416
417impl<'a, T: Float> NodeIterator<'a, T> {
418    fn new(
419        ll: &LinkedLists<T>,
420        start: LinkedListNodeIndex,
421        end: LinkedListNodeIndex,
422    ) -> NodeIterator<T> {
423        NodeIterator {
424            pending_result: Some(&ll.nodes[start]),
425            cur: start,
426            end,
427            ll,
428        }
429    }
430}
431
432impl<'a, T: Float> Iterator for NodeIterator<'a, T> {
433    type Item = &'a LinkedListNode<T>;
434    fn next(&mut self) -> Option<Self::Item> {
435        self.cur = self.ll.nodes[self.cur].next_linked_list_node_index;
436        let cur_result = self.pending_result;
437        self.pending_result = if self.cur == self.end {
438            // only one branch, saves time
439            None
440        } else {
441            Some(&self.ll.nodes[self.cur])
442        };
443        cur_result
444    }
445}
446
447struct NodePairIterator<'a, T: Float> {
448    cur: LinkedListNodeIndex,
449    end: LinkedListNodeIndex,
450    ll: &'a LinkedLists<T>,
451    pending_result: Option<(&'a LinkedListNode<T>, &'a LinkedListNode<T>)>,
452}
453
454impl<'a, T: Float> NodePairIterator<'a, T> {
455    fn new(
456        ll: &LinkedLists<T>,
457        start: LinkedListNodeIndex,
458        end: LinkedListNodeIndex,
459    ) -> NodePairIterator<T> {
460        NodePairIterator {
461            pending_result: Some((&ll.nodes[start], nextref!(ll, start))),
462            cur: start,
463            end,
464            ll,
465        }
466    }
467}
468
469impl<'a, T: Float> Iterator for NodePairIterator<'a, T> {
470    type Item = (&'a LinkedListNode<T>, &'a LinkedListNode<T>);
471    fn next(&mut self) -> Option<Self::Item> {
472        self.cur = self.ll.nodes[self.cur].next_linked_list_node_index;
473        let cur_result = self.pending_result;
474        if self.cur == self.end {
475            // only one branch, saves time
476            self.pending_result = None;
477        } else {
478            self.pending_result = Some((&self.ll.nodes[self.cur], nextref!(self.ll, self.cur)))
479        }
480        cur_result
481    }
482}
483
484// link every hole into the outer loop, producing a single-ring polygon
485// without holes
486fn eliminate_holes<T: Float>(
487    ll: &mut LinkedLists<T>,
488    vertices: &Vertices<T>,
489    hole_indices: &[VerticesIndex],
490    inouter_node: LinkedListNodeIndex,
491) -> Result<LinkedListNodeIndex, Error> {
492    let mut outer_node = inouter_node;
493    let mut queue: Vec<LinkedListNode<T>> = Vec::new();
494    for (vertices_hole_start_index, vertices_hole_end_index) in hole_indices
495        .iter()
496        .map(|index| index.checked_mul(DIM).ok_or(Error::Unknown))
497        .chain(iter::once(Ok(vertices.0.len())))
498        .tuple_windows()
499    {
500        let vertices_hole_start_index = vertices_hole_start_index?;
501        let vertices_hole_end_index = vertices_hole_end_index?;
502        let (list, leftmost_idx) = ll.add_contour(
503            vertices,
504            vertices_hole_start_index,
505            vertices_hole_end_index,
506            false,
507        )?;
508        if list == ll.nodes[list].next_linked_list_node_index {
509            ll.nodes[list].is_steiner_point = true;
510        }
511        queue.push(ll.nodes[leftmost_idx]);
512    }
513
514    queue.sort_by(|a, b| {
515        a.coord
516            .x
517            .partial_cmp(&b.coord.x)
518            .unwrap_or(cmp::Ordering::Equal)
519    });
520
521    // process holes from left to right
522    for node in queue {
523        ll.eliminate_hole(node.idx, outer_node);
524        let nextidx = next!(ll, outer_node).idx;
525        outer_node = filter_points(ll, outer_node, Some(nextidx));
526    }
527    Ok(outer_node)
528} // elim holes
529
530// minx, miny and invsize are later used to transform coords
531// into integers for z-order calculation
532fn calc_invsize<T: Float>(min: Coord<T>, max: Coord<T>) -> T {
533    let invsize = (max.x - min.x).max(max.y - min.y);
534    match invsize.is_zero() {
535        true => T::zero(),
536        false => num_traits::cast::<f64, T>(32767.0).unwrap() / invsize,
537    }
538}
539
540// main ear slicing loop which triangulates a polygon (given as a linked
541// list)
542fn earcut_linked_hashed<const PASS: usize, T: Float>(
543    ll: &mut LinkedLists<T>,
544    mut ear_idx: LinkedListNodeIndex,
545    triangle_indices: &mut FinalTriangleIndices,
546) -> Result<(), Error> {
547    // interlink polygon nodes in z-order
548    if PASS == 0 {
549        ll.index_curve(ear_idx)?;
550    }
551    // iterate through ears, slicing them one by one
552    let mut stop_idx = ear_idx;
553    let mut prev_idx = 0;
554    let mut next_idx = ll.nodes[ear_idx].next_linked_list_node_index;
555    while stop_idx != next_idx {
556        prev_idx = ll.nodes[ear_idx].prev_linked_list_node_index;
557        next_idx = ll.nodes[ear_idx].next_linked_list_node_index;
558        let node_index_triangle = NodeIndexTriangle(prev_idx, ear_idx, next_idx);
559        if node_index_triangle.node_triangle(ll).is_ear_hashed(ll)? {
560            triangle_indices.push(VerticesIndexTriangle(
561                ll.nodes[prev_idx].vertices_index,
562                ll.nodes[ear_idx].vertices_index,
563                ll.nodes[next_idx].vertices_index,
564            ));
565            ll.remove_node(ear_idx);
566            // skipping the next vertex leads to less sliver triangles
567            ear_idx = ll.nodes[next_idx].next_linked_list_node_index;
568            stop_idx = ear_idx;
569        } else {
570            ear_idx = next_idx;
571        }
572    }
573
574    if prev_idx == next_idx {
575        return Ok(());
576    };
577    // if we looped through the whole remaining polygon and can't
578    // find any more ears
579    if PASS == 0 {
580        let tmp = filter_points(ll, next_idx, None);
581        earcut_linked_hashed::<1, T>(ll, tmp, triangle_indices)?;
582    } else if PASS == 1 {
583        ear_idx = cure_local_intersections(ll, next_idx, triangle_indices);
584        earcut_linked_hashed::<2, T>(ll, ear_idx, triangle_indices)?;
585    } else if PASS == 2 {
586        split_earcut(ll, next_idx, triangle_indices)?;
587    }
588    Ok(())
589}
590
591// main ear slicing loop which triangulates a polygon (given as a linked
592// list)
593fn earcut_linked_unhashed<const PASS: usize, T: Float>(
594    ll: &mut LinkedLists<T>,
595    mut ear_idx: LinkedListNodeIndex,
596    triangles: &mut FinalTriangleIndices,
597) -> Result<(), Error> {
598    // iterate through ears, slicing them one by one
599    let mut stop_idx = ear_idx;
600    let mut prev_idx = 0;
601    let mut next_idx = ll.nodes[ear_idx].next_linked_list_node_index;
602    while stop_idx != next_idx {
603        prev_idx = ll.nodes[ear_idx].prev_linked_list_node_index;
604        next_idx = ll.nodes[ear_idx].next_linked_list_node_index;
605        if NodeIndexTriangle(prev_idx, ear_idx, next_idx).is_ear(ll) {
606            triangles.push(VerticesIndexTriangle(
607                ll.nodes[prev_idx].vertices_index,
608                ll.nodes[ear_idx].vertices_index,
609                ll.nodes[next_idx].vertices_index,
610            ));
611            ll.remove_node(ear_idx);
612            // skipping the next vertex leads to less sliver triangles
613            ear_idx = ll.nodes[next_idx].next_linked_list_node_index;
614            stop_idx = ear_idx;
615        } else {
616            ear_idx = next_idx;
617        }
618    }
619
620    if prev_idx == next_idx {
621        return Ok(());
622    };
623    // if we looped through the whole remaining polygon and can't
624    // find any more ears
625    if PASS == 0 {
626        let tmp = filter_points(ll, next_idx, None);
627        earcut_linked_unhashed::<1, T>(ll, tmp, triangles)?;
628    } else if PASS == 1 {
629        ear_idx = cure_local_intersections(ll, next_idx, triangles);
630        earcut_linked_unhashed::<2, T>(ll, ear_idx, triangles)?;
631    } else if PASS == 2 {
632        split_earcut(ll, next_idx, triangles)?;
633    }
634    Ok(())
635}
636
637#[derive(Clone, Copy)]
638struct NodeIndexTriangle(
639    LinkedListNodeIndex,
640    LinkedListNodeIndex,
641    LinkedListNodeIndex,
642);
643
644impl NodeIndexTriangle {
645    fn prev_node<T: Float>(self, ll: &LinkedLists<T>) -> LinkedListNode<T> {
646        ll.nodes[self.0]
647    }
648
649    fn ear_node<T: Float>(self, ll: &LinkedLists<T>) -> LinkedListNode<T> {
650        ll.nodes[self.1]
651    }
652
653    fn next_node<T: Float>(self, ll: &LinkedLists<T>) -> LinkedListNode<T> {
654        ll.nodes[self.2]
655    }
656
657    fn node_triangle<T: Float>(self, ll: &LinkedLists<T>) -> NodeTriangle<T> {
658        NodeTriangle(self.prev_node(ll), self.ear_node(ll), self.next_node(ll))
659    }
660
661    fn area<T: Float>(self, ll: &LinkedLists<T>) -> T {
662        self.node_triangle(ll).area()
663    }
664
665    // check whether a polygon node forms a valid ear with adjacent nodes
666    fn is_ear<T: Float>(self, ll: &LinkedLists<T>) -> bool {
667        let zero = T::zero();
668        match self.area(ll) >= zero {
669            true => false, // reflex, cant be ear
670            false => !ll
671                .iter(self.next_node(ll).next_linked_list_node_index..self.prev_node(ll).idx)
672                .any(|p| {
673                    self.node_triangle(ll).contains_point(*p)
674                        && (NodeTriangle(*prevref!(ll, p.idx), *p, *nextref!(ll, p.idx)).area()
675                            >= zero)
676                }),
677        }
678    }
679}
680
681#[derive(Clone, Copy)]
682struct NodeTriangle<T: Float>(LinkedListNode<T>, LinkedListNode<T>, LinkedListNode<T>);
683
684impl<T: Float> NodeTriangle<T> {
685    fn from_ear_node(ear_node: LinkedListNode<T>, ll: &LinkedLists<T>) -> Self {
686        NodeTriangle(
687            ear_node.prev_linked_list_node(ll),
688            ear_node,
689            ear_node.next_linked_list_node(ll),
690        )
691    }
692
693    fn area(&self) -> T {
694        let p = self.0;
695        let q = self.1;
696        let r = self.2;
697        // signed area of a parallelogram
698        (q.coord.y - p.coord.y) * (r.coord.x - q.coord.x)
699            - (q.coord.x - p.coord.x) * (r.coord.y - q.coord.y)
700    }
701
702    // check if a point lies within a convex triangle
703    fn contains_point(&self, p: LinkedListNode<T>) -> bool {
704        let zero = T::zero();
705
706        ((self.2.coord.x - p.coord.x) * (self.0.coord.y - p.coord.y)
707            - (self.0.coord.x - p.coord.x) * (self.2.coord.y - p.coord.y)
708            >= zero)
709            && ((self.0.coord.x - p.coord.x) * (self.1.coord.y - p.coord.y)
710                - (self.1.coord.x - p.coord.x) * (self.0.coord.y - p.coord.y)
711                >= zero)
712            && ((self.1.coord.x - p.coord.x) * (self.2.coord.y - p.coord.y)
713                - (self.2.coord.x - p.coord.x) * (self.1.coord.y - p.coord.y)
714                >= zero)
715    }
716
717    #[inline(always)]
718    fn is_ear_hashed(&self, ll: &mut LinkedLists<T>) -> Result<bool, Error> {
719        let zero = T::zero();
720
721        if self.area() >= zero {
722            return Ok(false);
723        };
724        let NodeTriangle(prev, ear, next) = self;
725
726        let bbox_maxx = prev.coord.x.max(ear.coord.x.max(next.coord.x));
727        let bbox_maxy = prev.coord.y.max(ear.coord.y.max(next.coord.y));
728        let bbox_minx = prev.coord.x.min(ear.coord.x.min(next.coord.x));
729        let bbox_miny = prev.coord.y.min(ear.coord.y.min(next.coord.y));
730        // z-order range for the current triangle bbox;
731        let min_z = Coord {
732            x: bbox_minx,
733            y: bbox_miny,
734        }
735        .zorder(ll.invsize)?;
736        let max_z = Coord {
737            x: bbox_maxx,
738            y: bbox_maxy,
739        }
740        .zorder(ll.invsize)?;
741
742        let mut p = ear.prevz_idx;
743        let mut n = ear.nextz_idx;
744        while (p != NULL) && (ll.nodes[p].z >= min_z) && (n != NULL) && (ll.nodes[n].z <= max_z) {
745            if earcheck(
746                prev,
747                ear,
748                next,
749                prevref!(ll, p),
750                &ll.nodes[p],
751                nextref!(ll, p),
752            ) {
753                return Ok(false);
754            }
755            p = ll.nodes[p].prevz_idx;
756
757            if earcheck(
758                prev,
759                ear,
760                next,
761                prevref!(ll, n),
762                &ll.nodes[n],
763                nextref!(ll, n),
764            ) {
765                return Ok(false);
766            }
767            n = ll.nodes[n].nextz_idx;
768        }
769
770        ll.nodes[NULL].z = min_z - 1;
771        while ll.nodes[p].z >= min_z {
772            if earcheck(
773                prev,
774                ear,
775                next,
776                prevref!(ll, p),
777                &ll.nodes[p],
778                nextref!(ll, p),
779            ) {
780                return Ok(false);
781            }
782            p = ll.nodes[p].prevz_idx;
783        }
784
785        ll.nodes[NULL].z = max_z + 1;
786        while ll.nodes[n].z <= max_z {
787            if earcheck(
788                prev,
789                ear,
790                next,
791                prevref!(ll, n),
792                &ll.nodes[n],
793                nextref!(ll, n),
794            ) {
795                return Ok(false);
796            }
797            n = ll.nodes[n].nextz_idx;
798        }
799
800        Ok(true)
801    }
802}
803
804// helper for is_ear_hashed. needs manual inline (rust 2018)
805#[inline(always)]
806fn earcheck<T: Float>(
807    a: &LinkedListNode<T>,
808    b: &LinkedListNode<T>,
809    c: &LinkedListNode<T>,
810    prev: &LinkedListNode<T>,
811    p: &LinkedListNode<T>,
812    next: &LinkedListNode<T>,
813) -> bool {
814    let zero = T::zero();
815
816    (p.idx != a.idx)
817        && (p.idx != c.idx)
818        && NodeTriangle(*a, *b, *c).contains_point(*p)
819        && NodeTriangle(*prev, *p, *next).area() >= zero
820}
821
822fn filter_points<T: Float>(
823    ll: &mut LinkedLists<T>,
824    start: LinkedListNodeIndex,
825    end: Option<LinkedListNodeIndex>,
826) -> LinkedListNodeIndex {
827    let mut end = end.unwrap_or(start);
828    if end >= ll.nodes.len() || start >= ll.nodes.len() {
829        return NULL;
830    }
831
832    let mut p = start;
833    let mut again;
834
835    // this loop "wastes" calculations by going over the same points multiple
836    // times. however, altering the location of the 'end' node can disrupt
837    // the algorithm of other code that calls the filter_points function.
838    loop {
839        again = false;
840        if !ll.nodes[p].is_steiner_point
841            && (ll.nodes[p].xy_eq(ll.nodes[ll.nodes[p].next_linked_list_node_index])
842                || NodeTriangle::from_ear_node(ll.nodes[p], ll)
843                    .area()
844                    .is_zero())
845        {
846            ll.remove_node(p);
847            end = ll.nodes[p].prev_linked_list_node_index;
848            p = end;
849            if p == ll.nodes[p].next_linked_list_node_index {
850                break end;
851            }
852            again = true;
853        } else {
854            if p == ll.nodes[p].next_linked_list_node_index {
855                break NULL;
856            }
857            p = ll.nodes[p].next_linked_list_node_index;
858        }
859        if !again && p == end {
860            break end;
861        }
862    }
863}
864
865// create a circular doubly linked list from polygon points in the
866// specified winding order
867fn linked_list<T: Float>(
868    vertices: &Vertices<T>,
869    start: usize,
870    end: usize,
871    clockwise: bool,
872) -> Result<(LinkedLists<T>, LinkedListNodeIndex), Error> {
873    let mut ll: LinkedLists<T> = LinkedLists::new(vertices.len() / DIM);
874    if vertices.len() < 80 {
875        ll.usehash = false
876    };
877    let (last_idx, _) = ll.add_contour(vertices, start, end, clockwise)?;
878    Ok((ll, last_idx))
879}
880
881struct VerticesIndexTriangle(usize, usize, usize);
882
883#[derive(Default, Debug)]
884struct FinalTriangleIndices(Vec<usize>);
885
886impl FinalTriangleIndices {
887    fn push(&mut self, vertices_index_triangle: VerticesIndexTriangle) {
888        self.0.push(vertices_index_triangle.0);
889        self.0.push(vertices_index_triangle.1);
890        self.0.push(vertices_index_triangle.2);
891    }
892}
893
894pub fn earcut<T: Float>(
895    vertices: &[T],
896    hole_indices: &[VerticesIndex],
897    dims: usize,
898) -> Result<Vec<usize>, Error> {
899    if vertices.is_empty() && hole_indices.is_empty() {
900        return Ok(vec![]);
901    }
902
903    if vertices.len() % 2 == 1 || dims > vertices.len() {
904        return Err(Error::Unknown);
905    }
906
907    let outer_len = match hole_indices.first() {
908        Some(first_hole_index) => {
909            let outer_len = first_hole_index.checked_mul(DIM).ok_or(Error::Unknown)?;
910            if outer_len > vertices.len() || outer_len == 0 {
911                return Err(Error::Unknown);
912            }
913            if outer_len % 2 == 1 {
914                return Err(Error::Unknown);
915            }
916            outer_len
917        }
918        None => vertices.len(),
919    };
920
921    let vertices = Vertices(vertices);
922    let (mut ll, outer_node) = linked_list(&vertices, 0, outer_len, true)?;
923    let mut triangles = FinalTriangleIndices(Vec::with_capacity(vertices.len() / DIM));
924    if ll.nodes.len() == 1 || DIM != dims {
925        return Ok(triangles.0);
926    }
927
928    let outer_node = eliminate_holes(&mut ll, &vertices, hole_indices, outer_node)?;
929
930    if ll.usehash {
931        ll.invsize = calc_invsize(ll.min, ll.max);
932
933        // translate all points so min is 0,0. prevents subtraction inside
934        // zorder. also note invsize does not depend on translation in space
935        // if one were translating in a space with an even spaced grid of points.
936        // floating point space is not evenly spaced, but it is close enough for
937        // this hash algorithm
938        let (mx, my) = (ll.min.x, ll.min.y);
939        ll.nodes.iter_mut().for_each(|n| {
940            n.coord.x = n.coord.x - mx;
941            n.coord.y = n.coord.y - my;
942        });
943        earcut_linked_hashed::<0, T>(&mut ll, outer_node, &mut triangles)?;
944    } else {
945        earcut_linked_unhashed::<0, T>(&mut ll, outer_node, &mut triangles)?;
946    }
947
948    Ok(triangles.0)
949}
950
951/* go through all polygon nodes and cure small local self-intersections
952what is a small local self-intersection? well, lets say you have four points
953a,b,c,d. now imagine you have three line segments, a-b, b-c, and c-d. now
954imagine two of those segments overlap each other. thats an intersection. so
955this will remove one of those nodes so there is no more overlap.
956
957but theres another important aspect of this function. it will dump triangles
958into the 'triangles' variable, thus this is part of the triangulation
959algorithm itself.*/
960fn cure_local_intersections<T: Float>(
961    ll: &mut LinkedLists<T>,
962    instart: LinkedListNodeIndex,
963    triangles: &mut FinalTriangleIndices,
964) -> LinkedListNodeIndex {
965    let mut p = instart;
966    let mut start = instart;
967
968    //        2--3  4--5 << 2-3 + 4-5 pseudointersects
969    //           x  x
970    //  0  1  2  3  4  5  6  7
971    //  a  p  pn b
972    //              eq     a      b
973    //              psi    a p pn b
974    //              li  pa a p pn b bn
975    //              tp     a p    b
976    //              rn       p pn
977    //              nst    a      p pn b
978    //                            st
979
980    //
981    //                            a p  pn b
982
983    loop {
984        let a = ll.nodes[p].prev_linked_list_node_index;
985        let b = next!(ll, p).next_linked_list_node_index;
986
987        if !ll.nodes[a].xy_eq(ll.nodes[b])
988            && pseudo_intersects(
989                ll.nodes[a],
990                ll.nodes[p],
991                *nextref!(ll, p),
992                ll.nodes[b],
993            )
994			// prev next a, prev next b
995            && locally_inside(ll, &ll.nodes[a], &ll.nodes[b])
996            && locally_inside(ll, &ll.nodes[b], &ll.nodes[a])
997        {
998            triangles.push(VerticesIndexTriangle(
999                ll.nodes[a].vertices_index,
1000                ll.nodes[p].vertices_index,
1001                ll.nodes[b].vertices_index,
1002            ));
1003
1004            // remove two nodes involved
1005            ll.remove_node(p);
1006            let nidx = ll.nodes[p].next_linked_list_node_index;
1007            ll.remove_node(nidx);
1008
1009            start = ll.nodes[b].idx;
1010            p = start;
1011        }
1012        p = ll.nodes[p].next_linked_list_node_index;
1013        if p == start {
1014            break;
1015        }
1016    }
1017
1018    p
1019}
1020
1021// try splitting polygon into two and triangulate them independently
1022fn split_earcut<T: Float>(
1023    ll: &mut LinkedLists<T>,
1024    start_idx: LinkedListNodeIndex,
1025    triangles: &mut FinalTriangleIndices,
1026) -> Result<(), Error> {
1027    // look for a valid diagonal that divides the polygon into two
1028    let mut a = start_idx;
1029    loop {
1030        let mut b = next!(ll, a).next_linked_list_node_index;
1031        while b != ll.nodes[a].prev_linked_list_node_index {
1032            if ll.nodes[a].vertices_index != ll.nodes[b].vertices_index
1033                && ll.is_valid_diagonal(&ll.nodes[a], &ll.nodes[b])
1034            {
1035                // split the polygon in two by the diagonal
1036                let mut c = split_bridge_polygon(ll, a, b);
1037
1038                // filter colinear points around the cuts
1039                let an = ll.nodes[a].next_linked_list_node_index;
1040                let cn = ll.nodes[c].next_linked_list_node_index;
1041                a = filter_points(ll, a, Some(an));
1042                c = filter_points(ll, c, Some(cn));
1043
1044                // run earcut on each half
1045                earcut_linked_hashed::<0, T>(ll, a, triangles)?;
1046                earcut_linked_hashed::<0, T>(ll, c, triangles)?;
1047                return Ok(());
1048            }
1049            b = ll.nodes[b].next_linked_list_node_index;
1050        }
1051        a = ll.nodes[a].next_linked_list_node_index;
1052        if a == start_idx {
1053            break;
1054        }
1055    }
1056    Ok(())
1057}
1058
1059// David Eberly's algorithm for finding a bridge between hole and outer polygon
1060fn find_hole_bridge<T: Float>(
1061    ll: &LinkedLists<T>,
1062    hole: LinkedListNodeIndex,
1063    outer_node: LinkedListNodeIndex,
1064) -> LinkedListNodeIndex {
1065    let mut p = outer_node;
1066    let hx = ll.nodes[hole].coord.x;
1067    let hy = ll.nodes[hole].coord.y;
1068    let mut qx = T::neg_infinity();
1069    let mut m: Option<LinkedListNodeIndex> = None;
1070
1071    // find a segment intersected by a ray from the hole's leftmost
1072    // point to the left; segment's endpoint with lesser x will be
1073    // potential connection point
1074    let calcx = |p: &LinkedListNode<T>| {
1075        p.coord.x
1076            + (hy - p.coord.y) * (next!(ll, p.idx).coord.x - p.coord.x)
1077                / (next!(ll, p.idx).coord.y - p.coord.y)
1078    };
1079    for (p, n) in ll
1080        .iter_pairs(p..outer_node)
1081        .filter(|(p, n)| hy <= p.coord.y && hy >= n.coord.y)
1082        .filter(|(p, n)| n.coord.y != p.coord.y)
1083        .filter(|(p, _)| calcx(p) <= hx)
1084    {
1085        if qx < calcx(p) {
1086            qx = calcx(p);
1087            if qx == hx && hy == p.coord.y {
1088                return p.idx;
1089            } else if qx == hx && hy == n.coord.y {
1090                return p.next_linked_list_node_index;
1091            }
1092            m = Some(if p.coord.x < n.coord.x { p.idx } else { n.idx });
1093        }
1094    }
1095
1096    let m = match m {
1097        Some(m) => m,
1098        None => return NULL,
1099    };
1100
1101    // hole touches outer segment; pick lower endpoint
1102    if hx == qx {
1103        return prev!(ll, m).idx;
1104    }
1105
1106    // look for points inside the triangle of hole point, segment
1107    // intersection and endpoint; if there are no points found, we have
1108    // a valid connection; otherwise choose the point of the minimum
1109    // angle with the ray as connection point
1110
1111    let mp = LinkedListNode::new(0, ll.nodes[m].coord, 0);
1112    p = next!(ll, m).idx;
1113    let x1 = if hy < mp.coord.y { hx } else { qx };
1114    let x2 = if hy < mp.coord.y { qx } else { hx };
1115    let n1 = LinkedListNode::new(0, Coord { x: x1, y: hy }, 0);
1116    let n2 = LinkedListNode::new(0, Coord { x: x2, y: hy }, 0);
1117    let two = num_traits::cast::<f64, T>(2.).unwrap();
1118
1119    let calctan = |p: &LinkedListNode<T>| (hy - p.coord.y).abs() / (hx - p.coord.x); // tangential
1120    ll.iter(p..m)
1121        .filter(|p| hx > p.coord.x && p.coord.x >= mp.coord.x)
1122        .filter(|p| NodeTriangle(n1, mp, n2).contains_point(**p))
1123        .fold((m, T::max_value() / two), |(m, tan_min), p| {
1124            if ((calctan(p) < tan_min)
1125                || (calctan(p) == tan_min && p.coord.x > ll.nodes[m].coord.x))
1126                && locally_inside(ll, p, &ll.nodes[hole])
1127            {
1128                (p.idx, calctan(p))
1129            } else {
1130                (m, tan_min)
1131            }
1132        })
1133        .0
1134}
1135
1136/* check if two segments cross over each other. note this is different
1137from pure intersction. only two segments crossing over at some interior
1138point is considered intersection.
1139
1140line segment p1-q1 vs line segment p2-q2.
1141
1142note that if they are collinear, or if the end points touch, or if
1143one touches the other at one point, it is not considered an intersection.
1144
1145please note that the other algorithms in this earcut code depend on this
1146interpretation of the concept of intersection - if this is modified
1147so that endpoint touching qualifies as intersection, then it will have
1148a problem with certain inputs.
1149
1150bsed on https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
1151
1152this has been modified from the version in earcut.js to remove the
1153detection for endpoint detection.
1154
1155    a1=area(p1,q1,p2);a2=area(p1,q1,q2);a3=area(p2,q2,p1);a4=area(p2,q2,q1);
1156    p1 q1    a1 cw   a2 cw   a3 ccw   a4  ccw  a1==a2  a3==a4  fl
1157    p2 q2
1158    p1 p2    a1 ccw  a2 ccw  a3 cw    a4  cw   a1==a2  a3==a4  fl
1159    q1 q2
1160    p1 q2    a1 ccw  a2 ccw  a3 ccw   a4  ccw  a1==a2  a3==a4  fl
1161    q1 p2
1162    p1 q2    a1 cw   a2 ccw  a3 ccw   a4  cw   a1!=a2  a3!=a4  tr
1163    p2 q1
1164*/
1165
1166fn pseudo_intersects<T: Float>(
1167    p1: LinkedListNode<T>,
1168    q1: LinkedListNode<T>,
1169    p2: LinkedListNode<T>,
1170    q2: LinkedListNode<T>,
1171) -> bool {
1172    if (p1.xy_eq(p2) && q1.xy_eq(q2)) || (p1.xy_eq(q2) && q1.xy_eq(p2)) {
1173        return true;
1174    }
1175    let zero = T::zero();
1176
1177    (NodeTriangle(p1, q1, p2).area() > zero) != (NodeTriangle(p1, q1, q2).area() > zero)
1178        && (NodeTriangle(p2, q2, p1).area() > zero) != (NodeTriangle(p2, q2, q1).area() > zero)
1179}
1180
1181// check if a polygon diagonal intersects any polygon segments
1182fn intersects_polygon<T: Float>(
1183    ll: &LinkedLists<T>,
1184    a: LinkedListNode<T>,
1185    b: LinkedListNode<T>,
1186) -> bool {
1187    ll.iter_pairs(a.idx..a.idx).any(|(p, n)| {
1188        p.vertices_index != a.vertices_index
1189            && n.vertices_index != a.vertices_index
1190            && p.vertices_index != b.vertices_index
1191            && n.vertices_index != b.vertices_index
1192            && pseudo_intersects(*p, *n, a, b)
1193    })
1194}
1195
1196// check if a polygon diagonal is locally inside the polygon
1197fn locally_inside<T: Float>(
1198    ll: &LinkedLists<T>,
1199    a: &LinkedListNode<T>,
1200    b: &LinkedListNode<T>,
1201) -> bool {
1202    let zero = T::zero();
1203
1204    match NodeTriangle(*prevref!(ll, a.idx), *a, *nextref!(ll, a.idx)).area() < zero {
1205        true => {
1206            NodeTriangle(*a, *b, *nextref!(ll, a.idx)).area() >= zero
1207                && NodeTriangle(*a, *prevref!(ll, a.idx), *b).area() >= zero
1208        }
1209        false => {
1210            NodeTriangle(*a, *b, *prevref!(ll, a.idx)).area() < zero
1211                || NodeTriangle(*a, *nextref!(ll, a.idx), *b).area() < zero
1212        }
1213    }
1214}
1215
1216// check if the middle point of a polygon diagonal is inside the polygon
1217fn middle_inside<T: Float>(
1218    ll: &LinkedLists<T>,
1219    a: &LinkedListNode<T>,
1220    b: &LinkedListNode<T>,
1221) -> bool {
1222    let two = T::one() + T::one();
1223
1224    let (mx, my) = ((a.coord.x + b.coord.x) / two, (a.coord.y + b.coord.y) / two);
1225    ll.iter_pairs(a.idx..a.idx)
1226        .filter(|(p, n)| (p.coord.y > my) != (n.coord.y > my))
1227        .filter(|(p, n)| n.coord.y != p.coord.y)
1228        .filter(|(p, n)| {
1229            (mx) < ((n.coord.x - p.coord.x) * (my - p.coord.y) / (n.coord.y - p.coord.y)
1230                + p.coord.x)
1231        })
1232        .fold(false, |inside, _| !inside)
1233}
1234
1235/* link two polygon vertices with a bridge;
1236
1237if the vertices belong to the same linked list, this splits the list
1238into two new lists, representing two new polygons.
1239
1240if the vertices belong to separate linked lists, it merges them into a
1241single linked list.
1242
1243For example imagine 6 points, labeled with numbers 0 thru 5, in a single cycle.
1244Now split at points 1 and 4. The 2 new polygon cycles will be like this:
12450 1 4 5 0 1 ...  and  1 2 3 4 1 2 3 .... However because we are using linked
1246lists of nodes, there will be two new nodes, copies of points 1 and 4. So:
1247the new cycles will be through nodes 0 1 4 5 0 1 ... and 2 3 6 7 2 3 6 7 .
1248
1249splitting algorithm:
1250
1251.0...1...2...3...4...5...     6     7
12525p1 0a2 1m3 2n4 3b5 4q0      .c.   .d.
1253
1254an<-2     an = a.next,
1255bp<-3     bp = b.prev;
12561.n<-4    a.next = b;
12574.p<-1    b.prev = a;
12586.n<-2    c.next = an;
12592.p<-6    an.prev = c;
12607.n<-6    d.next = c;
12616.p<-7    c.prev = d;
12623.n<-7    bp.next = d;
12637.p<-3    d.prev = bp;
1264
1265result of split:
1266<0...1> <2...3> <4...5>      <6....7>
12675p1 0a4 6m3 2n7 1b5 4q0      7c2  3d6
1268      x x     x x            x x  x x    // x shows links changed
1269
1270a b q p a b q p  // begin at a, go next (new cycle 1)
1271a p q b a p q b  // begin at a, go prev (new cycle 1)
1272m n d c m n d c  // begin at m, go next (new cycle 2)
1273m c d n m c d n  // begin at m, go prev (new cycle 2)
1274
1275Now imagine that we have two cycles, and
1276they are 0 1 2, and 3 4 5. Split at points 1 and
12774 will result in a single, long cycle,
12780 1 4 5 3 7 6 2 0 1 4 5 ..., where 6 and 1 have the
1279same x y f64s, as do 7 and 4.
1280
1281 0...1...2   3...4...5        6     7
12822p1 0a2 1m0 5n4 3b5 4q3      .c.   .d.
1283
1284an<-2     an = a.next,
1285bp<-3     bp = b.prev;
12861.n<-4    a.next = b;
12874.p<-1    b.prev = a;
12886.n<-2    c.next = an;
12892.p<-6    an.prev = c;
12907.n<-6    d.next = c;
12916.p<-7    c.prev = d;
12923.n<-7    bp.next = d;
12937.p<-3    d.prev = bp;
1294
1295result of split:
1296 0...1...2   3...4...5        6.....7
12972p1 0a4 6m0 5n7 1b5 4q3      7c2   3d6
1298      x x     x x            x x   x x
1299
1300a b q n d c m p a b q n d c m .. // begin at a, go next
1301a p m c d n q b a p m c d n q .. // begin at a, go prev
1302
1303Return value.
1304
1305Return value is the new node, at point 7.
1306*/
1307fn split_bridge_polygon<T: Float>(
1308    ll: &mut LinkedLists<T>,
1309    a: LinkedListNodeIndex,
1310    b: LinkedListNodeIndex,
1311) -> LinkedListNodeIndex {
1312    let cidx = ll.nodes.len();
1313    let didx = cidx + 1;
1314    let mut c = LinkedListNode::new(ll.nodes[a].vertices_index, ll.nodes[a].coord, cidx);
1315    let mut d = LinkedListNode::new(ll.nodes[b].vertices_index, ll.nodes[b].coord, didx);
1316
1317    let an = ll.nodes[a].next_linked_list_node_index;
1318    let bp = ll.nodes[b].prev_linked_list_node_index;
1319
1320    ll.nodes[a].next_linked_list_node_index = b;
1321    ll.nodes[b].prev_linked_list_node_index = a;
1322
1323    c.next_linked_list_node_index = an;
1324    ll.nodes[an].prev_linked_list_node_index = cidx;
1325
1326    d.next_linked_list_node_index = cidx;
1327    c.prev_linked_list_node_index = didx;
1328
1329    ll.nodes[bp].next_linked_list_node_index = didx;
1330    d.prev_linked_list_node_index = bp;
1331
1332    ll.nodes.push(c);
1333    ll.nodes.push(d);
1334    didx
1335}