1
1
2
2
#include " delaunator.hpp"
3
3
4
+ #include < iostream>
5
+
4
6
#include < algorithm>
5
7
#include < cmath>
8
+ #include < numeric>
6
9
#include < limits>
7
10
#include < stdexcept>
8
11
#include < tuple>
@@ -38,6 +41,25 @@ inline double dist(
38
41
return dx * dx + dy * dy;
39
42
}
40
43
44
+ inline double circumradius (const Point & p1, const Point & p2, const Point & p3)
45
+ {
46
+ Point d = Point::vector (p1, p2);
47
+ Point e = Point::vector (p1, p3);
48
+
49
+ const double bl = d.magnitude2 ();
50
+ const double cl = e.magnitude2 ();
51
+ const double det = Point::determinant (d, e);
52
+
53
+ Point radius ((e.y () * bl - d.y () * cl) * 0.5 / det,
54
+ (d.x () * cl - e.x () * bl) * 0.5 / det);
55
+
56
+ if ((bl > 0.0 || bl < 0.0 ) &&
57
+ (cl > 0.0 || cl < 0.0 ) &&
58
+ (det > 0.0 || det < 0.0 ))
59
+ return radius.magnitude2 ();
60
+ return (std::numeric_limits<double >::max)();
61
+ }
62
+
41
63
inline double circumradius (
42
64
const double ax,
43
65
const double ay,
@@ -64,16 +86,57 @@ inline double circumradius(
64
86
}
65
87
}
66
88
67
- inline bool orient (
68
- const double px,
69
- const double py,
70
- const double qx,
71
- const double qy,
72
- const double rx,
73
- const double ry) {
74
- return (qy - py) * (rx - qx) - (qx - px) * (ry - qy) < 0.0 ;
89
+ inline bool clockwise (const Point & p0, const Point & p1, const Point & p2)
90
+ {
91
+ Point v0 = Point::vector (p0, p1);
92
+ Point v1 = Point::vector (p0, p2);
93
+ double det = Point::determinant (v0, v1);
94
+ double dist = v0.magnitude2 () + v1.magnitude2 ();
95
+ double dist2 = Point::dist2 (v0, v1);
96
+ if (det == 0 )
97
+ {
98
+ return false ;
99
+ }
100
+ double reldet = std::abs (dist / det);
101
+ if (reldet > 1e14 )
102
+ return false ;
103
+ return det < 0 ;
104
+ }
105
+
106
+ inline bool clockwise (double px, double py, double qx, double qy,
107
+ double rx, double ry)
108
+ {
109
+ Point p0 (px, py);
110
+ Point p1 (qx, qy);
111
+ Point p2 (rx, ry);
112
+ return clockwise (p0, p1, p2);
113
+ }
114
+
115
+ inline bool counterclockwise (const Point & p0, const Point & p1, const Point & p2)
116
+ {
117
+ Point v0 = Point::vector (p0, p1);
118
+ Point v1 = Point::vector (p0, p2);
119
+ double det = Point::determinant (v0, v1);
120
+ double dist = v0.magnitude2 () + v1.magnitude2 ();
121
+ double dist2 = Point::dist2 (v0, v1);
122
+ if (det == 0 )
123
+ return false ;
124
+ double reldet = std::abs (dist / det);
125
+ if (reldet > 1e14 )
126
+ return false ;
127
+ return det > 0 ;
128
+ }
129
+
130
+ inline bool counterclockwise (double px, double py, double qx, double qy,
131
+ double rx, double ry)
132
+ {
133
+ Point p0 (px, py);
134
+ Point p1 (qx, qy);
135
+ Point p2 (rx, ry);
136
+ return counterclockwise (p0, p1, p2);
75
137
}
76
138
139
+
77
140
inline Point circumcenter (
78
141
const double ax,
79
142
const double ay,
@@ -88,6 +151,7 @@ inline Point circumcenter(
88
151
89
152
const double bl = dx * dx + dy * dy;
90
153
const double cl = ex * ex + ey * ey;
154
+ // ABELL - This is suspect for div-by-0.
91
155
const double d = dx * ey - dy * ex;
92
156
93
157
const double x = ax + (ey * bl - dy * cl) * 0.5 / d;
@@ -173,81 +237,63 @@ inline double pseudo_angle(const double dx, const double dy) {
173
237
return (dy > 0.0 ? 3.0 - p : 1.0 + p) / 4.0 ; // [0..1)
174
238
}
175
239
176
- struct DelaunatorPoint {
177
- std::size_t i;
178
- double x;
179
- double y;
180
- std::size_t t;
181
- std::size_t prev;
182
- std::size_t next;
183
- bool removed;
184
- };
185
240
186
241
Delaunator::Delaunator (std::vector<double > const & in_coords)
187
- : coords(in_coords),
188
- triangles(),
189
- halfedges(),
190
- hull_prev(),
191
- hull_next(),
192
- hull_tri(),
193
- hull_start(),
194
- m_hash(),
195
- m_hash_size(),
196
- m_edge_stack() {
242
+ : coords(in_coords), m_points(in_coords)
243
+ {
197
244
std::size_t n = coords.size () >> 1 ;
198
245
246
+ std::vector<std::size_t > ids (n);
247
+ std::iota (ids.begin (), ids.end (), 0 );
248
+
199
249
double max_x = std::numeric_limits<double >::lowest ();
200
250
double max_y = std::numeric_limits<double >::lowest ();
201
251
double min_x = (std::numeric_limits<double >::max)();
202
252
double min_y = (std::numeric_limits<double >::max)();
203
- std::vector<std::size_t > ids;
204
- ids.reserve (n);
205
-
206
- for (std::size_t i = 0 ; i < n; i++) {
207
- const double x = coords[2 * i];
208
- const double y = coords[2 * i + 1 ];
209
-
210
- if (x < min_x) min_x = x;
211
- if (y < min_y) min_y = y;
212
- if (x > max_x) max_x = x;
213
- if (y > max_y) max_y = y;
214
-
215
- ids.push_back (i);
253
+ for (const Point & p : m_points)
254
+ {
255
+ min_x = std::min (p.x (), min_x);
256
+ min_y = std::min (p.y (), min_y);
257
+ max_x = std::max (p.x (), max_x);
258
+ max_y = std::max (p.y (), max_y);
216
259
}
217
- const double cx = (min_x + max_x) / 2 ;
218
- const double cy = (min_y + max_y) / 2 ;
219
- double min_dist = (std::numeric_limits<double >::max)();
260
+ double width = max_x - min_x;
261
+ double height = max_x - min_y;
262
+ double span = width * width + height * height; // Everything is square dist.
263
+
264
+ Point center ((min_x + max_x) / 2 , (min_y + max_y) / 2 );
220
265
221
266
std::size_t i0 = INVALID_INDEX;
222
267
std::size_t i1 = INVALID_INDEX;
223
268
std::size_t i2 = INVALID_INDEX;
224
269
225
270
// pick a seed point close to the centroid
226
- for (std::size_t i = 0 ; i < n; i++) {
227
- const double d = dist (cx, cy, coords[2 * i], coords[2 * i + 1 ]);
271
+ double min_dist = (std::numeric_limits<double >::max)();
272
+ for (size_t i = 0 ; i < m_points.size (); ++i)
273
+ {
274
+ const Point & p = m_points[i];
275
+ const double d = Point::dist2 (center, p);
228
276
if (d < min_dist) {
229
277
i0 = i;
230
278
min_dist = d;
231
279
}
232
280
}
233
281
234
- const double i0x = coords[2 * i0];
235
- const double i0y = coords[2 * i0 + 1 ];
282
+ const Point & p0 = m_points[i0];
236
283
237
284
min_dist = (std::numeric_limits<double >::max)();
238
285
239
286
// find the point closest to the seed
240
287
for (std::size_t i = 0 ; i < n; i++) {
241
288
if (i == i0) continue ;
242
- const double d = dist (i0x, i0y, coords[ 2 * i], coords[ 2 * i + 1 ]);
289
+ const double d = Point::dist2 (p0, m_points[i ]);
243
290
if (d < min_dist && d > 0.0 ) {
244
291
i1 = i;
245
292
min_dist = d;
246
293
}
247
294
}
248
295
249
- double i1x = coords[2 * i1];
250
- double i1y = coords[2 * i1 + 1 ];
296
+ const Point & p1 = m_points[i1];
251
297
252
298
double min_radius = (std::numeric_limits<double >::max)();
253
299
@@ -256,9 +302,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
256
302
for (std::size_t i = 0 ; i < n; i++) {
257
303
if (i == i0 || i == i1) continue ;
258
304
259
- const double r = circumradius (
260
- i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1 ]);
261
-
305
+ const double r = circumradius (p0, p1, m_points[i]);
262
306
if (r < min_radius) {
263
307
i2 = i;
264
308
min_radius = r;
@@ -269,14 +313,17 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
269
313
throw std::runtime_error (" not triangulation" );
270
314
}
271
315
272
- double i2x = coords[2 * i2];
273
- double i2y = coords[2 * i2 + 1 ];
316
+ const Point & p2 = m_points[i2];
274
317
275
- if (orient (i0x, i0y, i1x, i1y, i2x, i2y)) {
318
+ if (counterclockwise (p0, p1, p2))
276
319
std::swap (i1, i2);
277
- std::swap (i1x, i2x);
278
- std::swap (i1y, i2y);
279
- }
320
+
321
+ double i0x = p0.x ();
322
+ double i0y = p0.y ();
323
+ double i1x = m_points[i1].x ();
324
+ double i1y = m_points[i1].y ();
325
+ double i2x = m_points[i2].x ();
326
+ double i2y = m_points[i2].y ();
280
327
281
328
m_center = circumcenter (i0x, i0y, i1x, i1y, i2x, i2y);
282
329
@@ -360,14 +407,20 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
360
407
size_t e = start;
361
408
size_t q;
362
409
363
- // ABELL - Make sure that start and e are linked.
364
-
365
- // Advance until we find a place in the hull where our current point
410
+ // Advance until we find a place in the hull where our current point
366
411
// can be added.
367
- while (q = hull_next[e],
368
- !orient (x, y, coords[2 * e], coords[2 * e + 1 ],
369
- coords[2 * q], coords[2 * q + 1 ]))
412
+ while (true )
370
413
{
414
+ q = hull_next[e];
415
+ if (Point::equal (m_points[i], m_points[e], span) ||
416
+ Point::equal (m_points[i], m_points[q], span))
417
+ {
418
+ e = INVALID_INDEX;
419
+ break ;
420
+ }
421
+ if (counterclockwise (x, y, coords[2 * e], coords[2 * e + 1 ],
422
+ coords[2 * q], coords[2 * q + 1 ]))
423
+ break ;
371
424
e = q;
372
425
if (e == start) {
373
426
e = INVALID_INDEX;
@@ -396,11 +449,12 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
396
449
// walk forward through the hull, adding more triangles and
397
450
// flipping recursively
398
451
std::size_t next = hull_next[e];
399
- while (
400
- q = hull_next[next],
401
- orient (x, y, coords[2 * next], coords[2 * next + 1 ],
402
- coords[2 * q], coords[2 * q + 1 ]))
452
+ while (true )
403
453
{
454
+ q = hull_next[next];
455
+ if (!counterclockwise (x, y, coords[2 * next], coords[2 * next + 1 ],
456
+ coords[2 * q], coords[2 * q + 1 ]))
457
+ break ;
404
458
t = add_triangle (next, i, q,
405
459
hull_tri[i], INVALID_INDEX, hull_tri[next]);
406
460
hull_tri[i] = legalize (t + 2 );
@@ -411,11 +465,12 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
411
465
412
466
// walk backward from the other side, adding more triangles and flipping
413
467
if (e == start) {
414
- while (
415
- q = hull_prev[e],
416
- orient (x, y, coords[2 * q], coords[2 * q + 1 ], coords[2 * e],
417
- coords[2 * e + 1 ]))
468
+ while (true )
418
469
{
470
+ q = hull_prev[e];
471
+ if (!counterclockwise (x, y, coords[2 * q], coords[2 * q + 1 ],
472
+ coords[2 * e], coords[2 * e + 1 ]))
473
+ break ;
419
474
t = add_triangle (q, i, e,
420
475
INVALID_INDEX, hull_tri[e], hull_tri[q]);
421
476
legalize (t + 2 );
@@ -438,12 +493,15 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
438
493
}
439
494
}
440
495
441
- double Delaunator::get_hull_area () {
496
+ double Delaunator::get_hull_area ()
497
+ {
442
498
std::vector<double > hull_area;
443
499
size_t e = hull_start;
500
+ size_t cnt = 1 ;
444
501
do {
445
502
hull_area.push_back ((coords[2 * e] - coords[2 * hull_prev[e]]) *
446
- (coords[2 * e + 1 ] + coords[2 * hull_prev[e] + 1 ]));
503
+ (coords[2 * e + 1 ] + coords[2 * hull_prev[e] + 1 ]));
504
+ cnt++;
447
505
e = hull_next[e];
448
506
} while (e != hull_start);
449
507
return sum (hull_area);
0 commit comments