9#ifndef CDT_pDqrlveWIOrIWeUCkPqX
10#define CDT_pDqrlveWIOrIWeUCkPqX
13#include "portable_nth_element.hpp"
21CDT_ENSURE_PRECISE_MATH_FOR_CONSTRUCTIONS
26typedef std::deque<TriInd> TriDeque;
34 return EdgeQueue(EdgeQueue::container_type(edges.begin(), edges.end()));
38template <
typename TVec>
41 std::sort(v.begin(), v.end());
42 v.erase(std::unique(v.begin(), v.end()), v.end());
52const float minDistToConstraintEdge(0);
67template <
typename T,
typename TNearPo
intLocator>
69 : m_vertexInsertionOrder(detail::defaults::vertexInsertionOrder)
70 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
71 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
72#ifdef CDT_ENABLE_CALLBACK_HANDLER
73 , m_callbackHandler(NULL)
77template <
typename T,
typename TNearPo
intLocator>
80 : m_vertexInsertionOrder(vertexInsertionOrder)
81 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
82 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
83#ifdef CDT_ENABLE_CALLBACK_HANDLER
84 , m_callbackHandler(NULL)
88template <
typename T,
typename TNearPo
intLocator>
92 const T minDistToConstraintEdge)
93 : m_vertexInsertionOrder(vertexInsertionOrder)
94 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
95 , m_minDistToConstraintEdge(minDistToConstraintEdge)
96#ifdef CDT_ENABLE_CALLBACK_HANDLER
97 , m_callbackHandler(NULL)
101template <
typename T,
typename TNearPo
intLocator>
104 const TNearPointLocator& nearPtLocator,
106 const T minDistToConstraintEdge)
107 : m_nearPtLocator(nearPtLocator)
108 , m_vertexInsertionOrder(vertexInsertionOrder)
109 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
110 , m_minDistToConstraintEdge(minDistToConstraintEdge)
111#ifdef CDT_ENABLE_CALLBACK_HANDLER
112 , m_callbackHandler(NULL)
116template <
typename T,
typename TNearPo
intLocator>
119 finalizeTriangulation(collectSuperTriangle());
122template <
typename T,
typename TNearPo
intLocator>
128template <
typename T,
typename TNearPo
intLocator>
134template <
typename T,
typename TNearPo
intLocator>
150template <
typename T,
typename TNearPo
intLocator>
156 assert(m_vertTris[0] != noNeighbor);
157 const std::stack<TriInd> seed(std::deque<TriInd>(1, m_vertTris[0]));
158 return growToBoundary(seed);
161template <
typename T,
typename TNearPo
intLocator>
171 for(std::size_t iT = 0; iT !=
triangles.size(); ++iT)
173 if(triDepths[iT] % 2 == 0)
174 toErase.insert(
static_cast<TriInd>(iT));
186template <
typename T,
typename TNearPo
intLocator>
190 if(removedTriangles.empty())
196 if(removedTriangles.count(iT))
198 triIndMap[iT] = iTnew;
209 for(NeighborsArr3::iterator n = nn.begin(); n != nn.end(); ++n)
211 if(removedTriangles.count(*n))
215 else if(*n != noNeighbor)
223template <
typename T,
typename TNearPo
intLocator>
229template <
typename T,
typename TNearPo
intLocator>
235template <
typename T,
typename TNearPo
intLocator>
248 typedef CDT::EdgeUSet::const_iterator It;
256 unordered_map<Edge, BoundaryOverlapCount> updatedOverlapCount;
257 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
260 updatedOverlapCount.insert(
266 unordered_map<Edge, EdgeVec> updatedPieceToOriginals;
267 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
272 for(EdgeVec::iterator eeIt = ee.begin(); eeIt != ee.end(); ++eeIt)
276 updatedPieceToOriginals.insert(
287 for(VerticesArr3::iterator v = vv.begin(); v != vv.end(); ++v)
289 *v -= nSuperTriVerts;
294template <
typename T,
typename TNearPo
intLocator>
295TriIndUSet Triangulation<T, TNearPointLocator>::growToBoundary(
296 std::stack<TriInd> seeds)
const
299 while(!seeds.empty())
301 const TriInd iT = seeds.top();
303 traversed.insert(iT);
308 if(fixedEdges.count(opEdge))
311 if(iN != noNeighbor && traversed.count(iN) == 0)
318template <
typename T,
typename TNearPo
intLocator>
319TriInd Triangulation<T, TNearPointLocator>::addTriangle(
const Triangle& t)
321 const TriInd iT = trianglesCount();
322 triangles.push_back(t);
326template <
typename T,
typename TNearPo
intLocator>
327TriInd Triangulation<T, TNearPointLocator>::addTriangle()
332template <
typename T,
typename TNearPo
intLocator>
333VertInd Triangulation<T, TNearPointLocator>::verticesCount()
const
335 return static_cast<VertInd>(vertices.size());
338template <
typename T,
typename TNearPo
intLocator>
339TriInd Triangulation<T, TNearPointLocator>::trianglesCount()
const
341 return static_cast<TriInd>(triangles.size());
344template <
typename T,
typename TNearPo
intLocator>
346 const std::vector<Edge>& edges)
351template <
typename T,
typename TNearPo
intLocator>
353 const std::vector<Edge>& edges)
358template <
typename T,
typename TNearPo
intLocator>
359void Triangulation<T, TNearPointLocator>::fixEdge(
const Edge& edge)
361 if(!fixedEdges.insert(edge).second)
363 ++overlapCount[edge];
371template <
typename T,
typename Allocator1>
372void insert_unique(std::vector<T, Allocator1>& to,
const T& elem)
374 if(std::find(to.begin(), to.end(), elem) == to.end())
381template <
typename T,
typename Allocator1,
typename Allocator2>
383 std::vector<T, Allocator1>& to,
384 const std::vector<T, Allocator2>& from)
386 typedef typename std::vector<T, Allocator2>::const_iterator Cit;
387 to.reserve(to.size() + from.size());
388 for(Cit cit = from.begin(); cit != from.end(); ++cit)
390 insert_unique(to, *cit);
396template <
typename T,
typename TNearPo
intLocator>
397void Triangulation<T, TNearPointLocator>::splitFixedEdge(
402 const Edge half1(edge.v1(), iSplitVert);
403 const Edge half2(iSplitVert, edge.v2());
405 fixedEdges.erase(edge);
409 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
410 const It overlapIt = overlapCount.find(edge);
411 if(overlapIt != overlapCount.end())
413 overlapCount[half1] += overlapIt->second;
414 overlapCount[half2] += overlapIt->second;
415 overlapCount.erase(overlapIt);
419 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
420 pieceToOriginals.find(edge);
421 if(originalsIt != pieceToOriginals.end())
423 newOriginals = originalsIt->second;
424 pieceToOriginals.erase(originalsIt);
426 detail::insert_unique(pieceToOriginals[half1], newOriginals);
427 detail::insert_unique(pieceToOriginals[half2], newOriginals);
430template <
typename T,
typename TNearPo
intLocator>
431VertInd Triangulation<T, TNearPointLocator>::addSplitEdgeVertex(
439 const VertInd iSplitVert = verticesCount();
440 addNewVertex(splitVert, noNeighbor);
442#ifdef CDT_ENABLE_CALLBACK_HANDLER
443 if(m_callbackHandler)
445 m_callbackHandler->onAddVertexStart(iSplitVert, vertexType);
451 std::stack<TriInd> triStack = insertVertexOnEdge(iSplitVert, iT, iTopo);
453 splitFixedEdge(edge, iSplitVert);
454 tryAddVertexToLocator(iSplitVert);
455 ensureDelaunayByEdgeFlips(iSplitVert, triStack);
459template <
typename T,
typename TNearPo
intLocator>
467 if(!isEdgeSplitVertexValid(splitVert, iT, iTopo))
470 addSplitEdgeVertex(edge, splitVert, iT, iTopo, vertexType);
474template <
typename T,
typename TNearPo
intLocator>
475bool Triangulation<T, TNearPointLocator>::isEdgeSplitVertexValid(
483 const V2d<T>& v1 = vertices[t1.vertices[i]];
484 const V2d<T>& v2 = vertices[t1.vertices[
ccw(i)]];
485 const V2d<T>& v4 = vertices[t1.vertices[
cw(i)]];
486 const Triangle& t2 = triangles[iTopo];
495template <
typename T,
typename TNearPo
intLocator>
496Edge Triangulation<T, TNearPointLocator>::originalInputEdge(
const Edge& e)
const
499 pieceToOriginals.count(e) ? pieceToOriginals.at(e).front() : e;
501 VertInd(orig.v1() - nSuperTriVerts),
502 VertInd(orig.v2() - nSuperTriVerts));
505template <
typename T,
typename TNearPo
intLocator>
507Triangulation<T, TNearPointLocator>::triangleAt(
const TriInd iT)
const
509 if(iT >=
TriInd(triangles.size()))
510 handleException(
Error(
512 ?
"Attempted reading no-neighbor sentinel value triangle"
513 :
"Triangle index " + CDT::to_string(iT) +
" out of range " +
514 CDT::to_string(triangles.size()),
515 CDT_SOURCE_LOCATION));
516 return triangles[iT];
519template <
typename T,
typename TNearPo
intLocator>
520void Triangulation<T, TNearPointLocator>::fixEdge(
522 const Edge& originalEdge)
525 if(edge != originalEdge)
526 detail::insert_unique(pieceToOriginals[edge], originalEdge);
533T lerp(
const T& a,
const T& b,
const T t)
535 return (T(1) - t) * a + t * b;
542 const T ux = a.
x - apex.
x, uy = a.
y - apex.
y;
543 const T wx = b.
x - apex.
x, wy = b.
y - apex.
y;
544 const T dot = ux * wx + uy * wy;
551V2d<T> intersectionPosition(
559 const T a_cd = predicates::orient2d(c.
x, c.
y, d.
x, d.
y, a.
x, a.
y);
560 const T b_cd = predicates::orient2d(c.
x, c.
y, d.
x, d.
y, b.
x, b.
y);
561 const T t_ab = a_cd / (a_cd - b_cd);
563 const T c_ab = predicates::orient2d(a.
x, a.
y, b.
x, b.
y, c.
x, c.
y);
564 const T d_ab = predicates::orient2d(a.
x, a.
y, b.
x, b.
y, d.
x, d.
y);
565 const T t_cd = c_ab / (c_ab - d_ab);
568 std::fabs(a.
x - b.
x) < std::fabs(c.
x - d.
x) ? lerp(a.
x, b.
x, t_ab)
569 : lerp(c.
x, d.
x, t_cd),
570 std::fabs(a.
y - b.
y) < std::fabs(c.
y - d.
y) ? lerp(a.
y, b.
y, t_ab)
571 : lerp(c.
y, d.
y, t_cd));
576template <
typename T,
typename TNearPo
intLocator>
577void Triangulation<T, TNearPointLocator>::insertEdgeIteration(
579 const Edge originalEdge,
581 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
588 const V2d<T>& a = vertices[iA];
589 const V2d<T>& b = vertices[iB];
590 const T distanceTolerance =
591 m_minDistToConstraintEdge == T(0)
593 : m_minDistToConstraintEdge *
distance(a, b);
597 const VertInd iV = opposedVertexOnEdge(edge, distanceTolerance);
600 remaining.push_back(
Edge(iV, iB));
601 remaining.push_back(
Edge(iA, iV));
604 fixEdge(edge, originalEdge);
611 tie(iT, iVL, iVR) = intersectedTriangle(iA, a, b, distanceTolerance);
615 remaining.push_back(
Edge(iVL, iB));
616 remaining.push_back(
Edge(iA, iVL));
620 std::vector<TriInd> intersected(1, iT);
621 std::vector<VertInd> polyL, polyR;
624 polyL.push_back(iVL);
627 polyR.push_back(iVR);
628 unordered_map<Edge, TriInd> outerTris;
633 while(!t.containsVertex(iB))
636 const Triangle& tOpo = triangleAt(iTopo);
639 switch(m_intersectingEdgesStrategy)
642 if(fixedEdges.count(
Edge(iVL, iVR)))
644 originalInputEdge(originalEdge),
645 originalInputEdge(
Edge(iVL, iVR)),
646 CDT_SOURCE_LOCATION));
650 if(!fixedEdges.count(
Edge(iVL, iVR)))
653 const V2d<T> newV = detail::intersectionPosition(
654 vertices[iA], vertices[iB], vertices[iVL], vertices[iVR]);
661 if(!splitVert.hasValue())
663 originalInputEdge(originalEdge),
664 originalInputEdge(
Edge(iVL, iVR)),
665 CDT_SOURCE_LOCATION));
666 const VertInd iNewVert = splitVert.value();
669 remaining.push_back(
Edge(iA, iNewVert));
670 remaining.push_back(
Edge(iNewVert, iB));
674 assert(!fixedEdges.count(
Edge(iVL, iVR)));
680 if(loc == PtLineLocation::Left)
682 const Edge e(polyL.back(), iVopo);
684 if(!outerTris.insert(std::make_pair(e, outer)).second)
685 outerTris.at(e) = noNeighbor;
686 polyL.push_back(iVopo);
690 else if(loc == PtLineLocation::Right)
692 const Edge e(polyR.back(), iVopo);
694 if(!outerTris.insert(std::make_pair(e, outer)).second)
695 outerTris.at(e) = noNeighbor;
696 polyR.push_back(iVopo);
703 intersected.push_back(iTopo);
712 assert(!intersected.empty());
715 if(m_vertTris[iA] == intersected.front())
716 pivotVertexTriangleCW(iA);
717 if(m_vertTris[iB] == intersected.back())
718 pivotVertexTriangleCW(iB);
721#ifdef CDT_ENABLE_CALLBACK_HANDLER
722 if(m_callbackHandler)
724 m_callbackHandler->onReTriangulatePolygon(intersected);
729 std::reverse(polyR.begin(), polyR.end());
734 assert(intersected.size() >= 2);
735 const TriInd iTL = intersected.back();
736 intersected.pop_back();
737 const TriInd iTR = intersected.back();
738 intersected.pop_back();
740 triangulatePseudoPolygon(
741 polyL, outerTris, iTL, iTR, intersected, tppIterations);
742 triangulatePseudoPolygon(
743 polyR, outerTris, iTR, iTL, intersected, tppIterations);
744 assert(intersected.empty());
750 const Edge edgePart(iA, iB);
751 fixEdge(edgePart, originalEdge);
752 remaining.push_back(
Edge(iB, edge.v2()));
757 fixEdge(edge, originalEdge);
761template <
typename T,
typename TNearPo
intLocator>
762void Triangulation<T, TNearPointLocator>::insertEdge(
764 const Edge originalEdge,
766 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
768#ifdef CDT_ENABLE_CALLBACK_HANDLER
769 if(m_callbackHandler)
771 m_callbackHandler->onAddEdgeStart(edge);
777 remaining.push_back(edge);
778 while(!remaining.empty())
780 edge = remaining.back();
781 remaining.pop_back();
782 insertEdgeIteration(edge, originalEdge, remaining, tppIterations);
786template <
typename T,
typename TNearPo
intLocator>
787void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
790 BoundaryOverlapCount overlaps,
791 std::vector<ConformToEdgeTask>& remaining)
798 const V2d<T>& a = vertices[iA];
799 const V2d<T>& b = vertices[iB];
800 const T distanceTolerance =
801 m_minDistToConstraintEdge == T(0)
803 : m_minDistToConstraintEdge *
distance(a, b);
807 const VertInd iV = opposedVertexOnEdge(edge, distanceTolerance);
810#ifdef CDT_CXX11_IS_SUPPORTED
811 remaining.emplace_back(
Edge(iV, iB), originals, overlaps);
812 remaining.emplace_back(
Edge(iA, iV), originals, overlaps);
814 remaining.push_back(make_tuple(
Edge(iV, iB), originals, overlaps));
815 remaining.push_back(make_tuple(
Edge(iA, iV), originals, overlaps));
821 overlapCount[edge] = overlaps;
823 if(!originals.empty() && edge != originals.front())
825 detail::insert_unique(pieceToOriginals[edge], originals);
832 tie(iT, iVleft, iVright) = intersectedTriangle(iA, a, b, distanceTolerance);
836#ifdef CDT_CXX11_IS_SUPPORTED
837 remaining.emplace_back(
Edge(iVleft, iB), originals, overlaps);
838 remaining.emplace_back(
Edge(iA, iVleft), originals, overlaps);
840 remaining.push_back(make_tuple(
Edge(iVleft, iB), originals, overlaps));
841 remaining.push_back(make_tuple(
Edge(iA, iVleft), originals, overlaps));
848 while(std::find(t.vertices.begin(), t.vertices.end(), iB) ==
852 const Triangle& tOpo = triangleAt(iTopo);
854 const V2d<T> vOpo = vertices[iVopo];
856 switch(m_intersectingEdgesStrategy)
859 if(fixedEdges.count(
Edge(iVleft, iVright)))
861 originalInputEdge(edge),
862 originalInputEdge(
Edge(iVleft, iVright)),
863 CDT_SOURCE_LOCATION));
867 if(!fixedEdges.count(
Edge(iVleft, iVright)))
870 const V2d<T> newV = detail::intersectionPosition(
876 Edge(iVleft, iVright),
881 if(!splitVert.hasValue())
883 originalInputEdge(edge),
884 originalInputEdge(
Edge(iVleft, iVright)),
885 CDT_SOURCE_LOCATION));
886 const VertInd iNewVert = splitVert.value();
887#ifdef CDT_CXX11_IS_SUPPORTED
888 remaining.emplace_back(
Edge(iNewVert, iB), originals, overlaps);
889 remaining.emplace_back(
Edge(iA, iNewVert), originals, overlaps);
892 make_tuple(
Edge(iNewVert, iB), originals, overlaps));
894 make_tuple(
Edge(iA, iNewVert), originals, overlaps));
899 assert(!fixedEdges.count(
Edge(iVleft, iVright)));
908 if(loc == PtLineLocation::Left)
913 else if(loc == PtLineLocation::Right)
925#ifdef CDT_CXX11_IS_SUPPORTED
926 remaining.emplace_back(
Edge(iB, edge.v2()), originals, overlaps);
929 make_tuple(
Edge(iB, edge.v2()), originals, overlaps));
934 const VertInd iMid = verticesCount();
935 const V2d<T>& start = vertices[iA];
936 const V2d<T>& end = vertices[iB];
938 V2d<T>((start.x + end.x) / T(2), (start.y + end.y) / T(2)), noNeighbor);
940#ifdef CDT_ENABLE_CALLBACK_HANDLER
941 if(m_callbackHandler)
943 m_callbackHandler->onAddVertexStart(
948 const std::vector<Edge> flippedFixedEdges =
949 insertVertex_FlipFixedEdges(iMid);
951#ifdef CDT_CXX11_IS_SUPPORTED
952 remaining.emplace_back(
Edge(iMid, iB), originals, overlaps);
953 remaining.emplace_back(
Edge(iA, iMid), originals, overlaps);
955 remaining.push_back(make_tuple(
Edge(iMid, iB), originals, overlaps));
956 remaining.push_back(make_tuple(
Edge(iA, iMid), originals, overlaps));
961 for(std::vector<Edge>::const_iterator it = flippedFixedEdges.begin();
962 it != flippedFixedEdges.end();
965 const Edge& flippedFixedEdge = *it;
966 fixedEdges.erase(flippedFixedEdge);
968 BoundaryOverlapCount prevOverlaps = 0;
969 const unordered_map<Edge, BoundaryOverlapCount>::const_iterator
970 overlapsIt = overlapCount.find(flippedFixedEdge);
971 if(overlapsIt != overlapCount.end())
973 prevOverlaps = overlapsIt->second;
974 overlapCount.erase(overlapsIt);
977 EdgeVec prevOriginals(1, flippedFixedEdge);
978 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
979 pieceToOriginals.find(flippedFixedEdge);
980 if(originalsIt != pieceToOriginals.end())
982 prevOriginals = originalsIt->second;
984#ifdef CDT_CXX11_IS_SUPPORTED
985 remaining.emplace_back(flippedFixedEdge, prevOriginals, prevOverlaps);
988 make_tuple(flippedFixedEdge, prevOriginals, prevOverlaps));
993template <
typename T,
typename TNearPo
intLocator>
994void Triangulation<T, TNearPointLocator>::conformToEdge(
997 BoundaryOverlapCount overlaps,
998 std::vector<ConformToEdgeTask>& remaining)
1000#ifdef CDT_ENABLE_CALLBACK_HANDLER
1001 if(m_callbackHandler)
1003 m_callbackHandler->onAddEdgeStart(edge);
1009#ifdef CDT_CXX11_IS_SUPPORTED
1010 remaining.emplace_back(edge, originals, overlaps);
1012 remaining.push_back(make_tuple(edge, originals, overlaps));
1014 while(!remaining.empty())
1016 tie(edge, originals, overlaps) = remaining.back();
1017 remaining.pop_back();
1018 conformToEdgeIteration(edge, originals, overlaps, remaining);
1032template <
typename T,
typename TNearPo
intLocator>
1033tuple<TriInd, VertInd, VertInd>
1034Triangulation<T, TNearPointLocator>::intersectedTriangle(
1038 const T orientationTolerance)
const
1040 const TriInd startTri = m_vertTris[iA];
1047 const T orientP2 =
orient2D(vertices[iP2], a, b);
1049 if(locP2 == PtLineLocation::Right)
1052 const T orientP1 =
orient2D(vertices[iP1], a, b);
1054 if(locP1 == PtLineLocation::OnLine)
1056 return make_tuple(noNeighbor, iP1, iP1);
1058 if(locP1 == PtLineLocation::Left)
1060 if(orientationTolerance)
1064 if(std::abs(orientP1) <= std::abs(orientP2))
1066 closestOrient = orientP1;
1071 closestOrient = orientP2;
1075 closestOrient, orientationTolerance) ==
1076 PtLineLocation::OnLine)
1078 return make_tuple(noNeighbor, iClosestP, iClosestP);
1081 return make_tuple(iT, iP1, iP2);
1084 iT = t.next(iA).first;
1085 }
while(iT != startTri);
1087 handleException(
Error(
1088 "Could not find vertex triangle intersected by an edge.",
1089 CDT_SOURCE_LOCATION));
1090 return make_tuple(noNeighbor, noVertex, noVertex);
1093template <
typename T,
typename TNearPo
intLocator>
1094void Triangulation<T, TNearPointLocator>::addSuperTriangle(
const Box2d<T>& box)
1097 (box.min.x + box.max.x) / T(2), (box.min.y + box.max.y) / T(2));
1098 const T w = box.max.x - box.min.x;
1099 const T h = box.max.y - box.min.y;
1100 T r = std::max(w, h);
1105 r = std::max(T(2) * r, T(1));
1111 while(center.y <= center.y - r)
1115 const T R = T(2) * r;
1116 const T cos_30_deg = T(0.8660254037844386);
1117 const T shiftX = R * cos_30_deg;
1118 const V2d<T> posV1(center.x - shiftX, center.y - r);
1119 const V2d<T> posV2(center.x + shiftX, center.y - r);
1120 const V2d<T> posV3(center.x, center.y + R);
1121 addNewVertex(posV1,
TriInd(0));
1122 addNewVertex(posV2,
TriInd(0));
1123 addNewVertex(posV3,
TriInd(0));
1125#ifdef CDT_ENABLE_CALLBACK_HANDLER
1126 if(m_callbackHandler)
1128 m_callbackHandler->onAddSuperTriangle();
1137 m_nearPtLocator.initialize(vertices);
1141template <
typename T,
typename TNearPo
intLocator>
1142void Triangulation<T, TNearPointLocator>::addNewVertex(
1146 vertices.push_back(pos);
1147 m_vertTris.push_back(iT);
1150template <
typename T,
typename TNearPo
intLocator>
1152Triangulation<T, TNearPointLocator>::insertVertex_FlipFixedEdges(
1155 std::vector<Edge> flippedFixedEdges;
1157 const V2d<T>& v1 = vertices[iV1];
1158 const VertInd startVertex = m_nearPtLocator.nearPoint(v1, vertices);
1159 array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iV1, startVertex);
1160 std::stack<TriInd> triStack =
1161 trisAt[1] == noNeighbor ? insertVertexInsideTriangle(iV1, trisAt[0])
1162 : insertVertexOnEdge(iV1, trisAt[0], trisAt[1]);
1164 TriInd iTopo, n1, n2, n3, n4;
1166 while(!triStack.empty())
1168 const TriInd iT = triStack.top();
1171 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1172 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4, true))
1175 const Edge flippedEdge(iV2, iV4);
1176 if(!fixedEdges.empty() &&
1177 fixedEdges.find(flippedEdge) != fixedEdges.end())
1179 flippedFixedEdges.push_back(flippedEdge);
1182 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1184 triStack.push(iTopo);
1188 tryAddVertexToLocator(iV1);
1189 return flippedFixedEdges;
1192template <
typename T,
typename TNearPo
intLocator>
1193void Triangulation<T, TNearPointLocator>::insertVertex(
1194 const VertInd iVert,
1195 const VertInd walkStart)
1197#ifdef CDT_ENABLE_CALLBACK_HANDLER
1198 if(m_callbackHandler)
1200 m_callbackHandler->onAddVertexStart(iVert, AddVertexType::UserInput);
1204 const array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iVert, walkStart);
1205 std::stack<TriInd> triStack =
1206 trisAt[1] == noNeighbor
1207 ? insertVertexInsideTriangle(iVert, trisAt[0])
1208 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1], true);
1209 ensureDelaunayByEdgeFlips(iVert, triStack);
1212template <
typename T,
typename TNearPo
intLocator>
1213void Triangulation<T, TNearPointLocator>::insertVertex(
const VertInd iVert)
1215 const V2d<T>& v = vertices[iVert];
1216 const VertInd walkStart = m_nearPtLocator.nearPoint(v, vertices);
1217 insertVertex(iVert, walkStart);
1218 tryAddVertexToLocator(iVert);
1221template <
typename T,
typename TNearPo
intLocator>
1222void Triangulation<T, TNearPointLocator>::ensureDelaunayByEdgeFlips(
1224 std::stack<TriInd>& triStack)
1226 TriInd iTopo, n1, n2, n3, n4;
1228 while(!triStack.empty())
1230 const TriInd iT = triStack.top();
1233 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1234 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1236 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1238 triStack.push(iTopo);
1256template <
typename T,
typename TNearPo
intLocator>
1257void Triangulation<T, TNearPointLocator>::edgeFlipInfo(
1274 const Triangle& t = triangles[iT];
1275 if(t.vertices[0] == iV1)
1277 iV2 = t.vertices[1];
1278 iV4 = t.vertices[2];
1279 n1 = t.neighbors[0];
1280 n3 = t.neighbors[2];
1281 iTopo = t.neighbors[1];
1283 else if(t.vertices[1] == iV1)
1285 iV2 = t.vertices[2];
1286 iV4 = t.vertices[0];
1287 n1 = t.neighbors[1];
1288 n3 = t.neighbors[0];
1289 iTopo = t.neighbors[2];
1293 iV2 = t.vertices[0];
1294 iV4 = t.vertices[1];
1295 n1 = t.neighbors[2];
1296 n3 = t.neighbors[1];
1297 iTopo = t.neighbors[0];
1299 if(iTopo == noNeighbor)
1301 const Triangle& tOpo = triangles[iTopo];
1302 if(tOpo.neighbors[0] == iT)
1304 iV3 = tOpo.vertices[2];
1305 n2 = tOpo.neighbors[1];
1306 n4 = tOpo.neighbors[2];
1308 else if(tOpo.neighbors[1] == iT)
1310 iV3 = tOpo.vertices[0];
1311 n2 = tOpo.neighbors[2];
1312 n4 = tOpo.neighbors[0];
1316 iV3 = tOpo.vertices[1];
1317 n2 = tOpo.neighbors[0];
1318 n4 = tOpo.neighbors[1];
1322template <
typename T,
typename TNearPo
intLocator>
1323bool Triangulation<T, TNearPointLocator>::isSameOriginalEdge(
1325 const Edge& e2)
const
1327 if(!fixedEdges.count(e1) || !fixedEdges.count(e2))
1329 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
1330 const It it1 = pieceToOriginals.find(e1);
1331 const It it2 = pieceToOriginals.find(e2);
1332 return (it1 == pieceToOriginals.end() ? e1 : it1->second.front()) ==
1333 (it2 == pieceToOriginals.end() ? e2 : it2->second.front());
1359template <
typename T,
typename TNearPo
intLocator>
1360bool Triangulation<T, TNearPointLocator>::isFlipNeeded(
1365 const bool doFlipFixedEdges)
const
1367 if(!doFlipFixedEdges && fixedEdges.count(Edge(iV2, iV4)))
1370 if(!fixedEdges.empty() &&
1371 (isSameOriginalEdge(Edge(iV1, iV2), Edge(iV2, iV3)) ||
1372 isSameOriginalEdge(Edge(iV3, iV4), Edge(iV4, iV1))))
1374 const V2d<T>& v1 = vertices[iV1];
1375 const V2d<T>& v2 = vertices[iV2];
1376 const V2d<T>& v3 = vertices[iV3];
1377 const V2d<T>& v4 = vertices[iV4];
1382 if(iV1 < nSuperTriVerts)
1385 if(iV2 < nSuperTriVerts)
1387 if(iV4 < nSuperTriVerts)
1391 if(iV3 < nSuperTriVerts)
1394 if(iV2 < nSuperTriVerts)
1398 if(iV4 < nSuperTriVerts)
1405 if(iV2 < nSuperTriVerts)
1407 if(iV4 < nSuperTriVerts)
1428template <
typename T,
typename TNearPo
intLocator>
1433#ifdef CDT_ENABLE_CALLBACK_HANDLER
1434 if(m_callbackHandler)
1436 m_callbackHandler->onFlipEdge(iT, iTopo);
1442 const array<TriInd, 3>& triNs = t.
neighbors;
1443 const array<TriInd, 3>& triOpoNs = tOpo.
neighbors;
1444 const array<VertInd, 3>& triVs = t.
vertices;
1445 const array<VertInd, 3>& triOpoVs = tOpo.
vertices;
1450 const TriInd n1 = triNs[i];
1453 const VertInd v3 = triOpoVs[i];
1455 const TriInd n4 = triOpoNs[i];
1461 changeNeighbor(n1, iT, iTopo);
1462 changeNeighbor(n4, iTopo, iT);
1468 setAdjacentTriangle(v4, iT);
1469 setAdjacentTriangle(v2, iTopo);
1473template <
typename T,
typename TNearPo
intLocator>
1474bool Triangulation<T, TNearPointLocator>::isRefinementNeeded(
1477 const T refinementThreshold)
const
1482 switch(refinementCriterion)
1487 return area(a, b, c) > refinementThreshold;
1493template <
typename T,
typename TNearPo
intLocator>
1494bool Triangulation<T, TNearPointLocator>::isSmallestAngleFixed(
1495 const Triangle& tri)
const
1499 vertices[tri.vertices[
ccw(
Index(0))]],
1500 vertices[tri.vertices[
cw(
Index(0))]]);
1501 for(Index i(1); i <
Index(3); ++i)
1504 vertices[tri.vertices[
ccw(i)]], vertices[tri.vertices[
cw(i)]]);
1505 if(sqLen < shortestSqLen)
1507 shortestSqLen = sqLen;
1511 const VertInd apex = tri.vertices[iApex];
1512 return fixedEdges.count(Edge(apex, tri.vertices[
ccw(iApex)])) &&
1513 fixedEdges.count(Edge(apex, tri.vertices[
cw(iApex)]));
1516template <
typename T,
typename TNearPo
intLocator>
1517bool Triangulation<T, TNearPointLocator>::isEdgeEncroached(
1518 const Edge& edge)
const
1521 tie(iT, iTopo) = edgeTriangles(edge.v1(), edge.v2());
1522 assert(iT != noNeighbor && iTopo != noNeighbor);
1525 const V2d<T>& edgeStart = vertices[edge.v1()];
1526 const V2d<T>& edgeEnd = vertices[edge.v2()];
1527 return detail::isEncroachingOnEdge(vertices[v1], edgeStart, edgeEnd) ||
1528 detail::isEncroachingOnEdge(vertices[v2], edgeStart, edgeEnd);
1531template <
typename T,
typename TNearPo
intLocator>
1532bool Triangulation<T, TNearPointLocator>::isEdgeEncroachedBy(
1534 const V2d<T>& v)
const
1536 return detail::isEncroachingOnEdge(
1537 v, vertices[edge.v1()], vertices[edge.v2()]);
1540template <
typename T,
typename TNearPo
intLocator>
1548 typedef EdgeUSet::const_iterator Iter;
1551 const Edge edge = *it;
1552 if(isEdgeEncroached(edge))
1554 encroachedEdges.push_back(edge);
1559 std::sort(encroachedEdges.begin(), encroachedEdges.end());
1560 return encroachedEdges;
1563template <
typename T,
typename TNearPo
intLocator>
1566 const T refinementThreshold)
const
1575 if(isRefinementNeeded(t, refinementCriterion, refinementThreshold))
1576 unrefinedTriangles.push_back(iT);
1578 return unrefinedTriangles;
1581template <
typename T,
typename TNearPo
intLocator>
1582EdgeVec Triangulation<T, TNearPointLocator>::edgesEncroachedBy(
1596 std::stack<TriInd> toTraverse;
1597 toTraverse.push(iT);
1598 traversed.insert(iT);
1599 while(!toTraverse.empty())
1601 const Triangle& t = triangles[toTraverse.top()];
1606 if(fixedEdges.count(opEdge))
1609 if(isEdgeEncroachedBy(opEdge, v))
1610 detail::insert_unique(encroachedEdges, opEdge);
1613 const TriInd iN = t.
neighbors[opoNbr(i)];
1614 if(iN == noNeighbor || traversed.count(iN))
1616 const Triangle& n = triangles[iN];
1617 if(!isInCircumcircle(
1619 vertices[n.vertices[0]],
1620 vertices[n.vertices[1]],
1621 vertices[n.vertices[2]]))
1623 traversed.insert(iN);
1624 toTraverse.push(iN);
1627 return encroachedEdges;
1630template <
typename T,
typename TNearPo
intLocator>
1631TriIndVec Triangulation<T, TNearPointLocator>::resolveEncroachedEdges(
1632 EdgeQueue encroachedEdges,
1633 VertInd& remainingVertexBudget,
1634 const VertInd steinerVerticesOffset,
1635 const V2d<T>*
const circumcenterOrNull,
1636 const RefinementCriterion::Enum refinementCriterion,
1637 const T badTriangleThreshold,
1638 TriIndUSet*
const toEraseOrNull,
1639 const T minEdgeLength,
1640 Unrefined& unrefined)
1642 std::vector<TriInd> badTriangles;
1644 while(!encroachedEdges.empty() && remainingVertexBudget > 0)
1646 const Edge edge = encroachedEdges.front();
1647 encroachedEdges.pop();
1648 if(fixedEdges.find(edge) == fixedEdges.end())
1653 if(
distance(vertices[edge.v1()], vertices[edge.v2()]) <= minEdgeLength)
1655 ++unrefined.shortEdges;
1660 edge, steinerVerticesOffset, toEraseOrNull, unrefined);
1661 if(!splitVert.hasValue())
1663 const VertInd iSplitVert = splitVert.value();
1664 --remainingVertexBudget;
1666 const TriInd start = m_vertTris[iSplitVert];
1670 const Triangle& t = triangles[iT];
1671 const bool isMarkedForErasure =
1672 toEraseOrNull && toEraseOrNull->count(iT);
1673 if(circumcenterOrNull && !isMarkedForErasure &&
1675 isRefinementNeeded(t, refinementCriterion, badTriangleThreshold))
1677 badTriangles.push_back(iT);
1679 for(Index i(0); i <
Index(3); ++i)
1681 const Edge triEdge(t.vertices[i], t.vertices[
cw(i)]);
1682 if(fixedEdges.find(triEdge) == fixedEdges.end())
1684 if(isEdgeEncroached(triEdge) ||
1685 (circumcenterOrNull &&
1686 isEdgeEncroachedBy(triEdge, *circumcenterOrNull)))
1688 encroachedEdges.push(triEdge);
1691 iT = t.
next(iSplitVert).first;
1692 }
while(iT != start);
1694 return badTriangles;
1697template <
typename T,
typename TNearPo
intLocator>
1698OptionalVertInd Triangulation<T, TNearPointLocator>::splitEncroachedEdge(
1700 const VertInd steinerVerticesOffset,
1701 TriIndUSet*
const toEraseOrNull,
1702 Unrefined& unrefined)
1704 const V2d<T>& start = vertices[edge.v1()];
1705 const V2d<T>& end = vertices[edge.v2()];
1708 tie(iT, iTopo) = edgeTriangles(edge.v1(), edge.v2());
1709 assert(iT != noNeighbor && iTopo != noNeighbor);
1714 if(edge.v1() < steinerVerticesOffset &&
1715 edge.v2() >= steinerVerticesOffset &&
1716 hasAnotherFixedEdgeAtSmallAngle(edge.v1(), edge))
1720 const T len =
distance(start, end);
1721 const T d = len / T(2);
1723 T nearestPowerOfTwo = T(1);
1724 while(d > nearestPowerOfTwo)
1726 nearestPowerOfTwo *= T(2);
1728 while(d < T(0.75) * nearestPowerOfTwo)
1730 nearestPowerOfTwo *= T(0.5);
1732 split = nearestPowerOfTwo / len;
1735 const V2d<T> mid = V2d<T>(
1736 detail::lerp(start.x, end.x, split),
1737 detail::lerp(start.y, end.y, split));
1740 edge, mid, iT, iTopo, AddVertexType::RefinementEdgeSplit);
1741 if(!iMid.hasValue())
1743 ++unrefined.splitVertexInvalid;
1745 else if(toEraseOrNull)
1749 if(toEraseOrNull->count(iT))
1750 toEraseOrNull->insert(
TriInd(triangles.size() - 2));
1751 if(toEraseOrNull->count(iTopo))
1752 toEraseOrNull->insert(
TriInd(triangles.size() - 1));
1773template <
typename T,
typename TNearPo
intLocator>
1786#ifdef CDT_ENABLE_CALLBACK_HANDLER
1787 if(m_callbackHandler)
1789 m_callbackHandler->onFlipEdge(iT, iTopo);
1797 changeNeighbor(n1, iT, iTopo);
1798 changeNeighbor(n4, iTopo, iT);
1804 setAdjacentTriangle(v4, iT);
1805 setAdjacentTriangle(v2, iTopo);
1825template <
typename T,
typename TNearPo
intLocator>
1827Triangulation<T, TNearPointLocator>::insertVertexInsideTriangle(
1831 const TriInd iNewT1 = addTriangle();
1832 const TriInd iNewT2 = addTriangle();
1834#ifdef CDT_ENABLE_CALLBACK_HANDLER
1835 if(m_callbackHandler)
1837 m_callbackHandler->onInsertVertexInsideTriangle(iT, iNewT1, iNewT2);
1841 Triangle& t = triangles[iT];
1842 const array<VertInd, 3> vv = t.vertices;
1843 const array<TriInd, 3> nn = t.neighbors;
1844 const VertInd v1 = vv[0], v2 = vv[1], v3 = vv[2];
1845 const TriInd n1 = nn[0], n2 = nn[1], n3 = nn[2];
1848 triangles[iNewT1] = Triangle(arr3(v2, v3, v), arr3(n2, iNewT2, iT));
1849 triangles[iNewT2] = Triangle(arr3(v3, v1, v), arr3(n3, iT, iNewT1));
1850 t = Triangle(arr3(v1, v2, v), arr3(n1, iNewT1, iNewT2));
1852 setAdjacentTriangle(v, iT);
1853 setAdjacentTriangle(v3, iNewT1);
1855 changeNeighbor(n2, iT, iNewT1);
1856 changeNeighbor(n3, iT, iNewT2);
1858 std::stack<TriInd> newTriangles;
1859 newTriangles.push(iT);
1860 newTriangles.push(iNewT1);
1861 newTriangles.push(iNewT2);
1862 return newTriangles;
1878template <
typename T,
typename TNearPo
intLocator>
1879std::stack<TriInd> Triangulation<T, TNearPointLocator>::insertVertexOnEdge(
1883 const bool doHandleFixedSplitEdge)
1885 const TriInd iTnew1 = addTriangle();
1886 const TriInd iTnew2 = addTriangle();
1888#ifdef CDT_ENABLE_CALLBACK_HANDLER
1889 if(m_callbackHandler)
1891 m_callbackHandler->onInsertVertexOnEdge(iT1, iT2, iTnew1, iTnew2);
1895 Triangle& t1 = triangles[iT1];
1896 Triangle& t2 = triangles[iT2];
1898 const VertInd v1 = t1.vertices[i];
1900 const TriInd n1 = t1.neighbors[i];
1901 const TriInd n4 = t1.neighbors[
cw(i)];
1903 const VertInd v3 = t2.vertices[i];
1905 const TriInd n3 = t2.neighbors[i];
1906 const TriInd n2 = t2.neighbors[
cw(i)];
1908 t1 = Triangle(
arr3(v, v1, v2),
arr3(iTnew1, n1, iT2));
1909 t2 = Triangle(
arr3(v, v2, v3),
arr3(iT1, n2, iTnew2));
1910 triangles[iTnew1] = Triangle(
arr3(v, v4, v1),
arr3(iTnew2, n4, iT1));
1911 triangles[iTnew2] = Triangle(
arr3(v, v3, v4),
arr3(iT2, n3, iTnew1));
1913 setAdjacentTriangle(v, iT1);
1914 setAdjacentTriangle(v4, iTnew1);
1916 changeNeighbor(n4, iT1, iTnew1);
1917 changeNeighbor(n3, iT2, iTnew2);
1919 if(doHandleFixedSplitEdge)
1921 const Edge sharedEdge(v2, v4);
1922 if(fixedEdges.count(sharedEdge))
1923 splitFixedEdge(sharedEdge, v);
1926 std::stack<TriInd> newTriangles;
1927 newTriangles.push(iT1);
1928 newTriangles.push(iTnew2);
1929 newTriangles.push(iT2);
1930 newTriangles.push(iTnew1);
1931 return newTriangles;
1934template <
typename T,
typename TNearPo
intLocator>
1936Triangulation<T, TNearPointLocator>::trianglesAt(
const V2d<T>& pos)
const
1938 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1939 for(TriInd i =
TriInd(0); i <
TriInd(triangles.size()); ++i)
1941 const Triangle& t = triangles[i];
1942 const V2d<T>& v1 = vertices[t.vertices[0]];
1943 const V2d<T>& v2 = vertices[t.vertices[1]];
1944 const V2d<T>& v3 = vertices[t.vertices[2]];
1946 if(loc == PtTriLocation::Outside)
1954 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
1958template <
typename T,
typename TNearPo
intLocator>
1959OptionalTriInd Triangulation<T, TNearPointLocator>::walkTriangles(
1960 const VertInd startVertex,
1961 const V2d<T>& pos)
const
1964 TriInd currTri = m_vertTris[startVertex];
1966 bool isOutside =
false;
1967 detail::SplitMix64RandGen prng;
1970 const Triangle& t = triangles[currTri];
1974 const Index offset(prng() % 3);
1975 for(Index i_(0); i_ <
Index(3); ++i_)
1977 const Index i((i_ + offset) % 3);
1978 const V2d<T>& vStart = vertices[t.vertices[i]];
1979 const V2d<T>& vEnd = vertices[t.vertices[
ccw(i)]];
1980 const PtLineLocation::Enum edgeCheck =
1982 const TriInd iN = t.neighbors[i];
1983 if(edgeCheck == PtLineLocation::Right)
1985 if(iN != noNeighbor)
2000template <
typename T,
typename TNearPo
intLocator>
2001array<TriInd, 2> Triangulation<T, TNearPointLocator>::walkingSearchTrianglesAt(
2003 const VertInd startVertex)
const
2005 const V2d<T> v = vertices[iV];
2006 array<TriInd, 2> out = {noNeighbor, noNeighbor};
2008 if(!walkResult.hasValue())
2011 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
2013 const TriInd iT = walkResult.value();
2015 const Triangle& t = triangles[iT];
2016 const V2d<T>& v1 = vertices[t.vertices[0]];
2017 const V2d<T>& v2 = vertices[t.vertices[1]];
2018 const V2d<T>& v3 = vertices[t.vertices[2]];
2021 if(loc == PtTriLocation::Outside)
2024 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
2026 if(loc == PtTriLocation::OnVertex)
2028 const VertInd iDupe = v1 == v ? t.vertices[0]
2029 : v2 == v ? t.vertices[1]
2031 handleException(DuplicateVertexError(
2033 VertInd(iDupe - nSuperTriVerts),
2034 CDT_SOURCE_LOCATION));
2043template <
typename T,
typename TNearPo
intLocator>
2044void Triangulation<T, TNearPointLocator>::changeNeighbor(
2046 const TriInd oldNeighbor,
2047 const TriInd newNeighbor)
2049 if(iT == noNeighbor)
2053 nn[0] == oldNeighbor || nn[1] == oldNeighbor || nn[2] == oldNeighbor);
2054 if(nn[0] == oldNeighbor)
2055 nn[0] = newNeighbor;
2056 else if(nn[1] == oldNeighbor)
2057 nn[1] = newNeighbor;
2059 nn[2] = newNeighbor;
2062template <
typename T,
typename TNearPo
intLocator>
2063void Triangulation<T, TNearPointLocator>::changeNeighbor(
2065 const VertInd iVedge1,
2066 const VertInd iVedge2,
2067 const TriInd newNeighbor)
2069 assert(iT != noNeighbor);
2070 Triangle& t = triangles[iT];
2071 t.neighbors[
edgeNeighborInd(t.vertices, iVedge1, iVedge2)] = newNeighbor;
2074template <
typename T,
typename TNearPo
intLocator>
2075void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygon(
2076 const std::vector<VertInd>& poly,
2077 unordered_map<Edge, TriInd>& outerTris,
2080 std::vector<TriInd>& trianglesToReuse,
2081 std::vector<TriangulatePseudoPolygonTask>& iterations)
2083 assert(poly.size() > 2);
2086 iterations.push_back(make_tuple(
2088 static_cast<IndexSizeType
>(poly.size() - 1),
2092 while(!iterations.empty())
2094 triangulatePseudoPolygonIteration(
2095 poly, outerTris, trianglesToReuse, iterations);
2099template <
typename T,
typename TNearPo
intLocator>
2100void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygonIteration(
2101 const std::vector<VertInd>& poly,
2102 unordered_map<Edge, TriInd>& outerTris,
2103 std::vector<TriInd>& trianglesToReuse,
2104 std::vector<TriangulatePseudoPolygonTask>& iterations)
2106 IndexSizeType iA, iB;
2109 assert(!iterations.empty());
2110 tie(iA, iB, iT, iParent, iInParent) = iterations.back();
2111 iterations.pop_back();
2112 assert(iB - iA > 1 && iT != noNeighbor && iParent != noNeighbor);
2113 Triangle& t = triangles[iT];
2115 const IndexSizeType iC = findDelaunayPoint(poly, iA, iB);
2127 assert(!trianglesToReuse.empty());
2128 const TriInd iNext = trianglesToReuse.back();
2129 trianglesToReuse.pop_back();
2130 iterations.push_back(make_tuple(iC, iB, iNext, iT,
Index(1)));
2134 const Edge outerEdge(b, c);
2135 const TriInd outerTri = outerTris.at(outerEdge);
2136 if(outerTri != noNeighbor)
2138 assert(outerTri != iT);
2139 t.neighbors[1] = outerTri;
2140 changeNeighbor(outerTri, c, b, iT);
2143 outerTris.at(outerEdge) = iT;
2148 assert(!trianglesToReuse.empty());
2149 const TriInd iNext = trianglesToReuse.back();
2150 trianglesToReuse.pop_back();
2151 iterations.push_back(make_tuple(iA, iC, iNext, iT,
Index(2)));
2155 const Edge outerEdge(c, a);
2156 const TriInd outerTri = outerTris.at(outerEdge);
2157 if(outerTri != noNeighbor)
2159 assert(outerTri != iT);
2160 t.neighbors[2] = outerTri;
2161 changeNeighbor(outerTri, c, a, iT);
2164 outerTris.at(outerEdge) = iT;
2169 triangles[iParent].neighbors[iInParent] = iT;
2170 t.neighbors[0] = iParent;
2171 t.vertices =
arr3(a, b, c);
2172 setAdjacentTriangle(c, iT);
2175template <
typename T,
typename TNearPo
intLocator>
2176IndexSizeType Triangulation<T, TNearPointLocator>::findDelaunayPoint(
2177 const std::vector<VertInd>& poly,
2178 const IndexSizeType iA,
2179 const IndexSizeType iB)
const
2181 assert(iB - iA > 1);
2182 const V2d<T>& a = vertices[poly[iA]];
2183 const V2d<T>& b = vertices[poly[iB]];
2184 IndexSizeType out = iA + 1;
2185 const V2d<T>* c = &vertices[poly[out]];
2186 for(IndexSizeType i = iA + 1; i < iB; ++i)
2188 const V2d<T>& v = vertices[poly[i]];
2195 assert(out > iA && out < iB);
2199template <
typename T,
typename TNearPo
intLocator>
2201 const std::vector<
V2d<T> >& newVertices)
2207template <
typename T,
typename TNearPo
intLocator>
2210 return m_vertTris.empty() && !
vertices.empty();
2213template <
typename T,
typename TNearPo
intLocator>
2214unordered_map<TriInd, LayerDepth>
2215Triangulation<T, TNearPointLocator>::peelLayer(
2216 std::stack<TriInd> seeds,
2218 std::vector<LayerDepth>& triDepths)
const
2220 unordered_map<TriInd, LayerDepth> behindBoundary;
2221 while(!seeds.empty())
2223 const TriInd iT = seeds.top();
2225 triDepths[iT] = std::min(triDepths[iT], layerDepth);
2226 behindBoundary.erase(iT);
2232 if(iN == noNeighbor || triDepths[iN] <= layerDepth)
2234 if(fixedEdges.count(opEdge))
2236 const unordered_map<Edge, LayerDepth>::const_iterator cit =
2237 overlapCount.find(opEdge);
2238 const LayerDepth triDepth = cit == overlapCount.end()
2240 : layerDepth + cit->second + 1;
2241 behindBoundary[iN] = triDepth;
2247 return behindBoundary;
2250template <
typename T,
typename TNearPo
intLocator>
2251std::vector<LayerDepth>
2254 std::vector<LayerDepth> triDepths(
2255 triangles.size(), std::numeric_limits<LayerDepth>::max());
2256 std::stack<TriInd> seeds(TriDeque(1, m_vertTris[0]));
2260 unordered_map<LayerDepth, TriIndUSet> seedsByDepth;
2263 const unordered_map<TriInd, LayerDepth>& newSeeds =
2264 peelLayer(seeds, layerDepth, triDepths);
2266 seedsByDepth.erase(layerDepth);
2267 typedef unordered_map<TriInd, LayerDepth>::const_iterator Iter;
2268 for(Iter it = newSeeds.begin(); it != newSeeds.end(); ++it)
2270 deepestSeedDepth = std::max(deepestSeedDepth, it->second);
2271 seedsByDepth[it->second].insert(it->first);
2273 const TriIndUSet& nextLayerSeeds = seedsByDepth[layerDepth + 1];
2274 seeds = std::stack<TriInd>(
2275 TriDeque(nextLayerSeeds.begin(), nextLayerSeeds.end()));
2277 }
while(!seeds.empty() || deepestSeedDepth > layerDepth);
2282#ifdef CDT_ENABLE_CALLBACK_HANDLER
2283template <
typename T,
typename TNearPo
intLocator>
2287 m_callbackHandler = callbackHandler;
2291template <
typename T,
typename TNearPo
intLocator>
2292void Triangulation<T, TNearPointLocator>::insertVertices_AsProvided(
2295 for(
VertInd iV = superGeomVertCount; iV < vertices.size(); ++iV)
2297#ifdef CDT_ENABLE_CALLBACK_HANDLER
2298 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2307template <
typename T,
typename TNearPo
intLocator>
2308void Triangulation<T, TNearPointLocator>::insertVertices_Randomized(
2309 VertInd superGeomVertCount)
2311 std::size_t vertexCount = vertices.size() - superGeomVertCount;
2312 std::vector<VertInd> ii(vertexCount);
2313 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
2314 detail::random_shuffle(ii.begin(), ii.end());
2315 for(std::vector<VertInd>::iterator it = ii.begin(); it != ii.end(); ++it)
2317#ifdef CDT_ENABLE_CALLBACK_HANDLER
2318 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2331template <
typename T>
2332inline double log2_bc(T x)
2334#ifdef CDT_CXX11_IS_SUPPORTED
2335 return std::log2(x);
2337 static double log2_constant = std::log(2.0);
2338 return std::log(
static_cast<double>(x)) / log2_constant;
2348 const int filledLayerPow2 =
2349 static_cast<int>(std::floor(log2_bc(vertexCount)) - 1);
2350 const std::size_t nodesInFilledTree =
2351 static_cast<std::size_t
>(std::pow(2., filledLayerPow2 + 1) - 1);
2352 const std::size_t nodesInLastFilledLayer =
2353 static_cast<std::size_t
>(std::pow(2., filledLayerPow2));
2354 const std::size_t nodesInLastLayer = vertexCount - nodesInFilledTree;
2355 return nodesInLastLayer >= nodesInLastFilledLayer
2356 ? nodesInLastFilledLayer + nodesInLastLayer -
2357 nodesInLastFilledLayer
2358 : nodesInLastFilledLayer;
2361template <
typename T>
2362class FixedCapacityQueue
2365 FixedCapacityQueue(
const std::size_t capacity)
2367 , m_front(m_vec.begin())
2368 , m_back(m_vec.begin())
2375 const T& front()
const
2383 if(m_front == m_vec.end())
2384 m_front = m_vec.begin();
2387 void push(
const T& t)
2389 assert(m_size < m_vec.size());
2392 if(m_back == m_vec.end())
2393 m_back = m_vec.begin();
2396#ifdef CDT_CXX11_IS_SUPPORTED
2397 void push(
const T&& t)
2399 assert(m_size < m_vec.size());
2402 if(m_back == m_vec.end())
2403 m_back = m_vec.begin();
2408 std::vector<T> m_vec;
2409 typename std::vector<T>::iterator m_front;
2410 typename std::vector<T>::iterator m_back;
2414template <
typename T>
2417 const std::vector<V2d<T> >& m_vertices;
2420 less_than_x(
const std::vector<
V2d<T> >& vertices)
2421 : m_vertices(vertices)
2425 return m_vertices[a].x < m_vertices[b].x;
2429template <
typename T>
2432 const std::vector<V2d<T> >& m_vertices;
2435 less_than_y(
const std::vector<
V2d<T> >& vertices)
2436 : m_vertices(vertices)
2440 return m_vertices[a].y < m_vertices[b].y;
2446template <
typename T,
typename TNearPo
intLocator>
2447void Triangulation<T, TNearPointLocator>::insertVertices_KDTreeBFS(
2452 const VertInd vertexCount(verticesCount() - superGeomVertCount);
2455 std::vector<VertInd> ii(vertexCount);
2456 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
2458 typedef std::vector<VertInd>::iterator It;
2461 queue.push(make_tuple(ii.begin(), ii.end(), box.
min, box.
max,
VertInd(0)));
2464 V2d<T> newBoxMin, newBoxMax;
2470 while(!queue.empty())
2472#ifdef CDT_ENABLE_CALLBACK_HANDLER
2473 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2478 tie(first, last, box.
min, box.
max, parent) = queue.front();
2480 assert(first != last);
2482 const std::ptrdiff_t len = std::distance(first, last);
2485 insertVertex(*first, parent);
2488 const It midIt = first + len / 2;
2491 detail::portable_nth_element(first, midIt, last, cmpX);
2493 const T split = vertices[mid].x;
2494 newBoxMin.
x = split;
2495 newBoxMin.
y = box.
min.y;
2496 newBoxMax.
x = split;
2497 newBoxMax.
y = box.
max.y;
2501 detail::portable_nth_element(first, midIt, last, cmpY);
2503 const T split = vertices[mid].y;
2504 newBoxMin.
x = box.
min.x;
2505 newBoxMin.
y = split;
2506 newBoxMax.
x = box.
max.x;
2507 newBoxMax.
y = split;
2509 insertVertex(mid, parent);
2512 queue.push(make_tuple(first, midIt, box.
min, newBoxMax, mid));
2514 if(midIt + 1 != last)
2516 queue.push(make_tuple(midIt + 1, last, newBoxMin, box.
max, mid));
2521template <
typename T,
typename TNearPo
intLocator>
2522std::pair<TriInd, TriInd> Triangulation<T, TNearPointLocator>::edgeTriangles(
2524 const VertInd b)
const
2526 const TriInd triStart = m_vertTris[a];
2527 assert(triStart != noNeighbor);
2528 TriInd iT = triStart, iTNext = triStart;
2532 const Triangle& t = triangles[iT];
2533 tie(iTNext, iV) = t.
next(a);
2534 assert(iTNext != noNeighbor);
2537 return std::make_pair(iT, iTNext);
2540 }
while(iT != triStart);
2541 return std::make_pair(noNeighbor, noNeighbor);
2544template <
typename T,
typename TNearPo
intLocator>
2545bool Triangulation<T, TNearPointLocator>::hasEdge(
2547 const VertInd b)
const
2549 return edgeTriangles(a, b).first != invalidIndexSizeType;
2552template <
typename T,
typename TNearPo
intLocator>
2553VertInd Triangulation<T, TNearPointLocator>::opposedVertexOnEdge(
2555 const T tolerance)
const
2557 if(fixedEdges.count(edge))
2559 const V2d<T>& a = vertices[edge.v1()];
2560 const V2d<T>& b = vertices[edge.v2()];
2561 const std::pair<TriInd, TriInd> tris = edgeTriangles(edge.v1(), edge.v2());
2565 for(
int i = 0; i < 2; ++i)
2567 const V2d<T>& v = vertices[opposed[i]];
2571 detail::isEncroachingOnEdge(v, a, b))
2580template <
typename T,
typename TNearPo
intLocator>
2581bool Triangulation<T, TNearPointLocator>::hasAnotherFixedEdgeAtSmallAngle(
2583 const Edge& excludeEdge)
const
2587 excludeEdge.v1() == v ? excludeEdge.v2() : excludeEdge.v1();
2588 const TriInd triStart = m_vertTris[v];
2589 assert(triStart != noNeighbor);
2593 const Triangle& t = triangles[iT];
2596 tie(iTNext, iV) = t.next(v);
2597 const Edge candidate(v, iV);
2598 if(candidate != excludeEdge && fixedEdges.count(candidate) &&
2599 detail::isAngleAtApexSmall(
2600 vertices[v], vertices[iVOther], vertices[iV]))
2605 }
while(iT != triStart);
2609template <
typename T,
typename TNearPo
intLocator>
2610void Triangulation<T, TNearPointLocator>::setAdjacentTriangle(
2614 assert(t != noNeighbor);
2617 triangles[t].vertices[0] == v || triangles[t].vertices[1] == v ||
2618 triangles[t].vertices[2] == v);
2621template <
typename T,
typename TNearPo
intLocator>
2622void Triangulation<T, TNearPointLocator>::pivotVertexTriangleCW(
const VertInd v)
2624 assert(m_vertTris[v] != noNeighbor);
2625 m_vertTris[v] = triangles[m_vertTris[v]].next(v).first;
2626 assert(m_vertTris[v] != noNeighbor);
2628 triangles[m_vertTris[v]].vertices[0] == v ||
2629 triangles[m_vertTris[v]].vertices[1] == v ||
2630 triangles[m_vertTris[v]].vertices[2] == v);
2633template <
typename T,
typename TNearPo
intLocator>
2634void Triangulation<T, TNearPointLocator>::tryAddVertexToLocator(
const VertInd v)
2636 if(!m_nearPtLocator.empty())
2637 m_nearPtLocator.addPoint(v, vertices);
2640template <
typename T,
typename TNearPo
intLocator>
2641void Triangulation<T, TNearPointLocator>::tryInitNearestPointLocator()
2643 if(!vertices.empty() && m_nearPtLocator.empty())
2645 m_nearPtLocator.initialize(vertices);
2649template <
typename T,
typename TNearPo
intLocator>
2651 const VertInd maxVerticesToInsert,
2653 const T refinementThreshold,
2655 const T minEdgeLength)
2660 tryInitNearestPointLocator();
2663 VertInd remainingVertexBudget = maxVerticesToInsert;
2667 resolveEncroachedEdges(
2669 remainingVertexBudget,
2670 steinerVerticesOffset,
2672 refinementCriterion,
2673 refinementThreshold,
2684 !(toEraseOrNull && toEraseOrNull->count(iT)) &&
2685 isRefinementNeeded(t, refinementCriterion, refinementThreshold))
2687 badTriangles.push(iT);
2691 while(!badTriangles.empty() && remainingVertexBudget > 0)
2693 const TriInd iT = badTriangles.front();
2695 if(toEraseOrNull && toEraseOrNull->count(iT))
2697 if(!isRefinementNeeded(
2698 triangles[iT], refinementCriterion, refinementThreshold) ||
2710 const T shortestEdge = std::min(
2712 if(shortestEdge <= minEdgeLength)
2720 m_nearPtLocator.nearPoint(circumcenterPos,
vertices),
2722 if(!triAtCircumcenter.hasValue())
2729 const VertInd budgetBeforeSplits = remainingVertexBudget;
2730 const EdgeVec encroachedEdges =
2731 edgesEncroachedBy(circumcenterPos, triAtCircumcenter.value());
2732 const TriIndVec badTris = resolveEncroachedEdges(
2734 remainingVertexBudget,
2735 steinerVerticesOffset,
2737 refinementCriterion,
2738 refinementThreshold,
2742 if(!remainingVertexBudget)
2747 if(remainingVertexBudget != budgetBeforeSplits || !badTris.empty())
2749 typedef TriIndVec::const_iterator It;
2750 for(It it = badTris.begin(); it != badTris.end(); ++it)
2752 badTriangles.push(*it);
2754 badTriangles.push(iT);
2758 if(!encroachedEdges.empty())
2761 const TriInd iCircumcenterTri = triAtCircumcenter.value();
2768 if(loc == PtTriLocation::OnVertex)
2774 const array<TriInd, 2> trisAt = {
2780 (toEraseOrNull->count(trisAt[0]) || toEraseOrNull->count(trisAt[1])))
2787 --remainingVertexBudget;
2789 addNewVertex(circumcenterPos, noNeighbor);
2790#ifdef CDT_ENABLE_CALLBACK_HANDLER
2791 if(m_callbackHandler)
2793 m_callbackHandler->onAddVertexStart(
2797 std::stack<TriInd> triStack =
2798 trisAt[1] == noNeighbor
2799 ? insertVertexInsideTriangle(iVert, trisAt[0])
2800 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1],
true);
2801 ensureDelaunayByEdgeFlips(iVert, triStack);
2802 tryAddVertexToLocator(iVert);
2804 TriInd start = m_vertTris[iVert];
2809 if(!(toEraseOrNull && toEraseOrNull->count(currTri)) &&
2811 isRefinementNeeded(t, refinementCriterion, refinementThreshold))
2813 badTriangles.push(currTri);
2815 currTri = t.
next(iVert).first;
2816 }
while(currTri != start);
2827 (toEraseOrNull && toEraseOrNull->count(iT)))
2831 if(isRefinementNeeded(
2832 t, refinementCriterion, refinementThreshold) &&
2833 isSmallestAngleFixed(t))
2844CDT_RESTORE_MATH_SETTINGS_FOR_CONSTRUCTIONS
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...
bool isAngleAtApexSmall(const V2d< T > &apex, const V2d< T > &a, const V2d< T > &b)
Whether the angle at apex between apex->a and apex->b is smaller than 60°
EdgeQueue toQueue(const EdgeVec &edges)
Turn a vector into a queue, preserving order.
void sortUnique(TVec &v)
Sort a vector and remove its duplicate elements.
Error thrown when triangulation modification is attempted after it was finalized.
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...
EdgeUSet fixedEdges
triangulation's constraints (fixed edges)
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.
TriIndUSet collectSuperTriangle() const
Collect triangles adjacent to super-triangle: same triangles that eraseSuperTriangle would remove.
bool isFinalized() const
Check if the triangulation was finalized with erase... method and super-triangle was removed.
TriIndUSet collectOuterTrianglesAndHoles() const
Collect triangles outside of constrained boundary and auto-detected holes: same triangles that eraseO...
TriIndVec findUnrefinedTriangles(RefinementCriterion::Enum refinementCriterion=RefinementCriterion::SmallestAngle, T refinementThreshold=degToRad(T(20))) const
Find triangles that don't fulfill the refinement criterion.
void finalizeTriangulation(const TriIndUSet &removedTriangles)
Remove super-triangle and triangles with specified indices.
void eraseOuterTrianglesAndHoles()
Erase triangles outside of constrained boundary and auto-detected holes.
V2dVec vertices
triangulation's vertices
TriIndUSet collectOuterTriangles() const
Collect triangles outside of constrained boundary: same triangles that eraseOuterTriangles would remo...
Unrefined refineTriangles(VertInd maxVerticesToInsert, RefinementCriterion::Enum refinementCriterion=RefinementCriterion::SmallestAngle, T refinementThreshold=degToRad(T(20)), TriIndUSet *toEraseOrNull=NULL, T minEdgeLength=T(1e-6))
Triangles refinement by splitting bad triangles.
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.
unordered_map< Edge, EdgeVec > pieceToOriginals
Stores list of original edges represented by a given fixed edge.
unordered_map< Edge, BoundaryOverlapCount > overlapCount
Stores count of overlapping boundaries for a fixed edge.
TriangleVec triangles
triangulation's triangles
Triangulation()
Default constructor.
EdgeVec findEncroachedFixedEdges() const
Find all fixed edges encroached by their opposed vertices.
void setCallbackHandler(ICallbackHandler *callbackHandler)
Set user-provided callback handler.
unsigned short LayerDepth
Type used for storing layer depths for triangles.
OptionalIndex< VertInd > OptionalVertInd
Optional vertex index.
OptionalIndex< TriInd > OptionalTriInd
Optional triangle index.
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.
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.
unordered_set< Edge > EdgeUSet
Hash table of edges.
std::queue< TriInd > TriIndQueue
Queue of triangles.
VertInd edge_get_v2(const Edge &e)
Get edge second vertex.
CDT_EXPORT T area(const V2d< T > &a, const V2d< T > &b, const V2d< T > &c)
Surface area of a triangle ABC.
std::vector< TriInd > TriIndVec
Vector of triangle indices.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index edgeNeighborInd(const VerticesArr3 &vv, VertInd iVedge1, VertInd iVedge2)
Index of triangle's neighbor opposed to an edge.
VertInd edge_get_v1(const Edge &e)
Get edge first vertex.
CDT_EXPORT PtLineLocation::Enum classifyOrientation(T orientation, T orientationTolerance=T(0))
Classify value of orient2d predicate.
array< TriInd, 3 > NeighborsArr3
array of three neighbors
CDT_EXPORT T distance(const V2d< T > &a, const V2d< T > &b)
Distance between two 2D points.
IndexSizeType VertInd
Vertex index.
CDT_EXPORT Index cw(Index i)
Advance vertex or neighbor index clockwise.
array< VertInd, 3 > VerticesArr3
array of three vertex indices
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY bool touchesSuperTriangle(const Triangle &t)
Check if any of triangle's vertices belongs to a super-triangle.
array< T, 3 > arr3(const T &v0, const T &v1, const T &v2)
Needed for c++03 compatibility (no uniform initialization available)
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoNbr(Index vertIndex)
Opposed neighbor index from vertex index.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index vertexInd(const VerticesArr3 &vv, VertInd iV)
If triangle has a given vertex return vertex-index.
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.
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.
CDT_EXPORT T distanceSquared(const V2d< T > &a, const V2d< T > &b)
Squared distance between two 2D points.
unordered_set< TriInd > TriIndUSet
Hash table of triangles.
CDT_EXPORT Index ccw(Index i)
Advance vertex or neighbor index counter-clockwise.
CDT_EXPORT V2d< T > circumcenter(V2d< T > a, V2d< T > b, V2d< T > c)
Position of ABC triangle circumcenter.
CDT_EXPORT Index edgeNeighbor(PtTriLocation::Enum location)
Neighbor index from a on-edge location.
unordered_map< TriInd, TriInd > TriIndUMap
Triangle hash map.
const T & getX_V2d(const V2d< T > &v)
X- coordinate getter for V2d.
unsigned char Index
Index in triangle.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY TriInd opposedTriangle(const Triangle &tri, VertInd iVert)
Given triangle and a vertex find opposed triangle.
CDT_EXPORT T smallestAngle(const V2d< T > &a, const V2d< T > &b, const V2d< T > &c)
Smallest angle of triangle ABC in radians.
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.
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.
IndexSizeType TriInd
Triangle index.
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.
std::queue< Edge > EdgeQueue
Queue of edges.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opposedVertexInd(const NeighborsArr3 &nn, TriInd iTopo)
Index of triangle's vertex opposed to a triangle.
const T & getY_V2d(const V2d< T > &v)
Y-coordinate getter for V2d.
@ RefinementCircumcenter
Refinement: circumcenter of a poor-quality triangle.
@ FixedEdgeMidpoint
During conforming triangulation edge mid-point is added.
@ FixedEdgesIntersection
Resolving fixed/constraint edges' intersection.
V2d< T > max
max box corner
V2d< T > min
min box corner
Edge connecting two vertices: vertex with smaller index is always first.
VertInd v1() const
V1 getter.
VertInd v2() const
V2 getter.
@ TryResolve
attempt to resolve constraint edge intersections
@ NotAllowed
constraint edge intersections are not allowed
@ DontCheck
No checks: slightly faster but less safe.
@ LargestArea
constraint maximum triangles area
@ SmallestAngle
constraint minimum triangles angle
Triangulation triangle (counter-clockwise winding)
VerticesArr3 vertices
triangle's three vertices
NeighborsArr3 neighbors
triangle's three neighbors
std::pair< TriInd, VertInd > next(const VertInd i) const
Next triangle adjacent to a vertex (clockwise)
Counts of the refinements that Triangulation::refineTriangles was not able to perform.
std::size_t circumcenterOnVertex
triangles whose circumcenter coincides with an existing vertex
std::size_t sharpFixedCorner
triangles whose smallest angle is enclosed by two fixed edges: such an angle comes from the input and...
std::size_t splitVertexInvalid
fixed edges whose split vertex can not be placed: inserting it would break the triangulation's topolo...
std::size_t circumcenterOutside
triangles whose circumcenter is outside the triangulated area
std::size_t shortEdges
fixed edges that are shorter than the threshold
std::size_t shortEdgeTriangles
triangles whose shortest edge is shorter than the threshold
Unrefined()
Constructor: all the counts start at zero.
@ Auto
Automatic insertion order optimized for better performance.