11
22#include " delaunator.hpp"
33
4+ #include < iostream>
5+
46#include < algorithm>
57#include < cmath>
8+ #include < numeric>
69#include < limits>
710#include < stdexcept>
811#include < tuple>
@@ -38,6 +41,25 @@ inline double dist(
3841 return dx * dx + dy * dy;
3942}
4043
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+
4163inline double circumradius (
4264 const double ax,
4365 const double ay,
@@ -64,16 +86,57 @@ inline double circumradius(
6486 }
6587}
6688
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);
75137}
76138
139+
77140inline Point circumcenter (
78141 const double ax,
79142 const double ay,
@@ -88,6 +151,7 @@ inline Point circumcenter(
88151
89152 const double bl = dx * dx + dy * dy;
90153 const double cl = ex * ex + ey * ey;
154+ // ABELL - This is suspect for div-by-0.
91155 const double d = dx * ey - dy * ex;
92156
93157 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) {
173237 return (dy > 0.0 ? 3.0 - p : 1.0 + p) / 4.0 ; // [0..1)
174238}
175239
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- };
185240
186241Delaunator::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+ {
197244 std::size_t n = coords.size () >> 1 ;
198245
246+ std::vector<std::size_t > ids (n);
247+ std::iota (ids.begin (), ids.end (), 0 );
248+
199249 double max_x = std::numeric_limits<double >::lowest ();
200250 double max_y = std::numeric_limits<double >::lowest ();
201251 double min_x = (std::numeric_limits<double >::max)();
202252 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);
216259 }
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 );
220265
221266 std::size_t i0 = INVALID_INDEX;
222267 std::size_t i1 = INVALID_INDEX;
223268 std::size_t i2 = INVALID_INDEX;
224269
225270 // 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);
228276 if (d < min_dist) {
229277 i0 = i;
230278 min_dist = d;
231279 }
232280 }
233281
234- const double i0x = coords[2 * i0];
235- const double i0y = coords[2 * i0 + 1 ];
282+ const Point& p0 = m_points[i0];
236283
237284 min_dist = (std::numeric_limits<double >::max)();
238285
239286 // find the point closest to the seed
240287 for (std::size_t i = 0 ; i < n; i++) {
241288 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 ]);
243290 if (d < min_dist && d > 0.0 ) {
244291 i1 = i;
245292 min_dist = d;
246293 }
247294 }
248295
249- double i1x = coords[2 * i1];
250- double i1y = coords[2 * i1 + 1 ];
296+ const Point& p1 = m_points[i1];
251297
252298 double min_radius = (std::numeric_limits<double >::max)();
253299
@@ -256,9 +302,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
256302 for (std::size_t i = 0 ; i < n; i++) {
257303 if (i == i0 || i == i1) continue ;
258304
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]);
262306 if (r < min_radius) {
263307 i2 = i;
264308 min_radius = r;
@@ -269,14 +313,17 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
269313 throw std::runtime_error (" not triangulation" );
270314 }
271315
272- double i2x = coords[2 * i2];
273- double i2y = coords[2 * i2 + 1 ];
316+ const Point& p2 = m_points[i2];
274317
275- if (orient (i0x, i0y, i1x, i1y, i2x, i2y)) {
318+ if (counterclockwise (p0, p1, p2))
276319 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 ();
280327
281328 m_center = circumcenter (i0x, i0y, i1x, i1y, i2x, i2y);
282329
@@ -360,14 +407,20 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
360407 size_t e = start;
361408 size_t q;
362409
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
366411 // 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 )
370413 {
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 ;
371424 e = q;
372425 if (e == start) {
373426 e = INVALID_INDEX;
@@ -396,11 +449,12 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
396449 // walk forward through the hull, adding more triangles and
397450 // flipping recursively
398451 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 )
403453 {
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 ;
404458 t = add_triangle (next, i, q,
405459 hull_tri[i], INVALID_INDEX, hull_tri[next]);
406460 hull_tri[i] = legalize (t + 2 );
@@ -411,11 +465,12 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
411465
412466 // walk backward from the other side, adding more triangles and flipping
413467 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 )
418469 {
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 ;
419474 t = add_triangle (q, i, e,
420475 INVALID_INDEX, hull_tri[e], hull_tri[q]);
421476 legalize (t + 2 );
@@ -438,12 +493,15 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
438493 }
439494}
440495
441- double Delaunator::get_hull_area () {
496+ double Delaunator::get_hull_area ()
497+ {
442498 std::vector<double > hull_area;
443499 size_t e = hull_start;
500+ size_t cnt = 1 ;
444501 do {
445502 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++;
447505 e = hull_next[e];
448506 } while (e != hull_start);
449507 return sum (hull_area);
0 commit comments