Skip to content

Commit ab3e8b6

Browse files
committed
1 parent ec99845 commit ab3e8b6

File tree

4 files changed

+99
-144
lines changed

4 files changed

+99
-144
lines changed

README.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ int main() {
4848

4949
```
5050
Run on (4 X 2300 MHz CPU s)
51-
2018-09-23 08:36:08
51+
2018-09-26 09:28:34
5252
------------------------------------------------------------
5353
Benchmark Time CPU Iterations
5454
------------------------------------------------------------
55-
BM_45K_geojson_nodes 22 ms 22 ms 33
56-
BM_uniform/2000 1 ms 1 ms 953
57-
BM_uniform/100000 61 ms 61 ms 9
58-
BM_uniform/200000 140 ms 140 ms 4
59-
BM_uniform/500000 409 ms 408 ms 2
60-
BM_uniform/1000000 998 ms 995 ms 1
55+
BM_45K_geojson_nodes 24 ms 24 ms 29
56+
BM_uniform/2000 1 ms 1 ms 887
57+
BM_uniform/100000 66 ms 66 ms 9
58+
BM_uniform/200000 158 ms 155 ms 4
59+
BM_uniform/500000 441 ms 439 ms 2
60+
BM_uniform/1000000 1062 ms 1058 ms 1
6161
```
6262

6363
Library is ~10% faster then JS version for 1M uniform points ([details](https://github.com/delfrrr/delaunator-cpp/pull/8#issuecomment-422690056))

generate-reference-triangles/package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

generate-reference-triangles/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
"private": true,
44
"main": "index.js",
55
"dependencies": {
6-
"delaunator": "2.0.3"
6+
"delaunator": "3.0.1"
77
}
88
}

include/delaunator.hpp

+88-133
Original file line numberDiff line numberDiff line change
@@ -180,25 +180,23 @@ class Delaunator {
180180
std::vector<double> const& coords;
181181
std::vector<std::size_t> triangles;
182182
std::vector<std::size_t> halfedges;
183+
std::vector<std::size_t> hull_prev;
184+
std::vector<std::size_t> hull_next;
185+
std::vector<std::size_t> hull_tri;
186+
std::size_t hull_start;
183187

184188
Delaunator(std::vector<double> const& in_coords);
185189

186190
double get_hull_area();
187191

188192
private:
189193
std::vector<std::size_t> m_hash;
190-
std::vector<DelaunatorPoint> m_hull;
191-
std::size_t m_hull_entry;
192194
double m_center_x;
193195
double m_center_y;
194196
std::size_t m_hash_size;
195197

196-
std::size_t remove_node(std::size_t node);
197198
std::size_t legalize(std::size_t a);
198-
std::size_t insert_node(std::size_t i);
199-
std::size_t insert_node(std::size_t i, std::size_t prev);
200199
std::size_t hash_key(double x, double y);
201-
void hash_edge(std::size_t e);
202200
std::size_t add_triangle(
203201
std::size_t i0,
204202
std::size_t i1,
@@ -213,9 +211,11 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
213211
: coords(in_coords),
214212
triangles(),
215213
halfedges(),
214+
hull_prev(),
215+
hull_next(),
216+
hull_tri(),
217+
hull_start(),
216218
m_hash(),
217-
m_hull(),
218-
m_hull_entry(),
219219
m_center_x(),
220220
m_center_y(),
221221
m_hash_size() {
@@ -309,27 +309,29 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
309309

310310
// initialize a hash table for storing edges of the advancing convex hull
311311
m_hash_size = static_cast<std::size_t>(std::llround(std::ceil(std::sqrt(n))));
312-
m_hash.reserve(m_hash_size);
313-
for (std::size_t i = 0; i < m_hash_size; i++) {
314-
m_hash.push_back(INVALID_INDEX);
315-
}
312+
m_hash.resize(m_hash_size);
313+
std::fill(m_hash.begin(), m_hash.end(), INVALID_INDEX);
314+
315+
// initialize arrays for tracking the edges of the advancing convex hull
316+
hull_prev.resize(n);
317+
hull_next.resize(n);
318+
hull_tri.resize(n);
319+
320+
hull_start = i0;
316321

317-
// initialize a circular doubly-linked list that will hold an advancing convex hull
318-
// doubly-linked list is stored as plain vector
319-
// vertices are linked via ineces of next/prev vertice
320-
m_hull.reserve(coords.size());
321-
std::size_t e = insert_node(i0);
322-
m_hull_entry = e;
323-
hash_edge(e);
324-
m_hull[e].t = 0;
322+
size_t hull_size = 3;
325323

326-
e = insert_node(i1, e);
327-
hash_edge(e);
328-
m_hull[e].t = 1;
324+
hull_next[i0] = hull_prev[i2] = i1;
325+
hull_next[i1] = hull_prev[i0] = i2;
326+
hull_next[i2] = hull_prev[i1] = i0;
329327

330-
e = insert_node(i2, e);
331-
hash_edge(e);
332-
m_hull[e].t = 2;
328+
hull_tri[i0] = 0;
329+
hull_tri[i1] = 1;
330+
hull_tri[i2] = 2;
331+
332+
m_hash[hash_key(i0x, i0y)] = i0;
333+
m_hash[hash_key(i1x, i1y)] = i1;
334+
m_hash[hash_key(i2x, i2y)] = i2;
333335

334336
std::size_t max_triangles = n < 3 ? 1 : 2 * n - 5;
335337
triangles.reserve(max_triangles * 3);
@@ -354,108 +356,89 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
354356
check_pts_equal(x, y, i2x, i2y)) continue;
355357

356358
// find a visible edge on the convex hull using edge hash
357-
const std::size_t start_key = hash_key(x, y);
358-
std::size_t key = start_key;
359-
std::size_t start = INVALID_INDEX;
360-
do {
361-
start = m_hash[key];
362-
key = (key + 1) % m_hash_size;
363-
} while (
364-
(start == INVALID_INDEX || m_hull[start].removed) &&
365-
(key != start_key));
366-
367-
start = m_hull[start].prev;
368-
e = start;
369-
while (!orient(
370-
x, y, //
371-
m_hull[e].x,
372-
m_hull[e].y, //
373-
m_hull[m_hull[e].next].x, //
374-
m_hull[m_hull[e].next].y) //
375-
) {
376-
e = m_hull[e].next;
359+
std::size_t start = 0;
360+
361+
size_t key = hash_key(x, y);
362+
for (size_t j = 0; j < m_hash_size; j++) {
363+
start = m_hash[(key + j) % m_hash_size];
364+
if (start != INVALID_INDEX && start != hull_next[start]) break;
365+
}
366+
367+
start = hull_prev[start];
368+
size_t e = start;
369+
size_t q;
377370

371+
while (q = hull_next[e], !orient(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1])) { //TODO: does it works in a same way as in JS
372+
e = q;
378373
if (e == start) {
379-
e = INVALID_INDEX; //TODO: will it work correct?
374+
e = INVALID_INDEX;
380375
break;
381376
}
382377
}
383378

384-
// likely a near-duplicate point; skip it
385-
if (e == INVALID_INDEX) continue;
386-
387-
const bool walk_back = e == start;
379+
if (e == INVALID_INDEX) continue; // likely a near-duplicate point; skip it
388380

389381
// add the first triangle from the point
390382
std::size_t t = add_triangle(
391-
m_hull[e].i,
383+
e,
392384
i,
393-
m_hull[m_hull[e].next].i,
385+
hull_next[e],
394386
INVALID_INDEX,
395387
INVALID_INDEX,
396-
m_hull[e].t);
388+
hull_tri[e]);
397389

398-
m_hull[e].t = t; // keep track of boundary triangles on the hull
399-
e = insert_node(i, e);
400-
401-
// recursively flip triangles from the point until they satisfy the Delaunay condition
402-
m_hull[e].t = legalize(t + 2);
390+
hull_tri[i] = legalize(t + 2);
391+
hull_tri[e] = t;
392+
hull_size++;
403393

404394
// walk forward through the hull, adding more triangles and flipping recursively
405-
std::size_t q = m_hull[e].next;
406-
while (orient(
407-
x, y, //
408-
m_hull[q].x,
409-
m_hull[q].y, //
410-
m_hull[m_hull[q].next].x,
411-
m_hull[m_hull[q].next].y //
412-
)) {
413-
t = add_triangle(
414-
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);
415-
m_hull[m_hull[q].prev].t = legalize(t + 2);
416-
m_hull_entry = remove_node(q);
417-
q = m_hull[q].next;
395+
std::size_t next = hull_next[e];
396+
while (
397+
q = hull_next[next],
398+
orient(x, y, coords[2 * next], coords[2 * next + 1], coords[2 * q], coords[2 * q + 1])) {
399+
t = add_triangle(next, i, q, hull_tri[i], INVALID_INDEX, hull_tri[next]);
400+
hull_tri[i] = legalize(t + 2);
401+
hull_next[next] = next; // mark as removed
402+
hull_size--;
403+
next = q;
418404
}
419-
if (walk_back) {
420-
// walk backward from the other side, adding more triangles and flipping
421-
q = m_hull[e].prev;
422-
while (orient(
423-
x, y, //
424-
m_hull[m_hull[q].prev].x,
425-
m_hull[m_hull[q].prev].y, //
426-
m_hull[q].x,
427-
m_hull[q].y //
428-
)) {
429-
t = add_triangle(
430-
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);
405+
406+
// walk backward from the other side, adding more triangles and flipping
407+
if (e == start) {
408+
while (
409+
q = hull_prev[e],
410+
orient(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1])) {
411+
t = add_triangle(q, i, e, INVALID_INDEX, hull_tri[e], hull_tri[q]);
431412
legalize(t + 2);
432-
m_hull[m_hull[q].prev].t = t;
433-
m_hull_entry = remove_node(q);
434-
q = m_hull[q].prev;
413+
hull_tri[q] = t;
414+
hull_next[e] = e; // mark as removed
415+
hull_size--;
416+
e = q;
435417
}
436418
}
437-
hash_edge(e);
438-
hash_edge(m_hull[e].prev);
419+
420+
// update the hull indices
421+
hull_prev[i] = e;
422+
hull_start = e;
423+
hull_prev[next] = i;
424+
hull_next[e] = i;
425+
hull_next[i] = next;
426+
427+
m_hash[hash_key(x, y)] = i;
428+
m_hash[hash_key(coords[2 * e], coords[2 * e + 1])] = e;
439429
}
440430
}
441431

442432
double Delaunator::get_hull_area() {
443433
std::vector<double> hull_area;
444-
size_t e = m_hull_entry;
434+
size_t e = hull_start;
445435
do {
446-
hull_area.push_back((m_hull[e].x - m_hull[m_hull[e].prev].x) * (m_hull[e].y + m_hull[m_hull[e].prev].y));
447-
e = m_hull[e].next;
448-
} while (e != m_hull_entry);
436+
hull_area.push_back((coords[2 * e] - coords[2 * hull_prev[e]]) * (coords[2 * e + 1] + coords[2 * hull_prev[e] + 1]));
437+
e = hull_next[e];
438+
} while (e != hull_start);
449439
return sum(hull_area);
450440
}
451441

452-
std::size_t Delaunator::remove_node(std::size_t node) {
453-
m_hull[m_hull[node].prev].next = m_hull[node].next;
454-
m_hull[m_hull[node].next].prev = m_hull[node].prev;
455-
m_hull[node].removed = true;
456-
return m_hull[node].prev;
457-
}
458-
459442
std::size_t Delaunator::legalize(std::size_t a) {
460443
const std::size_t b = halfedges[a];
461444

@@ -508,14 +491,14 @@ std::size_t Delaunator::legalize(std::size_t a) {
508491

509492
// edge swapped on the other side of the hull (rare); fix the halfedge reference
510493
if (hbl == INVALID_INDEX) {
511-
std::size_t e = m_hull_entry;
494+
std::size_t e = hull_start;
512495
do {
513-
if (m_hull[e].t == bl) {
514-
m_hull[e].t = a;
496+
if (hull_tri[e] == bl) {
497+
hull_tri[e] = a;
515498
break;
516499
}
517-
e = m_hull[e].next;
518-
} while (e != m_hull_entry);
500+
e = hull_next[e];
501+
} while (e != hull_start);
519502
}
520503
link(a, hbl);
521504
link(b, halfedges[ar]);
@@ -529,30 +512,6 @@ std::size_t Delaunator::legalize(std::size_t a) {
529512
return ar;
530513
}
531514

532-
std::size_t Delaunator::insert_node(std::size_t i) {
533-
std::size_t node = m_hull.size();
534-
DelaunatorPoint p = {
535-
i,
536-
coords[2 * i],
537-
coords[2 * i + 1],
538-
0,
539-
node,
540-
node,
541-
false
542-
};
543-
m_hull.push_back(p);
544-
return node;
545-
}
546-
547-
std::size_t Delaunator::insert_node(std::size_t i, std::size_t prev) {
548-
std::size_t node = insert_node(i);
549-
m_hull[node].next = m_hull[prev].next;
550-
m_hull[node].prev = prev;
551-
m_hull[m_hull[node].next].prev = node;
552-
m_hull[prev].next = node;
553-
return node;
554-
}
555-
556515
std::size_t Delaunator::hash_key(double x, double y) {
557516
const double dx = x - m_center_x;
558517
const double dy = y - m_center_y;
@@ -561,10 +520,6 @@ std::size_t Delaunator::hash_key(double x, double y) {
561520
m_hash_size;
562521
}
563522

564-
void Delaunator::hash_edge(std::size_t e) {
565-
m_hash[hash_key(m_hull[e].x, m_hull[e].y)] = e;
566-
}
567-
568523
std::size_t Delaunator::add_triangle(
569524
std::size_t i0,
570525
std::size_t i1,

0 commit comments

Comments
 (0)