@@ -165,6 +165,7 @@ class Delaunator {
165165private:
166166 std::vector<std::size_t > m_hash;
167167 std::vector<DelaunatorPoint> m_hull;
168+ std::size_t m_hull_entry;
168169 double m_center_x;
169170 double m_center_y;
170171 std::size_t m_hash_size;
@@ -279,20 +280,21 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
279280 std::tie (m_center_x, m_center_y) = circumcenter (i0x, i0y, i1x, i1y, i2x, i2y);
280281
281282 // sort the points by distance from the seed triangle circumcenter
282- // cerr << ids << endl;
283283 std::sort (ids.begin (), ids.end (), sort_to_center{ coords, m_center_x, m_center_y });
284- // quicksort(ids, coords, 0, n - 1, m_center_x, m_center_y);
285- // cerr << ids << endl;
286284
285+ // initialize a hash table for storing edges of the advancing convex hull
287286 m_hash_size = static_cast <std::size_t >(std::llround (std::ceil (std::sqrt (n))));
288287 m_hash.reserve (m_hash_size);
289288 for (std::size_t i = 0 ; i < m_hash_size; i++) {
290289 m_hash.push_back (INVALID_INDEX);
291290 }
292291
292+ // initialize a circular doubly-linked list that will hold an advancing convex hull
293+ // doubly-linked list is stored as plain vector
294+ // vertices are linked via ineces of next/prev vertice
293295 m_hull.reserve (coords.size ());
294-
295296 std::size_t e = insert_node (i0);
297+ m_hull_entry = e;
296298 hash_edge (e);
297299 m_hull[e].t = 0 ;
298300
@@ -360,9 +362,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
360362
361363 // recursively flip triangles from the point until they satisfy the Delaunay condition
362364 m_hull[e].t = legalize (t + 2 );
363- if (m_hull[m_hull[m_hull[e].prev ].prev ].t == halfedges[t + 1 ]) {
364- m_hull[m_hull[m_hull[e].prev ].prev ].t = t + 2 ;
365- }
365+
366366 // walk forward through the hull, adding more triangles and flipping recursively
367367 std::size_t q = m_hull[e].next ;
368368 while (
@@ -371,7 +371,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
371371 t = add_triangle (
372372 m_hull[q].i , i, m_hull[m_hull[q].next ].i , m_hull[m_hull[q].prev ].t , INVALID_INDEX, m_hull[q].t );
373373 m_hull[m_hull[q].prev ].t = legalize (t + 2 );
374- remove_node (q);
374+ m_hull_entry = remove_node (q);
375375 q = m_hull[q].next ;
376376 }
377377 if (walk_back) {
@@ -384,7 +384,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
384384 m_hull[m_hull[q].prev ].i , i, m_hull[q].i , INVALID_INDEX, m_hull[q].t , m_hull[m_hull[q].prev ].t );
385385 legalize (t + 2 );
386386 m_hull[m_hull[q].prev ].t = t;
387- remove_node (q);
387+ m_hull_entry = remove_node (q);
388388 q = m_hull[q].prev ;
389389 }
390390 }
@@ -403,6 +403,21 @@ std::size_t Delaunator::remove_node(std::size_t node) {
403403std::size_t Delaunator::legalize (std::size_t a) {
404404 std::size_t b = halfedges[a];
405405
406+ /* if the pair of triangles doesn't satisfy the Delaunay condition
407+ * (p1 is inside the circumcircle of [p0, pl, pr]), flip them,
408+ * then do the same check/flip recursively for the new pair of triangles
409+ *
410+ * pl pl
411+ * /||\ / \
412+ * al/ || \bl al/ \a
413+ * / || \ / \
414+ * / a||b \ flip /___ar___\
415+ * p0\ || /p1 => p0\---bl---/p1
416+ * \ || / \ /
417+ * ar\ || /br b\ /br
418+ * \||/ \ /
419+ * pr pr
420+ */
406421 std::size_t a0 = a - a % 3 ;
407422 std::size_t b0 = b - b % 3 ;
408423
@@ -416,12 +431,33 @@ std::size_t Delaunator::legalize(std::size_t a) {
416431 std::size_t p1 = triangles[bl];
417432
418433 const bool illegal = in_circle (
419- coords[2 * p0], coords[2 * p0 + 1 ], coords[2 * pr], coords[2 * pr + 1 ], coords[2 * pl], coords[2 * pl + 1 ], coords[2 * p1], coords[2 * p1 + 1 ]);
434+ coords[2 * p0],
435+ coords[2 * p0 + 1 ],
436+ coords[2 * pr],
437+ coords[2 * pr + 1 ],
438+ coords[2 * pl],
439+ coords[2 * pl + 1 ],
440+ coords[2 * p1],
441+ coords[2 * p1 + 1 ]);
420442
421443 if (illegal) {
422444 triangles[a] = p1;
423445 triangles[b] = p0;
424- link (a, halfedges[bl]);
446+
447+ auto hbl = halfedges[bl];
448+
449+ // edge swapped on the other side of the hull (rare); fix the halfedge reference
450+ if (hbl == INVALID_INDEX) {
451+ std::size_t e = m_hull_entry;
452+ do {
453+ if (m_hull[e].t == bl) {
454+ m_hull[e].t = a;
455+ break ;
456+ }
457+ e = m_hull[e].next ;
458+ } while (e != m_hull_entry);
459+ }
460+ link (a, hbl);
425461 link (b, halfedges[ar]);
426462 link (ar, bl);
427463
0 commit comments