Skip to content

Commit 0b0d9d4

Browse files
committed
#2 parity with js: mapbox/delaunator@dcfaf92
1 parent 5ba668d commit 0b0d9d4

File tree

3 files changed

+62
-18
lines changed

3 files changed

+62
-18
lines changed

generate-reference-triangles/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const delaunator = new Delaunator(coords);
2323
const end = Date.now();
2424

2525
console.log('points =', coords.length / 2);
26-
console.log('miliseconds =', end - start);
26+
console.log('milliseconds =', end - start);
2727
console.log('triangles =', delaunator.triangles.length);
2828

2929
if (outputFile) {

include/delaunator.hpp

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class Delaunator {
165165
private:
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) {
403403
std::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

Comments
 (0)