CDT  1.4.5
C++ library for constrained Delaunay triangulation
Loading...
Searching...
No Matches
Triangulation.hpp
Go to the documentation of this file.
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
9#ifndef CDT_pDqrlveWIOrIWeUCkPqX
10#define CDT_pDqrlveWIOrIWeUCkPqX
11
12#include "Triangulation.h"
13#include "portable_nth_element.hpp"
14
15#include <algorithm>
16#include <cassert>
17#include <cmath>
18#include <deque>
19#include <stdexcept>
20
21CDT_ENSURE_PRECISE_MATH_FOR_CONSTRUCTIONS
22
23namespace CDT
24{
25
26typedef std::deque<TriInd> TriDeque;
27
28namespace detail
29{
30
31namespace defaults
32{
33
34const std::size_t nTargetVerts = 0;
36const VertexInsertionOrder::Enum vertexInsertionOrder =
38const IntersectingConstraintEdges::Enum intersectingEdgesStrategy =
40const float minDistToConstraintEdge(0);
41
42} // namespace defaults
43
44} // namespace detail
45
46template <typename T, typename TNearPointLocator>
48 : m_nTargetVerts(detail::defaults::nTargetVerts)
49 , m_superGeomType(detail::defaults::superGeomType)
50 , m_vertexInsertionOrder(detail::defaults::vertexInsertionOrder)
51 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
52 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
53#ifdef CDT_ENABLE_CALLBACK_HANDLER
54 , m_callbackHandler(NULL)
55#endif
56{}
57
58template <typename T, typename TNearPointLocator>
60 const VertexInsertionOrder::Enum vertexInsertionOrder)
61 : m_nTargetVerts(detail::defaults::nTargetVerts)
62 , m_superGeomType(detail::defaults::superGeomType)
63 , m_vertexInsertionOrder(vertexInsertionOrder)
64 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
65 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
66#ifdef CDT_ENABLE_CALLBACK_HANDLER
67 , m_callbackHandler(NULL)
68#endif
69{}
70
71template <typename T, typename TNearPointLocator>
73 const VertexInsertionOrder::Enum vertexInsertionOrder,
74 const IntersectingConstraintEdges::Enum intersectingEdgesStrategy,
75 const T minDistToConstraintEdge)
76 : m_nTargetVerts(detail::defaults::nTargetVerts)
77 , m_superGeomType(detail::defaults::superGeomType)
78 , m_vertexInsertionOrder(vertexInsertionOrder)
79 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
80 , m_minDistToConstraintEdge(minDistToConstraintEdge)
81#ifdef CDT_ENABLE_CALLBACK_HANDLER
82 , m_callbackHandler(NULL)
83#endif
84{}
85
86template <typename T, typename TNearPointLocator>
88 const VertexInsertionOrder::Enum vertexInsertionOrder,
89 const TNearPointLocator& nearPtLocator,
90 const IntersectingConstraintEdges::Enum intersectingEdgesStrategy,
91 const T minDistToConstraintEdge)
92 : m_nearPtLocator(nearPtLocator)
93 , m_nTargetVerts(detail::defaults::nTargetVerts)
94 , m_superGeomType(detail::defaults::superGeomType)
95 , m_vertexInsertionOrder(vertexInsertionOrder)
96 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
97 , m_minDistToConstraintEdge(minDistToConstraintEdge)
98#ifdef CDT_ENABLE_CALLBACK_HANDLER
99 , m_callbackHandler(NULL)
100#endif
101{}
102
103template <typename T, typename TNearPointLocator>
105{
106 if(m_superGeomType != SuperGeometryType::SuperTriangle)
107 return;
108 // find triangles adjacent to super-triangle's vertices
109 TriIndUSet toErase;
110 for(TriInd iT(0); iT < TriInd(triangles.size()); ++iT)
111 {
112 if(touchesSuperTriangle(triangles[iT]))
113 toErase.insert(iT);
114 }
115 finalizeTriangulation(toErase);
116}
117
118template <typename T, typename TNearPointLocator>
120{
121 assert(m_vertTris[0] != noNeighbor);
122 const std::stack<TriInd> seed(std::deque<TriInd>(1, m_vertTris[0]));
123 const TriIndUSet toErase = growToBoundary(seed);
124 finalizeTriangulation(toErase);
125}
126
127template <typename T, typename TNearPointLocator>
129{
130 const std::vector<LayerDepth> triDepths = calculateTriangleDepths();
131 TriIndUSet toErase;
132 toErase.reserve(triangles.size());
133 for(std::size_t iT = 0; iT != triangles.size(); ++iT)
134 {
135 if(triDepths[iT] % 2 == 0)
136 toErase.insert(static_cast<TriInd>(iT));
137 }
138 finalizeTriangulation(toErase);
139}
140
143{
144 return Edge(VertInd(e.v1() - 3), VertInd(e.v2() - 3));
145}
146
147template <typename T, typename TNearPointLocator>
149 const TriIndUSet& removedTriangles)
150{
151 if(removedTriangles.empty())
152 return;
153 // remove triangles and calculate triangle index mapping
154 TriIndUMap triIndMap;
155 for(TriInd iT(0), iTnew(0); iT < TriInd(triangles.size()); ++iT)
156 {
157 if(removedTriangles.count(iT))
158 continue;
159 triIndMap[iT] = iTnew;
160 triangles[iTnew] = triangles[iT];
161 iTnew++;
162 }
163 triangles.erase(triangles.end() - removedTriangles.size(), triangles.end());
164 // adjust triangles' neighbors
165 for(TriInd iT(0); iT < triangles.size(); ++iT)
166 {
167 Triangle& t = triangles[iT];
168 // update neighbors to account for removed triangles
169 NeighborsArr3& nn = t.neighbors;
170 for(NeighborsArr3::iterator n = nn.begin(); n != nn.end(); ++n)
171 {
172 if(removedTriangles.count(*n))
173 {
174 *n = noNeighbor;
175 }
176 else if(*n != noNeighbor)
177 {
178 *n = triIndMap[*n];
179 }
180 }
181 }
182}
183
184template <typename T, typename TNearPointLocator>
189
190template <typename T, typename TNearPointLocator>
192{
193 return m_vertTris;
194}
195
196template <typename T, typename TNearPointLocator>
197void Triangulation<T, TNearPointLocator>::finalizeTriangulation(
198 const TriIndUSet& removedTriangles)
199{
200 m_vertTris = TriIndVec();
201 // remove super-triangle
202 if(m_superGeomType == SuperGeometryType::SuperTriangle)
203 {
204 vertices.erase(
205 vertices.begin(), vertices.begin() + nSuperTriangleVertices);
206 // Edge re-mapping
207 { // fixed edges
208 EdgeUSet updatedFixedEdges;
209 typedef CDT::EdgeUSet::const_iterator It;
210 for(It e = fixedEdges.begin(); e != fixedEdges.end(); ++e)
211 {
212 updatedFixedEdges.insert(RemapNoSuperTriangle(*e));
213 }
214 fixedEdges = updatedFixedEdges;
215 }
216 { // overlap count
217 unordered_map<Edge, BoundaryOverlapCount> updatedOverlapCount;
218 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator
219 It;
220 for(It it = overlapCount.begin(); it != overlapCount.end(); ++it)
221 {
222 updatedOverlapCount.insert(
223 std::make_pair(
224 RemapNoSuperTriangle(it->first), it->second));
225 }
226 overlapCount = updatedOverlapCount;
227 }
228 { // split edges mapping
229 unordered_map<Edge, EdgeVec> updatedPieceToOriginals;
230 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
231 for(It it = pieceToOriginals.begin(); it != pieceToOriginals.end();
232 ++it)
233 {
234 EdgeVec ee = it->second;
235 for(EdgeVec::iterator eeIt = ee.begin(); eeIt != ee.end();
236 ++eeIt)
237 {
238 *eeIt = RemapNoSuperTriangle(*eeIt);
239 }
240 updatedPieceToOriginals.insert(
241 std::make_pair(RemapNoSuperTriangle(it->first), ee));
242 }
243 pieceToOriginals = updatedPieceToOriginals;
244 }
245 }
246 // remove other triangles
247 removeTriangles(removedTriangles);
248 // adjust triangle vertices: account for removed super-triangle
249 if(m_superGeomType == SuperGeometryType::SuperTriangle)
250 {
251 for(TriangleVec::iterator t = triangles.begin(); t != triangles.end();
252 ++t)
253 {
254 VerticesArr3& vv = t->vertices;
255 for(VerticesArr3::iterator v = vv.begin(); v != vv.end(); ++v)
256 {
257 *v -= nSuperTriangleVertices;
258 }
259 }
260 }
261}
262
263template <typename T, typename TNearPointLocator>
265{
266 m_nearPtLocator.initialize(vertices);
267 m_nTargetVerts = verticesCount();
268 m_superGeomType = SuperGeometryType::Custom;
269}
270
271template <typename T, typename TNearPointLocator>
272TriIndUSet Triangulation<T, TNearPointLocator>::growToBoundary(
273 std::stack<TriInd> seeds) const
274{
275 TriIndUSet traversed;
276 while(!seeds.empty())
277 {
278 const TriInd iT = seeds.top();
279 seeds.pop();
280 traversed.insert(iT);
281 const Triangle& t = triangles[iT];
282 for(Index i(0); i < Index(3); ++i)
283 {
284 const Edge opEdge(t.vertices[ccw(i)], t.vertices[cw(i)]);
285 if(fixedEdges.count(opEdge))
286 continue;
287 const TriInd iN = t.neighbors[opoNbr(i)];
288 if(iN != noNeighbor && traversed.count(iN) == 0)
289 seeds.push(iN);
290 }
291 }
292 return traversed;
293}
294
295template <typename T, typename TNearPointLocator>
296TriInd Triangulation<T, TNearPointLocator>::addTriangle(const Triangle& t)
297{
298 const TriInd iT = trianglesCount();
299 triangles.push_back(t);
300 return iT;
301}
302
303template <typename T, typename TNearPointLocator>
304TriInd Triangulation<T, TNearPointLocator>::addTriangle()
305{
306 return addTriangle(Triangle());
307}
308
309template <typename T, typename TNearPointLocator>
310VertInd Triangulation<T, TNearPointLocator>::verticesCount() const
311{
312 return static_cast<VertInd>(vertices.size());
313}
314
315template <typename T, typename TNearPointLocator>
316TriInd Triangulation<T, TNearPointLocator>::trianglesCount() const
317{
318 return static_cast<TriInd>(triangles.size());
319}
320
321template <typename T, typename TNearPointLocator>
323 const std::vector<Edge>& edges)
324{
325 insertEdges(edges.begin(), edges.end(), edge_get_v1, edge_get_v2);
326}
327
328template <typename T, typename TNearPointLocator>
330 const std::vector<Edge>& edges)
331{
332 conformToEdges(edges.begin(), edges.end(), edge_get_v1, edge_get_v2);
333}
334
335template <typename T, typename TNearPointLocator>
336void Triangulation<T, TNearPointLocator>::fixEdge(const Edge& edge)
337{
338 if(!fixedEdges.insert(edge).second)
339 {
340 ++overlapCount[edge]; // if edge is already fixed increment the counter
341 }
342}
343
344namespace detail
345{
346
347// add element to 'to' if not already in 'to'
348template <typename T, typename Allocator1>
349void insert_unique(std::vector<T, Allocator1>& to, const T& elem)
350{
351 if(std::find(to.begin(), to.end(), elem) == to.end())
352 {
353 to.push_back(elem);
354 }
355}
356
357// add elements of 'from' that are not present in 'to' to 'to'
358template <typename T, typename Allocator1, typename Allocator2>
359void insert_unique(
360 std::vector<T, Allocator1>& to,
361 const std::vector<T, Allocator2>& from)
362{
363 typedef typename std::vector<T, Allocator2>::const_iterator Cit;
364 to.reserve(to.size() + from.size());
365 for(Cit cit = from.begin(); cit != from.end(); ++cit)
366 {
367 insert_unique(to, *cit);
368 }
369}
370
371} // namespace detail
372
373template <typename T, typename TNearPointLocator>
374void Triangulation<T, TNearPointLocator>::splitFixedEdge(
375 const Edge& edge,
376 const VertInd iSplitVert)
377{
378 // split constraint (fixed) edge that already exists in triangulation
379 const Edge half1(edge.v1(), iSplitVert);
380 const Edge half2(iSplitVert, edge.v2());
381 // remove the edge that and add its halves
382 fixedEdges.erase(edge);
383 fixEdge(half1);
384 fixEdge(half2);
385 // maintain overlaps
386 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
387 const It overlapIt = overlapCount.find(edge);
388 if(overlapIt != overlapCount.end())
389 {
390 overlapCount[half1] += overlapIt->second;
391 overlapCount[half2] += overlapIt->second;
392 overlapCount.erase(overlapIt);
393 }
394 // maintain piece-to-original mapping
395 EdgeVec newOriginals(1, edge);
396 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
397 pieceToOriginals.find(edge);
398 if(originalsIt != pieceToOriginals.end())
399 { // edge being split was split before: pass-through originals
400 newOriginals = originalsIt->second;
401 pieceToOriginals.erase(originalsIt);
402 }
403 detail::insert_unique(pieceToOriginals[half1], newOriginals);
404 detail::insert_unique(pieceToOriginals[half2], newOriginals);
405}
406
407template <typename T, typename TNearPointLocator>
408VertInd Triangulation<T, TNearPointLocator>::addSplitEdgeVertex(
409 const V2d<T>& splitVert,
410 const TriInd iT,
411 const TriInd iTopo)
412{
413 // add a new point on the edge that splits an edge in two
414 const VertInd iSplitVert = verticesCount();
415 addNewVertex(splitVert, noNeighbor);
416
417#ifdef CDT_ENABLE_CALLBACK_HANDLER
418 if(m_callbackHandler)
419 {
420 m_callbackHandler->onAddVertexStart(
422 }
423#endif
424
425 std::stack<TriInd> triStack = insertVertexOnEdge(iSplitVert, iT, iTopo);
426 tryAddVertexToLocator(iSplitVert);
427 ensureDelaunayByEdgeFlips(iSplitVert, triStack);
428 return iSplitVert;
429}
430
431template <typename T, typename TNearPointLocator>
432VertInd Triangulation<T, TNearPointLocator>::splitFixedEdgeAt(
433 const Edge& edge,
434 const V2d<T>& splitVert,
435 const TriInd iT,
436 const TriInd iTopo)
437{
438 const VertInd iSplitVert = addSplitEdgeVertex(splitVert, iT, iTopo);
439 splitFixedEdge(edge, iSplitVert);
440 return iSplitVert;
441}
442
443template <typename T, typename TNearPointLocator>
444bool Triangulation<T, TNearPointLocator>::isEdgeSplitVertexValid(
445 const V2d<T>& splitVert,
446 const TriInd iT,
447 const TriInd iTopo,
448 const VertInd iVL,
449 const VertInd iVR) const
450{
451 // Orient the split edge as it appears (counter-clockwise) in iT. Locating
452 // the (floating-point-rounded) split vertex against it both tells whether
453 // the split is safe and which of the two triangles sharing the edge must
454 // contain the vertex: 'Left' is iT's interior side, 'Right' is iTopo's.
455 const Triangle& tL = triangles[iT];
456 const Index sL = edgeNeighborInd(tL.vertices, iVL, iVR);
458 splitVert, vertices[tL.vertices[sL]], vertices[tL.vertices[ccw(sL)]]);
459 if(side == PtLineLocation::OnLine)
460 {
461 return splitVert != vertices[iVL] && splitVert != vertices[iVR];
462 }
463 const Triangle& t = side == PtLineLocation::Left ? tL : triangles[iTopo];
464
465 // The split vertex must not fall outside that triangle. Its relation to the
466 // split edge is already established by 'side', so only the two edges
467 // meeting at the apex (opposite the split edge) are tested. A point to the
468 // right of a counter-clockwise triangle's edge lies outside it.
469 const Index s = edgeNeighborInd(t.vertices, iVL, iVR);
470 const V2d<T>& from = vertices[t.vertices[s]]; // split edge tail (CCW)
471 const V2d<T>& to = vertices[t.vertices[ccw(s)]]; // split edge head (CCW)
472 const V2d<T>& apex = vertices[t.vertices[cw(s)]]; // opposite the split edge
473 return locatePointLine(splitVert, to, apex) != PtLineLocation::Right &&
474 locatePointLine(splitVert, apex, from) != PtLineLocation::Right;
475}
476
477template <typename T, typename TNearPointLocator>
478Edge Triangulation<T, TNearPointLocator>::originalInputEdge(const Edge& e) const
479{
480 const Edge orig =
481 pieceToOriginals.count(e) ? pieceToOriginals.at(e).front() : e;
482 return Edge(
483 VertInd(orig.v1() - m_nTargetVerts),
484 VertInd(orig.v2() - m_nTargetVerts));
485}
486
487template <typename T, typename TNearPointLocator>
488const Triangle&
489Triangulation<T, TNearPointLocator>::triangleAt(const TriInd iT) const
490{
491 if(iT >= triangles.size())
492 handleException(Error(
493 iT == noNeighbor
494 ? "Attempted reading no-neighbor sentinel value triangle"
495 : "Triangle index " + CDT::to_string(iT) + " out of range " +
496 CDT::to_string(triangles.size()),
497 CDT_SOURCE_LOCATION));
498 return triangles[iT];
499}
500
501template <typename T, typename TNearPointLocator>
502void Triangulation<T, TNearPointLocator>::fixEdge(
503 const Edge& edge,
504 const Edge& originalEdge)
505{
506 fixEdge(edge);
507 if(edge != originalEdge)
508 detail::insert_unique(pieceToOriginals[edge], originalEdge);
509}
510
511namespace detail
512{
513
514template <typename T>
515T lerp(const T& a, const T& b, const T t)
516{
517 return (T(1) - t) * a + t * b;
518}
519
520// Precondition: ab and cd intersect normally
521template <typename T>
522V2d<T> intersectionPosition(
523 const V2d<T>& a,
524 const V2d<T>& b,
525 const V2d<T>& c,
526 const V2d<T>& d)
527{
528 using namespace predicates::adaptive;
529
530 // note: for better accuracy we interpolate x and y separately
531 // on a segment with the shortest x/y-projection correspondingly
532 const T a_cd = orient2d(c.x, c.y, d.x, d.y, a.x, a.y);
533 const T b_cd = orient2d(c.x, c.y, d.x, d.y, b.x, b.y);
534 const T t_ab = a_cd / (a_cd - b_cd);
535
536 const T c_ab = orient2d(a.x, a.y, b.x, b.y, c.x, c.y);
537 const T d_ab = orient2d(a.x, a.y, b.x, b.y, d.x, d.y);
538 const T t_cd = c_ab / (c_ab - d_ab);
539
540 return V2d<T>(
541 std::fabs(a.x - b.x) < std::fabs(c.x - d.x) ? lerp(a.x, b.x, t_ab)
542 : lerp(c.x, d.x, t_cd),
543 std::fabs(a.y - b.y) < std::fabs(c.y - d.y) ? lerp(a.y, b.y, t_ab)
544 : lerp(c.y, d.y, t_cd));
545}
546
547} // namespace detail
548
549template <typename T, typename TNearPointLocator>
550void Triangulation<T, TNearPointLocator>::insertEdgeIteration(
551 const Edge edge,
552 const Edge originalEdge,
553 EdgeVec& remaining,
554 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
555{
556 const VertInd iA = edge.v1();
557 VertInd iB = edge.v2();
558 if(iA == iB) // edge connects a vertex to itself
559 return;
560
561 if(hasEdge(iA, iB))
562 {
563 fixEdge(edge, originalEdge);
564 return;
565 }
566
567 const V2d<T>& a = vertices[iA];
568 const V2d<T>& b = vertices[iB];
569 const T distanceTolerance =
570 m_minDistToConstraintEdge == T(0)
571 ? T(0)
572 : m_minDistToConstraintEdge * distance(a, b);
573
574 TriInd iT;
575 // Note: 'L' is left and 'R' is right of the inserted constraint edge
576 VertInd iVL, iVR;
577 tie(iT, iVL, iVR) = intersectedTriangle(iA, a, b, distanceTolerance);
578 // if one of the triangle vertices is on the edge, move edge start
579 if(iT == noNeighbor)
580 {
581 const Edge edgePart(iA, iVL);
582 fixEdge(edgePart, originalEdge);
583 remaining.push_back(Edge(iVL, iB));
584 return;
585 }
586 Triangle t = triangles[iT];
587 std::vector<TriInd> intersected(1, iT);
588 std::vector<VertInd> polyL, polyR;
589 polyL.reserve(2);
590 polyL.push_back(iA);
591 polyL.push_back(iVL);
592 polyR.reserve(2);
593 polyR.push_back(iA);
594 polyR.push_back(iVR);
595 unordered_map<Edge, TriInd> outerTris;
596 outerTris[Edge(iA, iVL)] = edgeNeighbor(t, iA, iVL);
597 outerTris[Edge(iA, iVR)] = edgeNeighbor(t, iA, iVR);
598 VertInd iV = iA;
599
600 while(!t.containsVertex(iB))
601 {
602 const TriInd iTopo = opposedTriangle(t, iV);
603 const Triangle& tOpo = triangleAt(iTopo);
604 const VertInd iVopo = opposedVertex(tOpo, iT);
605
606 switch(m_intersectingEdgesStrategy)
607 {
609 if(fixedEdges.count(Edge(iVL, iVR)))
610 handleException(IntersectingConstraintsError(
611 originalInputEdge(originalEdge),
612 originalInputEdge(Edge(iVL, iVR)),
613 CDT_SOURCE_LOCATION));
614 break;
616 {
617 if(!fixedEdges.count(Edge(iVL, iVR)))
618 break;
619 // split edge at the intersection of two constraint edges
620 const V2d<T> newV = detail::intersectionPosition(
621 vertices[iA], vertices[iB], vertices[iVL], vertices[iVR]);
622 if(!isEdgeSplitVertexValid(newV, iT, iTopo, iVL, iVR))
623 handleException(InvalidEdgeSplitVertex(
624 originalInputEdge(originalEdge),
625 originalInputEdge(Edge(iVL, iVR)),
626 CDT_SOURCE_LOCATION));
627 const VertInd iNewVert =
628 splitFixedEdgeAt(Edge(iVL, iVR), newV, iT, iTopo);
629 // TODO: is it's possible to re-use pseudo-polygons
630 // for inserting [iA, iNewVert] edge half?
631 remaining.push_back(Edge(iA, iNewVert));
632 remaining.push_back(Edge(iNewVert, iB));
633 return;
634 }
636 assert(!fixedEdges.count(Edge(iVL, iVR)));
637 break;
638 }
639
640 const PtLineLocation::Enum loc =
641 locatePointLine(vertices[iVopo], a, b, distanceTolerance);
642 if(loc == PtLineLocation::Left)
643 {
644 const Edge e(polyL.back(), iVopo);
645 const TriInd outer = edgeNeighbor(tOpo, e.v1(), e.v2());
646 if(!outerTris.insert(std::make_pair(e, outer)).second)
647 outerTris.at(e) = noNeighbor; // hanging edge detected
648 polyL.push_back(iVopo);
649 iV = iVL;
650 iVL = iVopo;
651 }
652 else if(loc == PtLineLocation::Right)
653 {
654 const Edge e(polyR.back(), iVopo);
655 const TriInd outer = edgeNeighbor(tOpo, e.v1(), e.v2());
656 if(!outerTris.insert(std::make_pair(e, outer)).second)
657 outerTris.at(e) = noNeighbor; // hanging edge detected
658 polyR.push_back(iVopo);
659 iV = iVR;
660 iVR = iVopo;
661 }
662 else // encountered point on the edge
663 iB = iVopo;
664
665 intersected.push_back(iTopo);
666 iT = iTopo;
667 t = triangles[iT];
668 }
669 outerTris[Edge(polyL.back(), iB)] = edgeNeighbor(t, polyL.back(), iB);
670 outerTris[Edge(polyR.back(), iB)] = edgeNeighbor(t, polyR.back(), iB);
671 polyL.push_back(iB);
672 polyR.push_back(iB);
673
674 assert(!intersected.empty());
675 // make sure start/end vertices have a valid adjacent triangle
676 // that is not intersected by an edge
677 if(m_vertTris[iA] == intersected.front())
678 pivotVertexTriangleCW(iA);
679 if(m_vertTris[iB] == intersected.back())
680 pivotVertexTriangleCW(iB);
681
682 {
683#ifdef CDT_ENABLE_CALLBACK_HANDLER
684 if(m_callbackHandler)
685 {
686 m_callbackHandler->onReTriangulatePolygon(intersected);
687 }
688#endif
689
690 // Triangulate pseudo-polygons on both sides
691 std::reverse(polyR.begin(), polyR.end());
692
693 // note: intersected triangles are re-used for new triangles
694 // every triangulation of an n-gon has n − 2 triangles
695 // even if outer polygon has hanging edges it holds
696 assert(intersected.size() >= 2);
697 const TriInd iTL = intersected.back();
698 intersected.pop_back();
699 const TriInd iTR = intersected.back();
700 intersected.pop_back();
701
702 triangulatePseudoPolygon(
703 polyL, outerTris, iTL, iTR, intersected, tppIterations);
704 triangulatePseudoPolygon(
705 polyR, outerTris, iTR, iTL, intersected, tppIterations);
706 assert(intersected.empty());
707 }
708
709 if(iB != edge.v2()) // encountered point on the edge
710 {
711 // fix edge part
712 const Edge edgePart(iA, iB);
713 fixEdge(edgePart, originalEdge);
714 remaining.push_back(Edge(iB, edge.v2()));
715 return;
716 }
717 else
718 {
719 fixEdge(edge, originalEdge);
720 }
721}
722
723template <typename T, typename TNearPointLocator>
724void Triangulation<T, TNearPointLocator>::insertEdge(
725 Edge edge,
726 const Edge originalEdge,
727 EdgeVec& remaining,
728 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
729{
730#ifdef CDT_ENABLE_CALLBACK_HANDLER
731 if(m_callbackHandler)
732 {
733 m_callbackHandler->onAddEdgeStart(edge);
734 }
735#endif
736
737 // use iteration over recursion to avoid stack overflows
738 remaining.clear();
739 remaining.push_back(edge);
740 while(!remaining.empty())
741 {
742 edge = remaining.back();
743 remaining.pop_back();
744 insertEdgeIteration(edge, originalEdge, remaining, tppIterations);
745 }
746}
747
748template <typename T, typename TNearPointLocator>
749void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
750 Edge edge,
751 const EdgeVec& originals,
752 BoundaryOverlapCount overlaps,
753 std::vector<ConformToEdgeTask>& remaining)
754{
755 const VertInd iA = edge.v1();
756 VertInd iB = edge.v2();
757 if(iA == iB) // edge connects a vertex to itself
758 return;
759
760 if(hasEdge(iA, iB))
761 {
762 fixEdge(edge);
763 if(overlaps > 0)
764 overlapCount[edge] = overlaps;
765 // avoid marking edge as a part of itself
766 if(!originals.empty() && edge != originals.front())
767 {
768 detail::insert_unique(pieceToOriginals[edge], originals);
769 }
770 return;
771 }
772
773 const V2d<T>& a = vertices[iA];
774 const V2d<T>& b = vertices[iB];
775 const T distanceTolerance =
776 m_minDistToConstraintEdge == T(0)
777 ? T(0)
778 : m_minDistToConstraintEdge * distance(a, b);
779 TriInd iT;
780 VertInd iVleft, iVright;
781 tie(iT, iVleft, iVright) = intersectedTriangle(iA, a, b, distanceTolerance);
782 // if one of the triangle vertices is on the edge, move edge start
783 if(iT == noNeighbor)
784 {
785 const Edge edgePart(iA, iVleft);
786 fixEdge(edgePart);
787 if(overlaps > 0)
788 overlapCount[edgePart] = overlaps;
789 detail::insert_unique(pieceToOriginals[edgePart], originals);
790#ifdef CDT_CXX11_IS_SUPPORTED
791 remaining.emplace_back(Edge(iVleft, iB), originals, overlaps);
792#else
793 remaining.push_back(make_tuple(Edge(iVleft, iB), originals, overlaps));
794#endif
795 return;
796 }
797
798 VertInd iV = iA;
799 Triangle t = triangles[iT];
800 while(std::find(t.vertices.begin(), t.vertices.end(), iB) ==
801 t.vertices.end())
802 {
803 const TriInd iTopo = opposedTriangle(t, iV);
804 const Triangle& tOpo = triangleAt(iTopo);
805 const VertInd iVopo = opposedVertex(tOpo, iT);
806 const V2d<T> vOpo = vertices[iVopo];
807
808 switch(m_intersectingEdgesStrategy)
809 {
811 if(fixedEdges.count(Edge(iVleft, iVright)))
812 handleException(IntersectingConstraintsError(
813 originalInputEdge(edge),
814 originalInputEdge(Edge(iVleft, iVright)),
815 CDT_SOURCE_LOCATION));
816 break;
818 {
819 if(!fixedEdges.count(Edge(iVleft, iVright)))
820 break;
821 // split edge at the intersection of two constraint edges
822 const V2d<T> newV = detail::intersectionPosition(
823 vertices[iA],
824 vertices[iB],
825 vertices[iVleft],
826 vertices[iVright]);
827 if(!isEdgeSplitVertexValid(newV, iT, iTopo, iVleft, iVright))
828 handleException(InvalidEdgeSplitVertex(
829 originalInputEdge(edge),
830 originalInputEdge(Edge(iVleft, iVright)),
831 CDT_SOURCE_LOCATION));
832 const VertInd iNewVert =
833 splitFixedEdgeAt(Edge(iVleft, iVright), newV, iT, iTopo);
834#ifdef CDT_CXX11_IS_SUPPORTED
835 remaining.emplace_back(Edge(iNewVert, iB), originals, overlaps);
836 remaining.emplace_back(Edge(iA, iNewVert), originals, overlaps);
837#else
838 remaining.push_back(
839 make_tuple(Edge(iNewVert, iB), originals, overlaps));
840 remaining.push_back(
841 make_tuple(Edge(iA, iNewVert), originals, overlaps));
842#endif
843 return;
844 }
846 assert(!fixedEdges.count(Edge(iVleft, iVright)));
847 break;
848 }
849
850 iT = iTopo;
851 t = triangles[iT];
852
853 const PtLineLocation::Enum loc =
854 locatePointLine(vOpo, a, b, distanceTolerance);
855 if(loc == PtLineLocation::Left)
856 {
857 iV = iVleft;
858 iVleft = iVopo;
859 }
860 else if(loc == PtLineLocation::Right)
861 {
862 iV = iVright;
863 iVright = iVopo;
864 }
865 else // encountered point on the edge
866 iB = iVopo;
867 }
868
869 // encountered one or more points on the edge: add remaining edge part
870 if(iB != edge.v2())
871 {
872#ifdef CDT_CXX11_IS_SUPPORTED
873 remaining.emplace_back(Edge(iB, edge.v2()), originals, overlaps);
874#else
875 remaining.push_back(
876 make_tuple(Edge(iB, edge.v2()), originals, overlaps));
877#endif
878 }
879
880 // add mid-point to triangulation
881 const VertInd iMid = verticesCount();
882 const V2d<T>& start = vertices[iA];
883 const V2d<T>& end = vertices[iB];
884 addNewVertex(
885 V2d<T>((start.x + end.x) / T(2), (start.y + end.y) / T(2)), noNeighbor);
886
887#ifdef CDT_ENABLE_CALLBACK_HANDLER
888 if(m_callbackHandler)
889 {
890 m_callbackHandler->onAddVertexStart(
892 }
893#endif
894
895 const std::vector<Edge> flippedFixedEdges =
896 insertVertex_FlipFixedEdges(iMid);
897
898#ifdef CDT_CXX11_IS_SUPPORTED
899 remaining.emplace_back(Edge(iMid, iB), originals, overlaps);
900 remaining.emplace_back(Edge(iA, iMid), originals, overlaps);
901#else
902 remaining.push_back(make_tuple(Edge(iMid, iB), originals, overlaps));
903 remaining.push_back(make_tuple(Edge(iA, iMid), originals, overlaps));
904#endif
905
906 // re-introduce fixed edges that were flipped
907 // and make sure overlap count is preserved
908 for(std::vector<Edge>::const_iterator it = flippedFixedEdges.begin();
909 it != flippedFixedEdges.end();
910 ++it)
911 {
912 const Edge& flippedFixedEdge = *it;
913 fixedEdges.erase(flippedFixedEdge);
914
915 BoundaryOverlapCount prevOverlaps = 0;
916 const unordered_map<Edge, BoundaryOverlapCount>::const_iterator
917 overlapsIt = overlapCount.find(flippedFixedEdge);
918 if(overlapsIt != overlapCount.end())
919 {
920 prevOverlaps = overlapsIt->second;
921 overlapCount.erase(overlapsIt);
922 }
923 // override overlapping boundaries count when re-inserting an edge
924 EdgeVec prevOriginals(1, flippedFixedEdge);
925 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
926 pieceToOriginals.find(flippedFixedEdge);
927 if(originalsIt != pieceToOriginals.end())
928 {
929 prevOriginals = originalsIt->second;
930 }
931#ifdef CDT_CXX11_IS_SUPPORTED
932 remaining.emplace_back(flippedFixedEdge, prevOriginals, prevOverlaps);
933#else
934 remaining.push_back(
935 make_tuple(flippedFixedEdge, prevOriginals, prevOverlaps));
936#endif
937 }
938}
939
940template <typename T, typename TNearPointLocator>
941void Triangulation<T, TNearPointLocator>::conformToEdge(
942 Edge edge,
943 EdgeVec originals,
944 BoundaryOverlapCount overlaps,
945 std::vector<ConformToEdgeTask>& remaining)
946{
947#ifdef CDT_ENABLE_CALLBACK_HANDLER
948 if(m_callbackHandler)
949 {
950 m_callbackHandler->onAddEdgeStart(edge);
951 }
952#endif
953
954 // use iteration over recursion to avoid stack overflows
955 remaining.clear();
956#ifdef CDT_CXX11_IS_SUPPORTED
957 remaining.emplace_back(edge, originals, overlaps);
958#else
959 remaining.push_back(make_tuple(edge, originals, overlaps));
960#endif
961 while(!remaining.empty())
962 {
963 tie(edge, originals, overlaps) = remaining.back();
964 remaining.pop_back();
965 conformToEdgeIteration(edge, originals, overlaps, remaining);
966 }
967}
968
979template <typename T, typename TNearPointLocator>
980tuple<TriInd, VertInd, VertInd>
981Triangulation<T, TNearPointLocator>::intersectedTriangle(
982 const VertInd iA,
983 const V2d<T>& a,
984 const V2d<T>& b,
985 const T orientationTolerance) const
986{
987 const TriInd startTri = m_vertTris[iA];
988 TriInd iT = startTri;
989 do
990 {
991 const Triangle t = triangles[iT];
992 const Index i = vertexInd(t.vertices, iA);
993 const VertInd iP2 = t.vertices[ccw(i)];
994 const T orientP2 = orient2D(vertices[iP2], a, b);
995 const PtLineLocation::Enum locP2 = classifyOrientation(orientP2);
996 if(locP2 == PtLineLocation::Right)
997 {
998 const VertInd iP1 = t.vertices[cw(i)];
999 const T orientP1 = orient2D(vertices[iP1], a, b);
1000 const PtLineLocation::Enum locP1 = classifyOrientation(orientP1);
1001 if(locP1 == PtLineLocation::OnLine)
1002 {
1003 return make_tuple(noNeighbor, iP1, iP1);
1004 }
1005 if(locP1 == PtLineLocation::Left)
1006 {
1007 if(orientationTolerance)
1008 {
1009 T closestOrient;
1010 VertInd iClosestP;
1011 if(std::abs(orientP1) <= std::abs(orientP2))
1012 {
1013 closestOrient = orientP1;
1014 iClosestP = iP1;
1015 }
1016 else
1017 {
1018 closestOrient = orientP2;
1019 iClosestP = iP2;
1020 }
1022 closestOrient, orientationTolerance) ==
1023 PtLineLocation::OnLine)
1024 {
1025 return make_tuple(noNeighbor, iClosestP, iClosestP);
1026 }
1027 }
1028 return make_tuple(iT, iP1, iP2);
1029 }
1030 }
1031 iT = t.next(iA).first;
1032 } while(iT != startTri);
1033
1034 handleException(Error(
1035 "Could not find vertex triangle intersected by an edge.",
1036 CDT_SOURCE_LOCATION));
1037 return make_tuple(noNeighbor, noVertex, noVertex);
1038}
1039
1040template <typename T, typename TNearPointLocator>
1041void Triangulation<T, TNearPointLocator>::addSuperTriangle(const Box2d<T>& box)
1042{
1043 m_nTargetVerts = nSuperTriangleVertices;
1044 m_superGeomType = SuperGeometryType::SuperTriangle;
1045
1046 const V2d<T> center(
1047 (box.min.x + box.max.x) / T(2), (box.min.y + box.max.y) / T(2));
1048 const T w = box.max.x - box.min.x;
1049 const T h = box.max.y - box.min.y;
1050 T r = std::max(w, h); // incircle radius upper bound
1051
1052 // Note: make sure radius is big enough. Constants chosen experimentally.
1053 // - for tiny bounding boxes: use 1.0 as the smallest radius
1054 // - multiply radius by 2.0 for extra safety margin
1055 r = std::max(T(2) * r, T(1));
1056
1057 // Note: for very large floating point numbers rounding can lead to wrong
1058 // super-triangle coordinates. This is a very rare corner-case so the
1059 // handling is very primitive.
1060 { // note: '<=' means '==' but avoids the warning
1061 while(center.y <= center.y - r)
1062 r *= T(2);
1063 }
1064
1065 const T R = T(2) * r; // excircle radius
1066 const T cos_30_deg = T(0.8660254037844386); // note: (std::sqrt(3.0) / 2.0)
1067 const T shiftX = R * cos_30_deg;
1068 const V2d<T> posV1(center.x - shiftX, center.y - r);
1069 const V2d<T> posV2(center.x + shiftX, center.y - r);
1070 const V2d<T> posV3(center.x, center.y + R);
1071 addNewVertex(posV1, TriInd(0));
1072 addNewVertex(posV2, TriInd(0));
1073 addNewVertex(posV3, TriInd(0));
1074
1075#ifdef CDT_ENABLE_CALLBACK_HANDLER
1076 if(m_callbackHandler)
1077 {
1078 m_callbackHandler->onAddSuperTriangle();
1079 }
1080#endif
1081
1082 addTriangle(
1083 Triangle(arr3(VertInd(0), VertInd(1), VertInd(2)), arr3(noNeighbor)));
1084
1085 if(m_vertexInsertionOrder != VertexInsertionOrder::Auto)
1086 {
1087 m_nearPtLocator.initialize(vertices);
1088 }
1089}
1090
1091template <typename T, typename TNearPointLocator>
1092void Triangulation<T, TNearPointLocator>::addNewVertex(
1093 const V2d<T>& pos,
1094 const TriInd iT)
1095{
1096 vertices.push_back(pos);
1097 m_vertTris.push_back(iT);
1098}
1099
1100template <typename T, typename TNearPointLocator>
1101std::vector<Edge>
1102Triangulation<T, TNearPointLocator>::insertVertex_FlipFixedEdges(
1103 const VertInd iV1)
1104{
1105 std::vector<Edge> flippedFixedEdges;
1106
1107 const V2d<T>& v1 = vertices[iV1];
1108 const VertInd startVertex = m_nearPtLocator.nearPoint(v1, vertices);
1109 array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iV1, startVertex);
1110 std::stack<TriInd> triStack =
1111 trisAt[1] == noNeighbor ? insertVertexInsideTriangle(iV1, trisAt[0])
1112 : insertVertexOnEdge(iV1, trisAt[0], trisAt[1]);
1113
1114 TriInd iTopo, n1, n2, n3, n4;
1115 VertInd iV2, iV3, iV4;
1116 while(!triStack.empty())
1117 {
1118 const TriInd iT = triStack.top();
1119 triStack.pop();
1120
1121 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1122 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1123 {
1124 // if flipped edge is fixed, remember it
1125 const Edge flippedEdge(iV2, iV4);
1126 if(!fixedEdges.empty() &&
1127 fixedEdges.find(flippedEdge) != fixedEdges.end())
1128 {
1129 flippedFixedEdges.push_back(flippedEdge);
1130 }
1131
1132 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1133 triStack.push(iT);
1134 triStack.push(iTopo);
1135 }
1136 }
1137
1138 tryAddVertexToLocator(iV1);
1139 return flippedFixedEdges;
1140}
1141
1142template <typename T, typename TNearPointLocator>
1143void Triangulation<T, TNearPointLocator>::insertVertex(
1144 const VertInd iVert,
1145 const VertInd walkStart)
1146{
1147#ifdef CDT_ENABLE_CALLBACK_HANDLER
1148 if(m_callbackHandler)
1149 {
1150 m_callbackHandler->onAddVertexStart(iVert, AddVertexType::UserInput);
1151 }
1152#endif
1153
1154 const array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iVert, walkStart);
1155 std::stack<TriInd> triStack =
1156 trisAt[1] == noNeighbor
1157 ? insertVertexInsideTriangle(iVert, trisAt[0])
1158 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1], true);
1159 ensureDelaunayByEdgeFlips(iVert, triStack);
1160}
1161
1162template <typename T, typename TNearPointLocator>
1163void Triangulation<T, TNearPointLocator>::insertVertex(const VertInd iVert)
1164{
1165 const V2d<T>& v = vertices[iVert];
1166 const VertInd walkStart = m_nearPtLocator.nearPoint(v, vertices);
1167 insertVertex(iVert, walkStart);
1168 tryAddVertexToLocator(iVert);
1169}
1170
1171template <typename T, typename TNearPointLocator>
1172void Triangulation<T, TNearPointLocator>::ensureDelaunayByEdgeFlips(
1173 const VertInd iV1,
1174 std::stack<TriInd>& triStack)
1175{
1176 TriInd iTopo, n1, n2, n3, n4;
1177 VertInd iV2, iV3, iV4;
1178 while(!triStack.empty())
1179 {
1180 const TriInd iT = triStack.top();
1181 triStack.pop();
1182
1183 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1184 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1185 {
1186 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1187 triStack.push(iT);
1188 triStack.push(iTopo);
1189 }
1190 }
1191}
1192
1193/*
1194 * v4 original edge: (v1, v3)
1195 * /|\ flip-candidate edge: (v, v2)
1196 * / | \
1197 * n3 / | \ n4
1198 * / | \
1199 * new vertex--> v1 T | Topo v3
1200 * \ | /
1201 * n1 \ | / n2
1202 * \ | /
1203 * \|/
1204 * v2
1205 */
1206template <typename T, typename TNearPointLocator>
1207void Triangulation<T, TNearPointLocator>::edgeFlipInfo(
1208 const TriInd iT,
1209 const VertInd iV1,
1210 TriInd& iTopo,
1211 VertInd& iV2,
1212 VertInd& iV3,
1213 VertInd& iV4,
1214 TriInd& n1,
1215 TriInd& n2,
1216 TriInd& n3,
1217 TriInd& n4)
1218{
1219 /* v[2]
1220 / \
1221 n[2]/ \n[1]
1222 /_____\
1223 v[0] n[0] v[1] */
1224 const Triangle& t = triangles[iT];
1225 if(t.vertices[0] == iV1)
1226 {
1227 iV2 = t.vertices[1];
1228 iV4 = t.vertices[2];
1229 n1 = t.neighbors[0];
1230 n3 = t.neighbors[2];
1231 iTopo = t.neighbors[1];
1232 }
1233 else if(t.vertices[1] == iV1)
1234 {
1235 iV2 = t.vertices[2];
1236 iV4 = t.vertices[0];
1237 n1 = t.neighbors[1];
1238 n3 = t.neighbors[0];
1239 iTopo = t.neighbors[2];
1240 }
1241 else
1242 {
1243 iV2 = t.vertices[0];
1244 iV4 = t.vertices[1];
1245 n1 = t.neighbors[2];
1246 n3 = t.neighbors[1];
1247 iTopo = t.neighbors[0];
1248 }
1249 if(iTopo == noNeighbor)
1250 return;
1251 const Triangle& tOpo = triangles[iTopo];
1252 if(tOpo.neighbors[0] == iT)
1253 {
1254 iV3 = tOpo.vertices[2];
1255 n2 = tOpo.neighbors[1];
1256 n4 = tOpo.neighbors[2];
1257 }
1258 else if(tOpo.neighbors[1] == iT)
1259 {
1260 iV3 = tOpo.vertices[0];
1261 n2 = tOpo.neighbors[2];
1262 n4 = tOpo.neighbors[0];
1263 }
1264 else
1265 {
1266 iV3 = tOpo.vertices[1];
1267 n2 = tOpo.neighbors[0];
1268 n4 = tOpo.neighbors[1];
1269 }
1270}
1271
1282/*
1283 * v4 original edge: (v2, v4)
1284 * /|\ flip-candidate edge: (v1, v3)
1285 * / | \
1286 * / | \
1287 * / | \
1288 * new vertex--> v1 | v3
1289 * \ | /
1290 * \ | /
1291 * \ | /
1292 * \|/
1293 * v2
1294 */
1295template <typename T, typename TNearPointLocator>
1296bool Triangulation<T, TNearPointLocator>::isFlipNeeded(
1297 const VertInd iV1,
1298 const VertInd iV2,
1299 const VertInd iV3,
1300 const VertInd iV4) const
1301{
1302 if(fixedEdges.count(Edge(iV2, iV4)))
1303 return false; // flip not needed if the original edge is fixed
1304 const V2d<T>& v1 = vertices[iV1];
1305 const V2d<T>& v2 = vertices[iV2];
1306 const V2d<T>& v3 = vertices[iV3];
1307 const V2d<T>& v4 = vertices[iV4];
1308 if(m_superGeomType == SuperGeometryType::SuperTriangle)
1309 {
1310 // If flip-candidate edge touches super-triangle in-circumference
1311 // test has to be replaced with orient2d test against the line
1312 // formed by two non-artificial vertices (that don't belong to
1313 // super-triangle)
1314 if(iV1 < 3) // flip-candidate edge touches super-triangle
1315 {
1316 // does original edge also touch super-triangle?
1317 if(iV2 < 3)
1318 return locatePointLine(v2, v3, v4) ==
1319 locatePointLine(v1, v3, v4);
1320 if(iV4 < 3)
1321 return locatePointLine(v4, v2, v3) ==
1322 locatePointLine(v1, v2, v3);
1323 return false; // original edge does not touch super-triangle
1324 }
1325 if(iV3 < 3) // flip-candidate edge touches super-triangle
1326 {
1327 // does original edge also touch super-triangle?
1328 if(iV2 < 3)
1329 {
1330 return locatePointLine(v2, v1, v4) ==
1331 locatePointLine(v3, v1, v4);
1332 }
1333 if(iV4 < 3)
1334 {
1335 return locatePointLine(v4, v2, v1) ==
1336 locatePointLine(v3, v2, v1);
1337 }
1338 return false; // original edge does not touch super-triangle
1339 }
1340 // flip-candidate edge does not touch super-triangle
1341 if(iV2 < 3)
1342 return locatePointLine(v2, v3, v4) == locatePointLine(v1, v3, v4);
1343 if(iV4 < 3)
1344 return locatePointLine(v4, v2, v3) == locatePointLine(v1, v2, v3);
1345 }
1346 return isInCircumcircle(v1, v2, v3, v4);
1347}
1348
1349/* Flip edge between T and Topo:
1350 *
1351 * v4 | - old edge
1352 * /|\ ~ - new edge
1353 * / | \
1354 * n3 / T' \ n4
1355 * / | \
1356 * / | \
1357 * T -> v1~~~~~~~~~v3 <- Topo
1358 * \ | /
1359 * \ | /
1360 * n1 \Topo'/ n2
1361 * \ | /
1362 * \|/
1363 * v2
1364 */
1365template <typename T, typename TNearPointLocator>
1367 const TriInd iT,
1368 const TriInd iTopo)
1369{
1370#ifdef CDT_ENABLE_CALLBACK_HANDLER
1371 if(m_callbackHandler)
1372 {
1373 m_callbackHandler->onFlipEdge(iT, iTopo);
1374 }
1375#endif
1376
1377 Triangle& t = triangles[iT];
1378 Triangle& tOpo = triangles[iTopo];
1379 const array<TriInd, 3>& triNs = t.neighbors;
1380 const array<TriInd, 3>& triOpoNs = tOpo.neighbors;
1381 const array<VertInd, 3>& triVs = t.vertices;
1382 const array<VertInd, 3>& triOpoVs = tOpo.vertices;
1383 // find vertices and neighbors
1384 Index i = opposedVertexInd(t.neighbors, iTopo);
1385 const VertInd v1 = triVs[i];
1386 const VertInd v2 = triVs[ccw(i)];
1387 const TriInd n1 = triNs[i];
1388 const TriInd n3 = triNs[cw(i)];
1389 i = opposedVertexInd(tOpo.neighbors, iT);
1390 const VertInd v3 = triOpoVs[i];
1391 const VertInd v4 = triOpoVs[ccw(i)];
1392 const TriInd n4 = triOpoNs[i];
1393 const TriInd n2 = triOpoNs[cw(i)];
1394 // change vertices and neighbors
1395 t = Triangle(arr3(v4, v1, v3), arr3(n3, iTopo, n4));
1396 tOpo = Triangle(arr3(v2, v3, v1), arr3(n2, iT, n1));
1397 // adjust neighboring triangles and vertices
1398 changeNeighbor(n1, iT, iTopo);
1399 changeNeighbor(n4, iTopo, iT);
1400 // only adjust adjacent triangles if triangulation is not finalized:
1401 // can happen when called from outside on an already finalized
1402 // triangulation
1403 if(!isFinalized())
1404 {
1405 setAdjacentTriangle(v4, iT);
1406 setAdjacentTriangle(v2, iTopo);
1407 }
1408}
1409
1410/* Flip edge between T and Topo:
1411 *
1412 * v4 | - old edge
1413 * /|\ ~ - new edge
1414 * / | \
1415 * n3 / T' \ n4
1416 * / | \
1417 * / | \
1418 * T -> v1 ~~~~~~~~ v3 <- Topo
1419 * \ | /
1420 * \ | /
1421 * n1 \Topo'/ n2
1422 * \ | /
1423 * \|/
1424 * v2
1425 */
1426template <typename T, typename TNearPointLocator>
1428 const TriInd iT,
1429 const TriInd iTopo,
1430 const VertInd v1,
1431 const VertInd v2,
1432 const VertInd v3,
1433 const VertInd v4,
1434 const TriInd n1,
1435 const TriInd n2,
1436 const TriInd n3,
1437 const TriInd n4)
1438{
1439#ifdef CDT_ENABLE_CALLBACK_HANDLER
1440 if(m_callbackHandler)
1441 {
1442 m_callbackHandler->onFlipEdge(iT, iTopo);
1443 }
1444#endif
1445
1446 // change vertices and neighbors
1447 triangles[iT] = Triangle(arr3(v4, v1, v3), arr3(n3, iTopo, n4));
1448 triangles[iTopo] = Triangle(arr3(v2, v3, v1), arr3(n2, iT, n1));
1449 // adjust neighboring triangles and vertices
1450 changeNeighbor(n1, iT, iTopo);
1451 changeNeighbor(n4, iTopo, iT);
1452 // only adjust adjacent triangles if triangulation is not finalized:
1453 // can happen when called from outside on an already finalized
1454 // triangulation
1455 if(!isFinalized())
1456 {
1457 setAdjacentTriangle(v4, iT);
1458 setAdjacentTriangle(v2, iTopo);
1459 }
1460}
1461
1462/* Insert point into triangle: split into 3 triangles:
1463 * - create 2 new triangles
1464 * - re-use old triangle for the 3rd
1465 * v3
1466 * / | \
1467 * / | \ <-- original triangle (t)
1468 * / | \
1469 * n3 / | \ n2
1470 * /newT2|newT1\
1471 * / v \
1472 * / __/ \__ \
1473 * / __/ \__ \
1474 * / _/ t' \_ \
1475 * v1 ___________________ v2
1476 * n1
1477 */
1478template <typename T, typename TNearPointLocator>
1479std::stack<TriInd>
1480Triangulation<T, TNearPointLocator>::insertVertexInsideTriangle(
1481 VertInd v,
1482 TriInd iT)
1483{
1484 const TriInd iNewT1 = addTriangle();
1485 const TriInd iNewT2 = addTriangle();
1486
1487#ifdef CDT_ENABLE_CALLBACK_HANDLER
1488 if(m_callbackHandler)
1489 {
1490 m_callbackHandler->onInsertVertexInsideTriangle(iT, iNewT1, iNewT2);
1491 }
1492#endif
1493
1494 Triangle& t = triangles[iT];
1495 const array<VertInd, 3> vv = t.vertices;
1496 const array<TriInd, 3> nn = t.neighbors;
1497 const VertInd v1 = vv[0], v2 = vv[1], v3 = vv[2];
1498 const TriInd n1 = nn[0], n2 = nn[1], n3 = nn[2];
1499 // make two new triangles and convert current triangle to 3rd new
1500 // triangle
1501 triangles[iNewT1] = Triangle(arr3(v2, v3, v), arr3(n2, iNewT2, iT));
1502 triangles[iNewT2] = Triangle(arr3(v3, v1, v), arr3(n3, iT, iNewT1));
1503 t = Triangle(arr3(v1, v2, v), arr3(n1, iNewT1, iNewT2));
1504 // adjust adjacent triangles
1505 setAdjacentTriangle(v, iT);
1506 setAdjacentTriangle(v3, iNewT1);
1507 // change triangle neighbor's neighbors to new triangles
1508 changeNeighbor(n2, iT, iNewT1);
1509 changeNeighbor(n3, iT, iNewT2);
1510 // return newly added triangles
1511 std::stack<TriInd> newTriangles;
1512 newTriangles.push(iT);
1513 newTriangles.push(iNewT1);
1514 newTriangles.push(iNewT2);
1515 return newTriangles;
1516}
1517
1518/* Inserting a point on the edge between two triangles
1519 * T1 (top) v1
1520 * /|\
1521 * n1 / | \ n4
1522 * / | \
1523 * / T1' | Tnew1\
1524 * v2-------v-------v4
1525 * \ T2' | Tnew2/
1526 * \ | /
1527 * n2 \ | / n3
1528 * \|/
1529 * T2 (bottom) v3
1530 */
1531template <typename T, typename TNearPointLocator>
1532std::stack<TriInd> Triangulation<T, TNearPointLocator>::insertVertexOnEdge(
1533 VertInd v,
1534 TriInd iT1,
1535 TriInd iT2,
1536 const bool doHandleFixedSplitEdge)
1537{
1538 const TriInd iTnew1 = addTriangle();
1539 const TriInd iTnew2 = addTriangle();
1540
1541#ifdef CDT_ENABLE_CALLBACK_HANDLER
1542 if(m_callbackHandler)
1543 {
1544 m_callbackHandler->onInsertVertexOnEdge(iT1, iT2, iTnew1, iTnew2);
1545 }
1546#endif
1547
1548 Triangle& t1 = triangles[iT1];
1549 Triangle& t2 = triangles[iT2];
1550 Index i = opposedVertexInd(t1.neighbors, iT2);
1551 const VertInd v1 = t1.vertices[i];
1552 const VertInd v2 = t1.vertices[ccw(i)];
1553 const TriInd n1 = t1.neighbors[i];
1554 const TriInd n4 = t1.neighbors[cw(i)];
1555 i = opposedVertexInd(t2.neighbors, iT1);
1556 const VertInd v3 = t2.vertices[i];
1557 const VertInd v4 = t2.vertices[ccw(i)];
1558 const TriInd n3 = t2.neighbors[i];
1559 const TriInd n2 = t2.neighbors[cw(i)];
1560 // add new triangles and change existing ones
1561 t1 = Triangle(arr3(v, v1, v2), arr3(iTnew1, n1, iT2));
1562 t2 = Triangle(arr3(v, v2, v3), arr3(iT1, n2, iTnew2));
1563 triangles[iTnew1] = Triangle(arr3(v, v4, v1), arr3(iTnew2, n4, iT1));
1564 triangles[iTnew2] = Triangle(arr3(v, v3, v4), arr3(iT2, n3, iTnew1));
1565 // adjust adjacent triangles
1566 setAdjacentTriangle(v, iT1);
1567 setAdjacentTriangle(v4, iTnew1);
1568 // adjust neighboring triangles and vertices
1569 changeNeighbor(n4, iT1, iTnew1);
1570 changeNeighbor(n3, iT2, iTnew2);
1571 // properly handle the case when the split edge is a fixed edge
1572 if(doHandleFixedSplitEdge)
1573 {
1574 const Edge sharedEdge(v2, v4);
1575 if(fixedEdges.count(sharedEdge))
1576 splitFixedEdge(sharedEdge, v);
1577 }
1578 // return newly added triangles
1579 std::stack<TriInd> newTriangles;
1580 newTriangles.push(iT1);
1581 newTriangles.push(iTnew2);
1582 newTriangles.push(iT2);
1583 newTriangles.push(iTnew1);
1584 return newTriangles;
1585}
1586
1587template <typename T, typename TNearPointLocator>
1588array<TriInd, 2>
1589Triangulation<T, TNearPointLocator>::trianglesAt(const V2d<T>& pos) const
1590{
1591 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1592 for(TriInd i = TriInd(0); i < TriInd(triangles.size()); ++i)
1593 {
1594 const Triangle& t = triangles[i];
1595 const V2d<T>& v1 = vertices[t.vertices[0]];
1596 const V2d<T>& v2 = vertices[t.vertices[1]];
1597 const V2d<T>& v3 = vertices[t.vertices[2]];
1598 const PtTriLocation::Enum loc = locatePointTriangle(pos, v1, v2, v3);
1599 if(loc == PtTriLocation::Outside)
1600 continue;
1601 out[0] = i;
1602 if(isOnEdge(loc))
1603 out[1] = t.neighbors[edgeNeighbor(loc)];
1604 return out;
1605 }
1606 handleException(
1607 Error("No triangle was found at position", CDT_SOURCE_LOCATION));
1608 return out;
1609}
1610
1611template <typename T, typename TNearPointLocator>
1612TriInd Triangulation<T, TNearPointLocator>::walkTriangles(
1613 const VertInd startVertex,
1614 const V2d<T>& pos) const
1615{
1616 // begin walk in search of triangle at pos
1617 TriInd currTri = m_vertTris[startVertex];
1618 bool found = false;
1619 detail::SplitMix64RandGen prng;
1620 while(!found)
1621 {
1622 const Triangle& t = triangles[currTri];
1623 found = true;
1624 // stochastic offset to randomize which edge we check first
1625 const Index offset(prng() % 3);
1626 for(Index i_(0); i_ < Index(3); ++i_)
1627 {
1628 const Index i((i_ + offset) % 3);
1629 const V2d<T>& vStart = vertices[t.vertices[i]];
1630 const V2d<T>& vEnd = vertices[t.vertices[ccw(i)]];
1631 const PtLineLocation::Enum edgeCheck =
1632 locatePointLine(pos, vStart, vEnd);
1633 const TriInd iN = t.neighbors[i];
1634 if(edgeCheck == PtLineLocation::Right && iN != noNeighbor)
1635 {
1636 found = false;
1637 currTri = iN;
1638 break;
1639 }
1640 }
1641 }
1642 return currTri;
1643}
1644
1645template <typename T, typename TNearPointLocator>
1646array<TriInd, 2> Triangulation<T, TNearPointLocator>::walkingSearchTrianglesAt(
1647 const VertInd iV,
1648 const VertInd startVertex) const
1649{
1650 const V2d<T> v = vertices[iV];
1651 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1652 const TriInd iT = walkTriangles(startVertex, v);
1653 // Finished walk, locate point in current triangle
1654 const Triangle& t = triangles[iT];
1655 const V2d<T>& v1 = vertices[t.vertices[0]];
1656 const V2d<T>& v2 = vertices[t.vertices[1]];
1657 const V2d<T>& v3 = vertices[t.vertices[2]];
1658 const PtTriLocation::Enum loc = locatePointTriangle(v, v1, v2, v3);
1659
1660 if(loc == PtTriLocation::Outside)
1661 {
1662 handleException(
1663 Error("No triangle was found at position", CDT_SOURCE_LOCATION));
1664 }
1665 if(loc == PtTriLocation::OnVertex)
1666 {
1667 const VertInd iDupe = v1 == v ? t.vertices[0]
1668 : v2 == v ? t.vertices[1]
1669 : t.vertices[2];
1670 handleException(DuplicateVertexError(
1671 VertInd(iV - m_nTargetVerts),
1672 VertInd(iDupe - m_nTargetVerts),
1673 CDT_SOURCE_LOCATION));
1674 }
1675
1676 out[0] = iT;
1677 if(isOnEdge(loc))
1678 out[1] = t.neighbors[edgeNeighbor(loc)];
1679 return out;
1680}
1681
1682template <typename T, typename TNearPointLocator>
1683void Triangulation<T, TNearPointLocator>::changeNeighbor(
1684 const TriInd iT,
1685 const TriInd oldNeighbor,
1686 const TriInd newNeighbor)
1687{
1688 if(iT == noNeighbor)
1689 return;
1690 NeighborsArr3& nn = triangles[iT].neighbors;
1691 assert(
1692 nn[0] == oldNeighbor || nn[1] == oldNeighbor || nn[2] == oldNeighbor);
1693 if(nn[0] == oldNeighbor)
1694 nn[0] = newNeighbor;
1695 else if(nn[1] == oldNeighbor)
1696 nn[1] = newNeighbor;
1697 else
1698 nn[2] = newNeighbor;
1699}
1700
1701template <typename T, typename TNearPointLocator>
1702void Triangulation<T, TNearPointLocator>::changeNeighbor(
1703 const TriInd iT,
1704 const VertInd iVedge1,
1705 const VertInd iVedge2,
1706 const TriInd newNeighbor)
1707{
1708 assert(iT != noNeighbor);
1709 Triangle& t = triangles[iT];
1710 t.neighbors[edgeNeighborInd(t.vertices, iVedge1, iVedge2)] = newNeighbor;
1711}
1712
1713template <typename T, typename TNearPointLocator>
1714void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygon(
1715 const std::vector<VertInd>& poly,
1716 unordered_map<Edge, TriInd>& outerTris,
1717 TriInd iT,
1718 TriInd iN,
1719 std::vector<TriInd>& trianglesToReuse,
1720 std::vector<TriangulatePseudoPolygonTask>& iterations)
1721{
1722 assert(poly.size() > 2);
1723 // note: uses iteration instead of recursion to avoid stack overflows
1724 iterations.clear();
1725 iterations.push_back(make_tuple(
1726 IndexSizeType(0),
1727 static_cast<IndexSizeType>(poly.size() - 1),
1728 iT,
1729 iN,
1730 Index(0)));
1731 while(!iterations.empty())
1732 {
1733 triangulatePseudoPolygonIteration(
1734 poly, outerTris, trianglesToReuse, iterations);
1735 }
1736}
1737
1738template <typename T, typename TNearPointLocator>
1739void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygonIteration(
1740 const std::vector<VertInd>& poly,
1741 unordered_map<Edge, TriInd>& outerTris,
1742 std::vector<TriInd>& trianglesToReuse,
1743 std::vector<TriangulatePseudoPolygonTask>& iterations)
1744{
1745 IndexSizeType iA, iB;
1746 TriInd iT, iParent;
1747 Index iInParent;
1748 assert(!iterations.empty());
1749 tie(iA, iB, iT, iParent, iInParent) = iterations.back();
1750 iterations.pop_back();
1751 assert(iB - iA > 1 && iT != noNeighbor && iParent != noNeighbor);
1752 Triangle& t = triangles[iT];
1753 // find Delaunay point
1754 const IndexSizeType iC = findDelaunayPoint(poly, iA, iB);
1755
1756 const VertInd a = poly[iA];
1757 const VertInd b = poly[iB];
1758 const VertInd c = poly[iC];
1759
1760 // split pseudo-polygon in two parts and triangulate them
1761 // note: second part needs to be pushed on stack first to be processed first
1762
1763 // second part: points after the Delaunay point
1764 if(iB - iC > 1)
1765 {
1766 assert(!trianglesToReuse.empty());
1767 const TriInd iNext = trianglesToReuse.back();
1768 trianglesToReuse.pop_back();
1769 iterations.push_back(make_tuple(iC, iB, iNext, iT, Index(1)));
1770 }
1771 else // pseudo-poly is reduced to a single outer edge
1772 {
1773 const Edge outerEdge(b, c);
1774 const TriInd outerTri = outerTris.at(outerEdge);
1775 if(outerTri != noNeighbor)
1776 {
1777 assert(outerTri != iT);
1778 t.neighbors[1] = outerTri;
1779 changeNeighbor(outerTri, c, b, iT);
1780 }
1781 else
1782 outerTris.at(outerEdge) = iT;
1783 }
1784 // first part: points before the Delaunay point
1785 if(iC - iA > 1)
1786 { // add next triangle and add another iteration
1787 assert(!trianglesToReuse.empty());
1788 const TriInd iNext = trianglesToReuse.back();
1789 trianglesToReuse.pop_back();
1790 iterations.push_back(make_tuple(iA, iC, iNext, iT, Index(2)));
1791 }
1792 else
1793 { // pseudo-poly is reduced to a single outer edge
1794 const Edge outerEdge(c, a);
1795 const TriInd outerTri = outerTris.at(outerEdge);
1796 if(outerTri != noNeighbor)
1797 {
1798 assert(outerTri != iT);
1799 t.neighbors[2] = outerTri;
1800 changeNeighbor(outerTri, c, a, iT);
1801 }
1802 else
1803 outerTris.at(outerEdge) = iT;
1804 }
1805 // Finalize triangle
1806 // note: only when triangle is finalized to we add it as a neighbor to
1807 // parent to maintain triangulation topology consistency
1808 triangles[iParent].neighbors[iInParent] = iT;
1809 t.neighbors[0] = iParent;
1810 t.vertices = arr3(a, b, c);
1811 setAdjacentTriangle(c, iT);
1812}
1813
1814template <typename T, typename TNearPointLocator>
1815IndexSizeType Triangulation<T, TNearPointLocator>::findDelaunayPoint(
1816 const std::vector<VertInd>& poly,
1817 const IndexSizeType iA,
1818 const IndexSizeType iB) const
1819{
1820 assert(iB - iA > 1);
1821 const V2d<T>& a = vertices[poly[iA]];
1822 const V2d<T>& b = vertices[poly[iB]];
1823 IndexSizeType out = iA + 1;
1824 const V2d<T>* c = &vertices[poly[out]]; // caching for better performance
1825 for(IndexSizeType i = iA + 1; i < iB; ++i)
1826 {
1827 const V2d<T>& v = vertices[poly[i]];
1828 if(isInCircumcircle(v, a, b, *c))
1829 {
1830 out = i;
1831 c = &v;
1832 }
1833 }
1834 assert(out > iA && out < iB); // point is between ends
1835 return out;
1836}
1837
1838template <typename T, typename TNearPointLocator>
1840 const std::vector<V2d<T> >& newVertices)
1841{
1842 return insertVertices(
1843 newVertices.begin(), newVertices.end(), getX_V2d<T>, getY_V2d<T>);
1844}
1845
1846template <typename T, typename TNearPointLocator>
1848{
1849 return m_vertTris.empty() && !vertices.empty();
1850}
1851
1852template <typename T, typename TNearPointLocator>
1853unordered_map<TriInd, LayerDepth>
1854Triangulation<T, TNearPointLocator>::peelLayer(
1855 std::stack<TriInd> seeds,
1856 const LayerDepth layerDepth,
1857 std::vector<LayerDepth>& triDepths) const
1858{
1859 unordered_map<TriInd, LayerDepth> behindBoundary;
1860 while(!seeds.empty())
1861 {
1862 const TriInd iT = seeds.top();
1863 seeds.pop();
1864 triDepths[iT] = std::min(triDepths[iT], layerDepth);
1865 behindBoundary.erase(iT);
1866 const Triangle& t = triangles[iT];
1867 for(Index i(0); i < Index(3); ++i)
1868 {
1869 const Edge opEdge(t.vertices[ccw(i)], t.vertices[cw(i)]);
1870 const TriInd iN = t.neighbors[opoNbr(i)];
1871 if(iN == noNeighbor || triDepths[iN] <= layerDepth)
1872 continue;
1873 if(fixedEdges.count(opEdge))
1874 {
1875 const unordered_map<Edge, LayerDepth>::const_iterator cit =
1876 overlapCount.find(opEdge);
1877 const LayerDepth triDepth = cit == overlapCount.end()
1878 ? layerDepth + 1
1879 : layerDepth + cit->second + 1;
1880 behindBoundary[iN] = triDepth;
1881 continue;
1882 }
1883 seeds.push(iN);
1884 }
1885 }
1886 return behindBoundary;
1887}
1888
1889template <typename T, typename TNearPointLocator>
1890std::vector<LayerDepth>
1892{
1893 std::vector<LayerDepth> triDepths(
1894 triangles.size(), std::numeric_limits<LayerDepth>::max());
1895 std::stack<TriInd> seeds(TriDeque(1, m_vertTris[0]));
1896 LayerDepth layerDepth = 0;
1897 LayerDepth deepestSeedDepth = 0;
1898
1899 unordered_map<LayerDepth, TriIndUSet> seedsByDepth;
1900 do
1901 {
1902 const unordered_map<TriInd, LayerDepth>& newSeeds =
1903 peelLayer(seeds, layerDepth, triDepths);
1904
1905 seedsByDepth.erase(layerDepth);
1906 typedef unordered_map<TriInd, LayerDepth>::const_iterator Iter;
1907 for(Iter it = newSeeds.begin(); it != newSeeds.end(); ++it)
1908 {
1909 deepestSeedDepth = std::max(deepestSeedDepth, it->second);
1910 seedsByDepth[it->second].insert(it->first);
1911 }
1912 const TriIndUSet& nextLayerSeeds = seedsByDepth[layerDepth + 1];
1913 seeds = std::stack<TriInd>(
1914 TriDeque(nextLayerSeeds.begin(), nextLayerSeeds.end()));
1915 ++layerDepth;
1916 } while(!seeds.empty() || deepestSeedDepth > layerDepth);
1917
1918 return triDepths;
1919}
1920
1921#ifdef CDT_ENABLE_CALLBACK_HANDLER
1922template <typename T, typename TNearPointLocator>
1924 ICallbackHandler* callbackHandler)
1925{
1926 m_callbackHandler = callbackHandler;
1927}
1928#endif
1929
1930template <typename T, typename TNearPointLocator>
1931void Triangulation<T, TNearPointLocator>::insertVertices_AsProvided(
1932 VertInd superGeomVertCount)
1933{
1934 for(VertInd iV = superGeomVertCount; iV < vertices.size(); ++iV)
1935 {
1936#ifdef CDT_ENABLE_CALLBACK_HANDLER
1937 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
1938 {
1939 return;
1940 }
1941#endif
1942 insertVertex(iV);
1943 }
1944}
1945
1946template <typename T, typename TNearPointLocator>
1947void Triangulation<T, TNearPointLocator>::insertVertices_Randomized(
1948 VertInd superGeomVertCount)
1949{
1950 std::size_t vertexCount = vertices.size() - superGeomVertCount;
1951 std::vector<VertInd> ii(vertexCount);
1952 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
1953 detail::random_shuffle(ii.begin(), ii.end());
1954 for(std::vector<VertInd>::iterator it = ii.begin(); it != ii.end(); ++it)
1955 {
1956#ifdef CDT_ENABLE_CALLBACK_HANDLER
1957 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
1958 {
1959 return;
1960 }
1961#endif
1962 insertVertex(*it);
1963 }
1964}
1965
1966namespace detail
1967{
1968
1969// log2 implementation backwards compatible with pre c++11
1970template <typename T>
1971inline double log2_bc(T x)
1972{
1973#ifdef CDT_CXX11_IS_SUPPORTED
1974 return std::log2(x);
1975#else
1976 static double log2_constant = std::log(2.0);
1977 return std::log(static_cast<double>(x)) / log2_constant;
1978#endif
1979}
1980
1985inline std::size_t maxQueueLengthBFSKDTree(const std::size_t vertexCount)
1986{
1987 const int filledLayerPow2 =
1988 static_cast<int>(std::floor(log2_bc(vertexCount)) - 1);
1989 const std::size_t nodesInFilledTree =
1990 static_cast<std::size_t>(std::pow(2., filledLayerPow2 + 1) - 1);
1991 const std::size_t nodesInLastFilledLayer =
1992 static_cast<std::size_t>(std::pow(2., filledLayerPow2));
1993 const std::size_t nodesInLastLayer = vertexCount - nodesInFilledTree;
1994 return nodesInLastLayer >= nodesInLastFilledLayer
1995 ? nodesInLastFilledLayer + nodesInLastLayer -
1996 nodesInLastFilledLayer
1997 : nodesInLastFilledLayer;
1998}
1999
2000template <typename T>
2001class FixedCapacityQueue
2002{
2003public:
2004 FixedCapacityQueue(const std::size_t capacity)
2005 : m_vec(capacity)
2006 , m_front(m_vec.begin())
2007 , m_back(m_vec.begin())
2008 , m_size(0)
2009 {}
2010 bool empty() const
2011 {
2012 return m_size == 0;
2013 }
2014 const T& front() const
2015 {
2016 return *m_front;
2017 }
2018 void pop()
2019 {
2020 assert(m_size > 0);
2021 ++m_front;
2022 if(m_front == m_vec.end())
2023 m_front = m_vec.begin();
2024 --m_size;
2025 }
2026 void push(const T& t)
2027 {
2028 assert(m_size < m_vec.size());
2029 *m_back = t;
2030 ++m_back;
2031 if(m_back == m_vec.end())
2032 m_back = m_vec.begin();
2033 ++m_size;
2034 }
2035#ifdef CDT_CXX11_IS_SUPPORTED
2036 void push(const T&& t)
2037 {
2038 assert(m_size < m_vec.size());
2039 *m_back = t;
2040 ++m_back;
2041 if(m_back == m_vec.end())
2042 m_back = m_vec.begin();
2043 ++m_size;
2044 }
2045#endif
2046private:
2047 std::vector<T> m_vec;
2048 typename std::vector<T>::iterator m_front;
2049 typename std::vector<T>::iterator m_back;
2050 std::size_t m_size;
2051};
2052
2053template <typename T>
2054class less_than_x
2055{
2056 const std::vector<V2d<T> >& m_vertices;
2057
2058public:
2059 less_than_x(const std::vector<V2d<T> >& vertices)
2060 : m_vertices(vertices)
2061 {}
2062 bool operator()(const VertInd a, const VertInd b) const
2063 {
2064 return m_vertices[a].x < m_vertices[b].x;
2065 }
2066};
2067
2068template <typename T>
2069class less_than_y
2070{
2071 const std::vector<V2d<T> >& m_vertices;
2072
2073public:
2074 less_than_y(const std::vector<V2d<T> >& vertices)
2075 : m_vertices(vertices)
2076 {}
2077 bool operator()(const VertInd a, const VertInd b) const
2078 {
2079 return m_vertices[a].y < m_vertices[b].y;
2080 }
2081};
2082
2083} // namespace detail
2084
2085template <typename T, typename TNearPointLocator>
2086void Triangulation<T, TNearPointLocator>::insertVertices_KDTreeBFS(
2087 VertInd superGeomVertCount,
2088 Box2d<T> box)
2089{
2090 // calculate original indices
2091 const VertInd vertexCount(verticesCount() - superGeomVertCount);
2092 if(vertexCount <= VertInd(0))
2093 return;
2094 std::vector<VertInd> ii(vertexCount);
2095 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
2096
2097 typedef std::vector<VertInd>::iterator It;
2099 detail::maxQueueLengthBFSKDTree(vertexCount));
2100 queue.push(make_tuple(ii.begin(), ii.end(), box.min, box.max, VertInd(0)));
2101
2102 It first, last;
2103 V2d<T> newBoxMin, newBoxMax;
2104 VertInd parent, mid;
2105
2106 const detail::less_than_x<T> cmpX(vertices);
2107 const detail::less_than_y<T> cmpY(vertices);
2108
2109 while(!queue.empty())
2110 {
2111#ifdef CDT_ENABLE_CALLBACK_HANDLER
2112 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2113 {
2114 return;
2115 }
2116#endif
2117 tie(first, last, box.min, box.max, parent) = queue.front();
2118 queue.pop();
2119 assert(first != last);
2120
2121 const std::ptrdiff_t len = std::distance(first, last);
2122 if(len == 1)
2123 {
2124 insertVertex(*first, parent);
2125 continue;
2126 }
2127 const It midIt = first + len / 2;
2128 if(box.max.x - box.min.x >= box.max.y - box.min.y)
2129 {
2130 detail::portable_nth_element(first, midIt, last, cmpX);
2131 mid = *midIt;
2132 const T split = vertices[mid].x;
2133 newBoxMin.x = split;
2134 newBoxMin.y = box.min.y;
2135 newBoxMax.x = split;
2136 newBoxMax.y = box.max.y;
2137 }
2138 else
2139 {
2140 detail::portable_nth_element(first, midIt, last, cmpY);
2141 mid = *midIt;
2142 const T split = vertices[mid].y;
2143 newBoxMin.x = box.min.x;
2144 newBoxMin.y = split;
2145 newBoxMax.x = box.max.x;
2146 newBoxMax.y = split;
2147 }
2148 insertVertex(mid, parent);
2149 if(first != midIt)
2150 {
2151 queue.push(make_tuple(first, midIt, box.min, newBoxMax, mid));
2152 }
2153 if(midIt + 1 != last)
2154 {
2155 queue.push(make_tuple(midIt + 1, last, newBoxMin, box.max, mid));
2156 }
2157 }
2158}
2159
2160template <typename T, typename TNearPointLocator>
2161std::pair<TriInd, TriInd> Triangulation<T, TNearPointLocator>::edgeTriangles(
2162 const VertInd a,
2163 const VertInd b) const
2164{
2165 const TriInd triStart = m_vertTris[a];
2166 assert(triStart != noNeighbor);
2167 TriInd iT = triStart, iTNext = triStart;
2168 VertInd iV = noVertex;
2169 do
2170 {
2171 const Triangle& t = triangles[iT];
2172 tie(iTNext, iV) = t.next(a);
2173 assert(iTNext != noNeighbor);
2174 if(iV == b)
2175 {
2176 return std::make_pair(iT, iTNext);
2177 }
2178 iT = iTNext;
2179 } while(iT != triStart);
2180 return std::make_pair(noNeighbor, noNeighbor);
2181}
2182
2183template <typename T, typename TNearPointLocator>
2184bool Triangulation<T, TNearPointLocator>::hasEdge(
2185 const VertInd a,
2186 const VertInd b) const
2187{
2188 return edgeTriangles(a, b).first != invalidIndexSizeType;
2189}
2190
2191template <typename T, typename TNearPointLocator>
2192void Triangulation<T, TNearPointLocator>::setAdjacentTriangle(
2193 const VertInd v,
2194 const TriInd t)
2195{
2196 assert(t != noNeighbor);
2197 m_vertTris[v] = t;
2198 assert(
2199 triangles[t].vertices[0] == v || triangles[t].vertices[1] == v ||
2200 triangles[t].vertices[2] == v);
2201}
2202
2203template <typename T, typename TNearPointLocator>
2204void Triangulation<T, TNearPointLocator>::pivotVertexTriangleCW(const VertInd v)
2205{
2206 assert(m_vertTris[v] != noNeighbor);
2207 m_vertTris[v] = triangles[m_vertTris[v]].next(v).first;
2208 assert(m_vertTris[v] != noNeighbor);
2209 assert(
2210 triangles[m_vertTris[v]].vertices[0] == v ||
2211 triangles[m_vertTris[v]].vertices[1] == v ||
2212 triangles[m_vertTris[v]].vertices[2] == v);
2213}
2214
2215template <typename T, typename TNearPointLocator>
2216void Triangulation<T, TNearPointLocator>::tryAddVertexToLocator(const VertInd v)
2217{
2218 if(!m_nearPtLocator.empty()) // only if locator is initialized already
2219 m_nearPtLocator.addPoint(v, vertices);
2220}
2221
2222template <typename T, typename TNearPointLocator>
2223void Triangulation<T, TNearPointLocator>::tryInitNearestPointLocator()
2224{
2225 if(!vertices.empty() && m_nearPtLocator.empty())
2226 {
2227 m_nearPtLocator.initialize(vertices);
2228 }
2229}
2230
2231} // namespace CDT
2232
2233CDT_RESTORE_MATH_SETTINGS_FOR_CONSTRUCTIONS
2234
2235#endif // header-guard
Triangulation class.
void iota(ForwardIt first, ForwardIt last, T value)
backport from c++11
std::size_t maxQueueLengthBFSKDTree(const std::size_t vertexCount)
Since KD-tree bulk load builds a balanced tree the maximum length of a queue can be pre-calculated: i...
Base class for errors.
Interface for the callback handler that user can derive from and inject into the triangulation to mon...
Error thrown when intersecting constraint edges are detected, but triangulation is not configured to ...
Error thrown when resolving intersecting constraints fails: floating-point rounding places the comput...
void eraseOuterTriangles()
Erase triangles outside of constrained boundary using growing.
void conformToEdges(TEdgeIter first, TEdgeIter last, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd)
Insert constraint edges into triangulation for Conforming Delaunay Triangulation (for example see fig...
std::vector< LayerDepth > calculateTriangleDepths() const
Calculate depth of each triangle in constraint triangulation.
bool isFinalized() const
Check if the triangulation was finalized with erase... method and super-triangle was removed.
void eraseOuterTrianglesAndHoles()
Erase triangles outside of constrained boundary and auto-detected holes.
V2dVec vertices
triangulation's vertices
void insertEdges(TEdgeIter first, TEdgeIter last, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd)
Insert constraint edges into triangulation for Constrained Delaunay Triangulation (for example see fi...
void insertVertices(TVertexIter first, TVertexIter last, TGetVertexCoordX getX, TGetVertexCoordY getY)
Insert custom point-types specified by iterator range and X/Y-getters.
void eraseSuperTriangle()
Erase triangles adjacent to super triangle.
TriangleVec triangles
triangulation's triangles
Triangulation()
Default constructor.
void setCallbackHandler(ICallbackHandler *callbackHandler)
Set user-provided callback handler.
void initializedWithCustomSuperGeometry()
Call this method after directly setting custom super-geometry via vertices and triangles members.
unsigned short LayerDepth
Type used for storing layer depths for triangles.
Definition CDT.h:40
void flipEdge(TriInd iT, TriInd iTopo)
Flip an edge between two triangle.
TriIndVec & VertTrisInternal()
Access internal vertex adjacent triangles.
void removeTriangles(const TriIndUSet &removedTriangles)
Remove triangles with specified indices.
Namespace containing triangulation functionality.
std::vector< Edge > EdgeVec
Vector of edges.
Definition CDTUtils.h:386
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY VertInd opposedVertex(const Triangle &tri, TriInd iTopo)
Given two triangles, return vertex of first triangle opposed to the second.
Definition CDTUtils.hpp:205
unordered_set< Edge > EdgeUSet
Hash table of edges.
Definition CDTUtils.h:387
VertInd edge_get_v2(const Edge &e)
Get edge second vertex.
Definition CDTUtils.h:375
std::vector< TriInd > TriIndVec
Vector of triangle indices.
Definition CDTUtils.h:265
CDT_INLINE_IF_HEADER_ONLY Index edgeNeighborInd(const VerticesArr3 &vv, VertInd iVedge1, VertInd iVedge2)
Index of triangle's neighbor opposed to an edge.
Definition CDTUtils.hpp:143
VertInd edge_get_v1(const Edge &e)
Get edge first vertex.
Definition CDTUtils.h:369
CDT_EXPORT PtLineLocation::Enum classifyOrientation(T orientation, T orientationTolerance=T(0))
Classify value of orient2d predicate.
Definition CDTUtils.hpp:64
array< TriInd, 3 > NeighborsArr3
array of three neighbors
Definition CDTUtils.h:267
CDT_EXPORT T distance(const V2d< T > &a, const V2d< T > &b)
Distance between two 2D points.
Definition CDTUtils.hpp:252
IndexSizeType VertInd
Vertex index.
Definition CDTUtils.h:247
CDT_EXPORT Index cw(Index i)
Advance vertex or neighbor index clockwise.
Definition CDTUtils.hpp:28
array< VertInd, 3 > VerticesArr3
array of three vertex indices
Definition CDTUtils.h:266
CDT_INLINE_IF_HEADER_ONLY bool touchesSuperTriangle(const Triangle &t)
Check if any of triangle's vertices belongs to a super-triangle.
Definition CDTUtils.hpp:263
array< T, 3 > arr3(const T &v0, const T &v1, const T &v2)
Needed for c++03 compatibility (no uniform initialization available)
Definition CDTUtils.h:168
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoNbr(Index vertIndex)
Opposed neighbor index from vertex index.
Definition CDTUtils.hpp:106
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index vertexInd(const VerticesArr3 &vv, VertInd iV)
If triangle has a given vertex return vertex-index.
Definition CDTUtils.hpp:188
CDT_EXPORT T orient2D(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2)
Orient p against line v1-v2 2D: robust geometric predicate.
Definition CDTUtils.hpp:47
CDT_EXPORT PtLineLocation::Enum locatePointLine(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2, T orientationTolerance=T(0))
Check if point lies to the left of, to the right of, or on a line.
Definition CDTUtils.hpp:53
unordered_set< TriInd > TriIndUSet
Hash table of triangles.
Definition CDTUtils.h:388
CDT_EXPORT Index ccw(Index i)
Advance vertex or neighbor index counter-clockwise.
Definition CDTUtils.hpp:23
CDT_EXPORT Index edgeNeighbor(PtTriLocation::Enum location)
Neighbor index from a on-edge location.
Definition CDTUtils.hpp:40
unordered_map< TriInd, TriInd > TriIndUMap
Triangle hash map.
Definition CDTUtils.h:389
const T & getX_V2d(const V2d< T > &v)
X- coordinate getter for V2d.
Definition CDTUtils.h:204
unsigned char Index
Index in triangle.
Definition CDTUtils.h:245
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY TriInd opposedTriangle(const Triangle &tri, VertInd iVert)
Given triangle and a vertex find opposed triangle.
Definition CDTUtils.hpp:199
CDT_EXPORT bool isInCircumcircle(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2, const V2d< T > &v3)
Test if point lies in a circumscribed circle of a triangle.
Definition CDTUtils.hpp:218
Edge RemapNoSuperTriangle(const Edge &e)
Remap removing super-triangle: subtract 3 from vertices.
CDT_EXPORT bool isOnEdge(PtTriLocation::Enum location)
Check if location is classified as on any of three edges.
Definition CDTUtils.hpp:33
IndexSizeType TriInd
Triangle index.
Definition CDTUtils.h:249
CDT_EXPORT PtTriLocation::Enum locatePointTriangle(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2, const V2d< T > &v3)
Check if point a lies inside of, outside of, or on an edge of a triangle.
Definition CDTUtils.hpp:74
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opposedVertexInd(const NeighborsArr3 &nn, TriInd iTopo)
Index of triangle's vertex opposed to a triangle.
Definition CDTUtils.hpp:177
const T & getY_V2d(const V2d< T > &v)
Y-coordinate getter for V2d.
Definition CDTUtils.h:211
@ FixedEdgeMidpoint
During conforming triangulation edge mid-point is added.
@ FixedEdgesIntersection
Resolving fixed/constraint edges' intersection.
2D bounding box
Definition CDTUtils.h:272
V2d< T > max
max box corner
Definition CDTUtils.h:274
V2d< T > min
min box corner
Definition CDTUtils.h:273
Edge connecting two vertices: vertex with smaller index is always first.
Definition CDTUtils.h:327
VertInd v1() const
V1 getter.
Definition CDTUtils.h:347
VertInd v2() const
V2 getter.
Definition CDTUtils.h:353
@ TryResolve
attempt to resolve constraint edge intersections
@ NotAllowed
constraint edge intersections are not allowed
@ DontCheck
No checks: slightly faster but less safe.
Enum
The Enum itself.
@ SuperTriangle
conventional super-triangle
@ Custom
user-specified custom geometry (e.g., grid)
Triangulation triangle (counter-clockwise winding)
Definition CDTUtils.h:400
VerticesArr3 vertices
triangle's three vertices
Definition CDTUtils.h:401
NeighborsArr3 neighbors
triangle's three neighbors
Definition CDTUtils.h:402
std::pair< TriInd, VertInd > next(const VertInd i) const
Next triangle adjacent to a vertex (clockwise)
Definition CDTUtils.h:418
2D vector
Definition CDTUtils.h:185
T y
Y-coordinate.
Definition CDTUtils.h:187
T x
X-coordinate.
Definition CDTUtils.h:186
@ Auto
Automatic insertion order optimized for better performance.