11#include "portable_nth_element.hpp"
22typedef std::deque<TriInd> TriDeque;
29array<T, 3>
arr3(
const T& v0,
const T& v1,
const T& v2)
31 const array<T, 3> out = {v0, v1, v2};
38const std::size_t nTargetVerts = 0;
44const float minDistToConstraintEdge(0);
50template <
typename T,
typename TNearPo
intLocator>
52 : m_nTargetVerts(detail::defaults::nTargetVerts)
53 , m_superGeomType(detail::defaults::superGeomType)
54 , m_vertexInsertionOrder(detail::defaults::vertexInsertionOrder)
55 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
56 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
59template <
typename T,
typename TNearPo
intLocator>
62 : m_nTargetVerts(detail::defaults::nTargetVerts)
63 , m_superGeomType(detail::defaults::superGeomType)
64 , m_vertexInsertionOrder(vertexInsertionOrder)
65 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
66 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
69template <
typename T,
typename TNearPo
intLocator>
73 const T minDistToConstraintEdge)
74 : m_nTargetVerts(detail::defaults::nTargetVerts)
75 , m_superGeomType(detail::defaults::superGeomType)
76 , m_vertexInsertionOrder(vertexInsertionOrder)
77 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
78 , m_minDistToConstraintEdge(minDistToConstraintEdge)
81template <
typename T,
typename TNearPo
intLocator>
84 const TNearPointLocator& nearPtLocator,
86 const T minDistToConstraintEdge)
87 : m_nearPtLocator(nearPtLocator)
88 , m_nTargetVerts(detail::defaults::nTargetVerts)
89 , m_superGeomType(detail::defaults::superGeomType)
90 , m_vertexInsertionOrder(vertexInsertionOrder)
91 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
92 , m_minDistToConstraintEdge(minDistToConstraintEdge)
95template <
typename T,
typename TNearPo
intLocator>
98 if(m_dummyTris.empty())
100 const TriIndUSet dummySet(m_dummyTris.begin(), m_dummyTris.end());
102 triIndMap[noNeighbor] = noNeighbor;
103 for(
TriInd iT(0), iTnew(0); iT <
TriInd(triangles.size()); ++iT)
105 if(dummySet.count(iT))
107 triIndMap[iT] = iTnew;
108 triangles[iTnew] = triangles[iT];
111 triangles.erase(triangles.end() - dummySet.size(), triangles.end());
114 for(TriIndVec::iterator iT = m_vertTris.begin(); iT != m_vertTris.end();
117 *iT = triIndMap[*iT];
120 for(TriangleVec::iterator t = triangles.begin(); t != triangles.end(); ++t)
123 for(NeighborsArr3::iterator iN = nn.begin(); iN != nn.end(); ++iN)
124 *iN = triIndMap[*iN];
127 m_dummyTris = std::vector<TriInd>();
130template <
typename T,
typename TNearPo
intLocator>
142 finalizeTriangulation(toErase);
145template <
typename T,
typename TNearPo
intLocator>
149 assert(m_vertTris[0] != noNeighbor);
150 const std::stack<TriInd> seed(std::deque<TriInd>(1, m_vertTris[0]));
151 const TriIndUSet toErase = growToBoundary(seed);
152 finalizeTriangulation(toErase);
155template <
typename T,
typename TNearPo
intLocator>
158 const std::vector<LayerDepth> triDepths = calculateTriangleDepths();
160 toErase.reserve(triangles.size());
161 for(std::size_t iT = 0; iT != triangles.size(); ++iT)
163 if(triDepths[iT] % 2 == 0)
164 toErase.insert(
static_cast<TriInd>(iT));
166 finalizeTriangulation(toErase);
175template <
typename T,
typename TNearPo
intLocator>
179 if(removedTriangles.empty())
183 for(
TriInd iT(0), iTnew(0); iT <
TriInd(triangles.size()); ++iT)
185 if(removedTriangles.count(iT))
187 triIndMap[iT] = iTnew;
188 triangles[iTnew] = triangles[iT];
191 triangles.erase(triangles.end() - removedTriangles.size(), triangles.end());
193 for(
TriInd iT(0); iT < triangles.size(); ++iT)
198 for(NeighborsArr3::iterator n = nn.begin(); n != nn.end(); ++n)
200 if(removedTriangles.count(*n))
204 else if(*n != noNeighbor)
212template <
typename T,
typename TNearPo
intLocator>
218template <
typename T,
typename TNearPo
intLocator>
224template <
typename T,
typename TNearPo
intLocator>
233 vertices.erase(vertices.begin(), vertices.begin() + 3);
237 typedef CDT::EdgeUSet::const_iterator It;
238 for(It e = fixedEdges.begin(); e != fixedEdges.end(); ++e)
242 fixedEdges = updatedFixedEdges;
245 unordered_map<Edge, BoundaryOverlapCount> updatedOverlapCount;
246 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator
248 for(It it = overlapCount.begin(); it != overlapCount.end(); ++it)
250 updatedOverlapCount.insert(std::make_pair(
253 overlapCount = updatedOverlapCount;
256 unordered_map<Edge, EdgeVec> updatedPieceToOriginals;
257 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
258 for(It it = pieceToOriginals.begin(); it != pieceToOriginals.end();
262 for(EdgeVec::iterator eeIt = ee.begin(); eeIt != ee.end();
267 updatedPieceToOriginals.insert(
270 pieceToOriginals = updatedPieceToOriginals;
274 removeTriangles(removedTriangles);
278 for(TriangleVec::iterator t = triangles.begin(); t != triangles.end();
282 for(VerticesArr3::iterator v = vv.begin(); v != vv.end(); ++v)
290template <
typename T,
typename TNearPo
intLocator>
293 m_nearPtLocator.initialize(vertices);
294 m_nTargetVerts =
static_cast<IndexSizeType
>(vertices.size());
298template <
typename T,
typename TNearPo
intLocator>
300 std::stack<TriInd> seeds)
const
303 while(!seeds.empty())
305 const TriInd iT = seeds.top();
307 traversed.insert(iT);
312 if(fixedEdges.count(opEdge))
315 if(iN != noNeighbor && traversed.count(iN) == 0)
322template <
typename T,
typename TNearPo
intLocator>
323void Triangulation<T, TNearPointLocator>::makeDummy(
const TriInd iT)
325 m_dummyTris.push_back(iT);
328template <
typename T,
typename TNearPo
intLocator>
329TriInd Triangulation<T, TNearPointLocator>::addTriangle(
const Triangle& t)
331 if(m_dummyTris.empty())
333 triangles.push_back(t);
334 return TriInd(triangles.size() - 1);
336 const TriInd nxtDummy = m_dummyTris.back();
337 m_dummyTris.pop_back();
338 triangles[nxtDummy] = t;
342template <
typename T,
typename TNearPo
intLocator>
343TriInd Triangulation<T, TNearPointLocator>::addTriangle()
345 if(m_dummyTris.empty())
347 const Triangle dummy = {
348 {noVertex, noVertex, noVertex},
349 {noNeighbor, noNeighbor, noNeighbor}};
350 triangles.push_back(dummy);
351 return TriInd(triangles.size() - 1);
353 const TriInd nxtDummy = m_dummyTris.back();
354 m_dummyTris.pop_back();
358template <
typename T,
typename TNearPo
intLocator>
360 const std::vector<Edge>& edges)
365template <
typename T,
typename TNearPo
intLocator>
367 const std::vector<Edge>& edges)
372template <
typename T,
typename TNearPo
intLocator>
375 if(!fixedEdges.insert(edge).second)
377 ++overlapCount[edge];
385template <
typename T,
typename Allocator1>
386void insert_unique(std::vector<T, Allocator1>& to,
const T& elem)
388 if(std::find(to.begin(), to.end(), elem) == to.end())
395template <
typename T,
typename Allocator1,
typename Allocator2>
397 std::vector<T, Allocator1>& to,
398 const std::vector<T, Allocator2>& from)
400 typedef typename std::vector<T, Allocator2>::const_iterator Cit;
401 to.reserve(to.size() + from.size());
402 for(Cit cit = from.begin(); cit != from.end(); ++cit)
404 insert_unique(to, *cit);
410template <
typename T,
typename TNearPo
intLocator>
411void Triangulation<T, TNearPointLocator>::splitFixedEdge(
416 const Edge half1(edge.v1(), iSplitVert);
417 const Edge half2(iSplitVert, edge.v2());
419 fixedEdges.erase(edge);
423 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
424 const It overlapIt = overlapCount.find(edge);
425 if(overlapIt != overlapCount.end())
427 overlapCount[half1] += overlapIt->second;
428 overlapCount[half2] += overlapIt->second;
429 overlapCount.erase(overlapIt);
433 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
434 pieceToOriginals.find(edge);
435 if(originalsIt != pieceToOriginals.end())
437 newOriginals = originalsIt->second;
438 pieceToOriginals.erase(originalsIt);
440 detail::insert_unique(pieceToOriginals[half1], newOriginals);
441 detail::insert_unique(pieceToOriginals[half2], newOriginals);
444template <
typename T,
typename TNearPo
intLocator>
445VertInd Triangulation<T, TNearPointLocator>::addSplitEdgeVertex(
446 const V2d<T>& splitVert,
452 addNewVertex(splitVert, noNeighbor);
453 std::stack<TriInd> triStack = insertVertexOnEdge(iSplitVert, iT, iTopo);
454 tryAddVertexToLocator(iSplitVert);
455 ensureDelaunayByEdgeFlips(iSplitVert, triStack);
459template <
typename T,
typename TNearPo
intLocator>
460VertInd Triangulation<T, TNearPointLocator>::splitFixedEdgeAt(
462 const V2d<T>& splitVert,
466 const VertInd iSplitVert = addSplitEdgeVertex(splitVert, iT, iTopo);
467 splitFixedEdge(edge, iSplitVert);
471template <
typename T,
typename TNearPo
intLocator>
472void Triangulation<T, TNearPointLocator>::fixEdge(
474 const Edge& originalEdge)
477 if(edge != originalEdge)
478 detail::insert_unique(pieceToOriginals[edge], originalEdge);
485T lerp(
const T& a,
const T& b,
const T t)
487 return (T(1) - t) * a + t * b;
492V2d<T> intersectionPosition(
498 using namespace predicates::adaptive;
502 const T a_cd = orient2d(c.x, c.y, d.x, d.y, a.x, a.y);
503 const T b_cd = orient2d(c.x, c.y, d.x, d.y, b.x, b.y);
504 const T t_ab = a_cd / (a_cd - b_cd);
506 const T c_ab = orient2d(a.x, a.y, b.x, b.y, c.x, c.y);
507 const T d_ab = orient2d(a.x, a.y, b.x, b.y, d.x, d.y);
508 const T t_cd = c_ab / (c_ab - d_ab);
511 std::fabs(a.x - b.x) < std::fabs(c.x - d.x) ? lerp(a.x, b.x, t_ab)
512 : lerp(c.x, d.x, t_cd),
513 std::fabs(a.y - b.y) < std::fabs(c.y - d.y) ? lerp(a.y, b.y, t_ab)
514 : lerp(c.y, d.y, t_cd));
519template <
typename T,
typename TNearPo
intLocator>
520void Triangulation<T, TNearPointLocator>::insertEdgeIteration(
522 const Edge originalEdge,
524 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
533 fixEdge(edge, originalEdge);
537 const V2d<T>& a = vertices[iA];
538 const V2d<T>& b = vertices[iB];
539 const T distanceTolerance =
540 m_minDistToConstraintEdge == T(0)
542 : m_minDistToConstraintEdge *
distance(a, b);
547 tie(iT, iVL, iVR) = intersectedTriangle(iA, a, b, distanceTolerance);
551 const Edge edgePart(iA, iVL);
552 fixEdge(edgePart, originalEdge);
553 remaining.push_back(Edge(iVL, iB));
556 Triangle t = triangles[iT];
557 std::vector<TriInd> intersected(1, iT);
558 std::vector<VertInd> polyL, polyR;
561 polyL.push_back(iVL);
564 polyR.push_back(iVR);
565 unordered_map<Edge, TriInd> outerTris;
570 while(!t.containsVertex(iB))
573 const Triangle& tOpo = triangles[iTopo];
576 switch(m_intersectingEdgesStrategy)
579 if(fixedEdges.count(Edge(iVL, iVR)))
582 Edge e1 = originalEdge;
583 Edge e2 = Edge(iVL, iVR);
584 e2 = pieceToOriginals.count(e2)
585 ? pieceToOriginals.at(e2).front()
588 e1 = Edge(e1.v1() - m_nTargetVerts, e1.v2() - m_nTargetVerts);
589 e2 = Edge(e2.v1() - m_nTargetVerts, e2.v2() - m_nTargetVerts);
590 throw IntersectingConstraintsError(
592 pieceToOriginals.count(e2) ? pieceToOriginals.at(e2).front()
598 if(!fixedEdges.count(Edge(iVL, iVR)))
601 const V2d<T> newV = detail::intersectionPosition(
602 vertices[iA], vertices[iB], vertices[iVL], vertices[iVR]);
604 splitFixedEdgeAt(Edge(iVL, iVR), newV, iT, iTopo);
607 remaining.push_back(Edge(iA, iNewVert));
608 remaining.push_back(Edge(iNewVert, iB));
612 assert(!fixedEdges.count(Edge(iVL, iVR)));
618 if(loc == PtLineLocation::Left)
620 const Edge e(polyL.back(), iVopo);
622 if(!outerTris.insert(std::make_pair(e, outer)).second)
623 outerTris.at(e) = noNeighbor;
624 polyL.push_back(iVopo);
628 else if(loc == PtLineLocation::Right)
630 const Edge e(polyR.back(), iVopo);
632 if(!outerTris.insert(std::make_pair(e, outer)).second)
633 outerTris.at(e) = noNeighbor;
634 polyR.push_back(iVopo);
641 intersected.push_back(iTopo);
645 outerTris[Edge(polyL.back(), iB)] =
edgeNeighbor(t, polyL.back(), iB);
646 outerTris[Edge(polyR.back(), iB)] =
edgeNeighbor(t, polyR.back(), iB);
650 assert(!intersected.empty());
653 if(m_vertTris[iA] == intersected.front())
654 pivotVertexTriangleCW(iA);
655 if(m_vertTris[iB] == intersected.back())
656 pivotVertexTriangleCW(iB);
658 typedef std::vector<TriInd>::const_iterator TriIndCit;
659 for(TriIndCit it = intersected.begin(); it != intersected.end(); ++it)
662 std::reverse(polyR.begin(), polyR.end());
663 const TriInd iTL = addTriangle();
664 const TriInd iTR = addTriangle();
665 triangulatePseudoPolygon(polyL, outerTris, iTL, iTR, tppIterations);
666 triangulatePseudoPolygon(polyR, outerTris, iTR, iTL, tppIterations);
672 const Edge edgePart(iA, iB);
673 fixEdge(edgePart, originalEdge);
674 remaining.push_back(Edge(iB, edge.v2()));
679 fixEdge(edge, originalEdge);
683template <
typename T,
typename TNearPo
intLocator>
684void Triangulation<T, TNearPointLocator>::insertEdge(
686 const Edge originalEdge,
688 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
692 remaining.push_back(edge);
693 while(!remaining.empty())
695 edge = remaining.back();
696 remaining.pop_back();
697 insertEdgeIteration(edge, originalEdge, remaining, tppIterations);
701template <
typename T,
typename TNearPo
intLocator>
702void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
705 BoundaryOverlapCount overlaps,
706 std::vector<ConformToEdgeTask>& remaining)
717 overlapCount[edge] = overlaps;
719 if(!originals.empty() && edge != originals.front())
721 detail::insert_unique(pieceToOriginals[edge], originals);
726 const V2d<T>& a = vertices[iA];
727 const V2d<T>& b = vertices[iB];
728 const T distanceTolerance =
729 m_minDistToConstraintEdge == T(0)
731 : m_minDistToConstraintEdge *
distance(a, b);
734 tie(iT, iVleft, iVright) = intersectedTriangle(iA, a, b, distanceTolerance);
738 const Edge edgePart(iA, iVleft);
741 overlapCount[edgePart] = overlaps;
742 detail::insert_unique(pieceToOriginals[edgePart], originals);
743#ifdef CDT_CXX11_IS_SUPPORTED
744 remaining.emplace_back(Edge(iVleft, iB), originals, overlaps);
746 remaining.push_back(make_tuple(Edge(iVleft, iB), originals, overlaps));
752 Triangle t = triangles[iT];
753 while(std::find(t.vertices.begin(), t.vertices.end(), iB) ==
757 const Triangle& tOpo = triangles[iTopo];
759 const V2d<T> vOpo = vertices[iVopo];
761 switch(m_intersectingEdgesStrategy)
764 if(fixedEdges.count(Edge(iVleft, iVright)))
767 Edge e1 = pieceToOriginals.count(edge)
768 ? pieceToOriginals.at(edge).front()
770 Edge e2(iVleft, iVright);
771 e2 = pieceToOriginals.count(e2)
772 ? pieceToOriginals.at(e2).front()
775 e1 = Edge(e1.v1() - m_nTargetVerts, e1.v2() - m_nTargetVerts);
776 e2 = Edge(e2.v1() - m_nTargetVerts, e2.v2() - m_nTargetVerts);
781 if(!fixedEdges.count(Edge(iVleft, iVright)))
784 const V2d<T> newV = detail::intersectionPosition(
790 splitFixedEdgeAt(Edge(iVleft, iVright), newV, iT, iTopo);
791#ifdef CDT_CXX11_IS_SUPPORTED
792 remaining.emplace_back(Edge(iNewVert, iB), originals, overlaps);
793 remaining.emplace_back(Edge(iA, iNewVert), originals, overlaps);
796 make_tuple(Edge(iNewVert, iB), originals, overlaps));
798 make_tuple(Edge(iA, iNewVert), originals, overlaps));
803 assert(!fixedEdges.count(Edge(iVleft, iVright)));
812 if(loc == PtLineLocation::Left)
817 else if(loc == PtLineLocation::Right)
829#ifdef CDT_CXX11_IS_SUPPORTED
830 remaining.emplace_back(Edge(iB, edge.v2()), originals, overlaps);
833 make_tuple(Edge(iB, edge.v2()), originals, overlaps));
839 const V2d<T>& start = vertices[iA];
840 const V2d<T>& end = vertices[iB];
842 V2d<T>::make((start.x + end.x) / T(2), (start.y + end.y) / T(2)),
844 const std::vector<Edge> flippedFixedEdges =
845 insertVertex_FlipFixedEdges(iMid);
847#ifdef CDT_CXX11_IS_SUPPORTED
848 remaining.emplace_back(Edge(iMid, iB), originals, overlaps);
849 remaining.emplace_back(Edge(iA, iMid), originals, overlaps);
851 remaining.push_back(make_tuple(Edge(iMid, iB), originals, overlaps));
852 remaining.push_back(make_tuple(Edge(iA, iMid), originals, overlaps));
857 for(std::vector<Edge>::const_iterator it = flippedFixedEdges.begin();
858 it != flippedFixedEdges.end();
861 const Edge& flippedFixedEdge = *it;
862 fixedEdges.erase(flippedFixedEdge);
864 BoundaryOverlapCount prevOverlaps = 0;
865 const unordered_map<Edge, BoundaryOverlapCount>::const_iterator
866 overlapsIt = overlapCount.find(flippedFixedEdge);
867 if(overlapsIt != overlapCount.end())
869 prevOverlaps = overlapsIt->second;
870 overlapCount.erase(overlapsIt);
873 EdgeVec prevOriginals(1, flippedFixedEdge);
874 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
875 pieceToOriginals.find(flippedFixedEdge);
876 if(originalsIt != pieceToOriginals.end())
878 prevOriginals = originalsIt->second;
880#ifdef CDT_CXX11_IS_SUPPORTED
881 remaining.emplace_back(flippedFixedEdge, prevOriginals, prevOverlaps);
884 make_tuple(flippedFixedEdge, prevOriginals, prevOverlaps));
889template <
typename T,
typename TNearPo
intLocator>
890void Triangulation<T, TNearPointLocator>::conformToEdge(
893 BoundaryOverlapCount overlaps,
894 std::vector<ConformToEdgeTask>& remaining)
898#ifdef CDT_CXX11_IS_SUPPORTED
899 remaining.emplace_back(edge, originals, overlaps);
901 remaining.push_back(make_tuple(edge, originals, overlaps));
903 while(!remaining.empty())
905 tie(edge, originals, overlaps) = remaining.back();
906 remaining.pop_back();
907 conformToEdgeIteration(edge, originals, overlaps, remaining);
921template <
typename T,
typename TNearPo
intLocator>
922tuple<TriInd, VertInd, VertInd>
923Triangulation<T, TNearPointLocator>::intersectedTriangle(
927 const T orientationTolerance)
const
929 const TriInd startTri = m_vertTris[iA];
933 const Triangle t = triangles[iT];
936 const T orientP2 =
orient2D(vertices[iP2], a, b);
938 if(locP2 == PtLineLocation::Right)
941 const T orientP1 =
orient2D(vertices[iP1], a, b);
943 if(locP1 == PtLineLocation::OnLine)
945 return make_tuple(noNeighbor, iP1, iP1);
947 if(locP1 == PtLineLocation::Left)
949 if(orientationTolerance)
953 if(std::abs(orientP1) <= std::abs(orientP2))
955 closestOrient = orientP1;
960 closestOrient = orientP2;
964 closestOrient, orientationTolerance) ==
965 PtLineLocation::OnLine)
967 return make_tuple(noNeighbor, iClosestP, iClosestP);
970 return make_tuple(iT, iP1, iP2);
973 iT = t.next(iA).first;
974 }
while(iT != startTri);
977 "Could not find vertex triangle intersected by an edge.",
981template <
typename T,
typename TNearPo
intLocator>
982void Triangulation<T, TNearPointLocator>::addSuperTriangle(
const Box2d<T>& box)
987 const V2d<T> center = {
988 (box.min.x + box.max.x) / T(2), (box.min.y + box.max.y) / T(2)};
989 const T w = box.max.x - box.min.x;
990 const T h = box.max.y - box.min.y;
991 T r = std::max(w, h);
996 r = std::max(T(2) * r, T(1));
1002 while(center.y <= center.y - r)
1006 const T R = T(2) * r;
1007 const T cos_30_deg = 0.8660254037844386;
1008 const T shiftX = R * cos_30_deg;
1009 const V2d<T> posV1 = {center.x - shiftX, center.y - r};
1010 const V2d<T> posV2 = {center.x + shiftX, center.y - r};
1011 const V2d<T> posV3 = {center.x, center.y + R};
1012 addNewVertex(posV1,
TriInd(0));
1013 addNewVertex(posV2,
TriInd(0));
1014 addNewVertex(posV3,
TriInd(0));
1015 const Triangle superTri = {
1017 {noNeighbor, noNeighbor, noNeighbor}};
1018 addTriangle(superTri);
1021 m_nearPtLocator.initialize(vertices);
1025template <
typename T,
typename TNearPo
intLocator>
1026void Triangulation<T, TNearPointLocator>::addNewVertex(
1030 vertices.push_back(pos);
1031 m_vertTris.push_back(iT);
1034template <
typename T,
typename TNearPo
intLocator>
1036Triangulation<T, TNearPointLocator>::insertVertex_FlipFixedEdges(
1039 std::vector<Edge> flippedFixedEdges;
1041 const V2d<T>& v1 = vertices[iV1];
1042 const VertInd startVertex = m_nearPtLocator.nearPoint(v1, vertices);
1043 array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iV1, startVertex);
1044 std::stack<TriInd> triStack =
1045 trisAt[1] == noNeighbor ? insertVertexInsideTriangle(iV1, trisAt[0])
1046 : insertVertexOnEdge(iV1, trisAt[0], trisAt[1]);
1048 TriInd iTopo, n1, n2, n3, n4;
1050 while(!triStack.empty())
1052 const TriInd iT = triStack.top();
1055 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1056 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1059 const Edge flippedEdge(iV2, iV4);
1060 if(!fixedEdges.empty() &&
1061 fixedEdges.find(flippedEdge) != fixedEdges.end())
1063 flippedFixedEdges.push_back(flippedEdge);
1066 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1068 triStack.push(iTopo);
1072 tryAddVertexToLocator(iV1);
1073 return flippedFixedEdges;
1076template <
typename T,
typename TNearPo
intLocator>
1077void Triangulation<T, TNearPointLocator>::insertVertex(
1081 const array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iVert, walkStart);
1082 std::stack<TriInd> triStack =
1083 trisAt[1] == noNeighbor
1084 ? insertVertexInsideTriangle(iVert, trisAt[0])
1085 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1]);
1086 ensureDelaunayByEdgeFlips(iVert, triStack);
1089template <
typename T,
typename TNearPo
intLocator>
1090void Triangulation<T, TNearPointLocator>::insertVertex(
const VertInd iVert)
1092 const V2d<T>& v = vertices[iVert];
1093 const VertInd walkStart = m_nearPtLocator.nearPoint(v, vertices);
1094 insertVertex(iVert, walkStart);
1095 tryAddVertexToLocator(iVert);
1098template <
typename T,
typename TNearPo
intLocator>
1099void Triangulation<T, TNearPointLocator>::ensureDelaunayByEdgeFlips(
1101 std::stack<TriInd>& triStack)
1103 TriInd iTopo, n1, n2, n3, n4;
1105 while(!triStack.empty())
1107 const TriInd iT = triStack.top();
1110 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1111 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1113 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1115 triStack.push(iTopo);
1133template <
typename T,
typename TNearPo
intLocator>
1134void Triangulation<T, TNearPointLocator>::edgeFlipInfo(
1151 const Triangle& t = triangles[iT];
1152 if(t.vertices[0] == iV1)
1154 iV2 = t.vertices[1];
1155 iV4 = t.vertices[2];
1156 n1 = t.neighbors[0];
1157 n3 = t.neighbors[2];
1158 iTopo = t.neighbors[1];
1160 else if(t.vertices[1] == iV1)
1162 iV2 = t.vertices[2];
1163 iV4 = t.vertices[0];
1164 n1 = t.neighbors[1];
1165 n3 = t.neighbors[0];
1166 iTopo = t.neighbors[2];
1170 iV2 = t.vertices[0];
1171 iV4 = t.vertices[1];
1172 n1 = t.neighbors[2];
1173 n3 = t.neighbors[1];
1174 iTopo = t.neighbors[0];
1176 if(iTopo == noNeighbor)
1178 const Triangle& tOpo = triangles[iTopo];
1179 if(tOpo.neighbors[0] == iT)
1181 iV3 = tOpo.vertices[2];
1182 n2 = tOpo.neighbors[1];
1183 n4 = tOpo.neighbors[2];
1185 else if(tOpo.neighbors[1] == iT)
1187 iV3 = tOpo.vertices[0];
1188 n2 = tOpo.neighbors[2];
1189 n4 = tOpo.neighbors[0];
1193 iV3 = tOpo.vertices[1];
1194 n2 = tOpo.neighbors[0];
1195 n4 = tOpo.neighbors[1];
1222template <
typename T,
typename TNearPo
intLocator>
1223bool Triangulation<T, TNearPointLocator>::isFlipNeeded(
1229 if(fixedEdges.count(Edge(iV2, iV4)))
1231 const V2d<T>& v1 = vertices[iV1];
1232 const V2d<T>& v2 = vertices[iV2];
1233 const V2d<T>& v3 = vertices[iV3];
1234 const V2d<T>& v4 = vertices[iV4];
1292template <
typename T,
typename TNearPo
intLocator>
1310 changeNeighbor(n1, iT, iTopo);
1311 changeNeighbor(n4, iTopo, iT);
1317 setAdjacentTriangle(v4, iT);
1318 setAdjacentTriangle(v2, iTopo);
1338template <
typename T,
typename TNearPo
intLocator>
1340Triangulation<T, TNearPointLocator>::insertVertexInsideTriangle(
1344 const TriInd iNewT1 = addTriangle();
1345 const TriInd iNewT2 = addTriangle();
1347 Triangle& t = triangles[iT];
1348 const array<VertInd, 3> vv = t.vertices;
1349 const array<TriInd, 3> nn = t.neighbors;
1350 const VertInd v1 = vv[0], v2 = vv[1], v3 = vv[2];
1351 const TriInd n1 = nn[0], n2 = nn[1], n3 = nn[2];
1359 setAdjacentTriangle(v, iT);
1360 setAdjacentTriangle(v3, iNewT1);
1362 changeNeighbor(n2, iT, iNewT1);
1363 changeNeighbor(n3, iT, iNewT2);
1365 std::stack<TriInd> newTriangles;
1366 newTriangles.push(iT);
1367 newTriangles.push(iNewT1);
1368 newTriangles.push(iNewT2);
1369 return newTriangles;
1385template <
typename T,
typename TNearPo
intLocator>
1386std::stack<TriInd> Triangulation<T, TNearPointLocator>::insertVertexOnEdge(
1391 const TriInd iTnew1 = addTriangle();
1392 const TriInd iTnew2 = addTriangle();
1394 Triangle& t1 = triangles[iT1];
1395 Triangle& t2 = triangles[iT2];
1397 const VertInd v1 = t1.vertices[i];
1399 const TriInd n1 = t1.neighbors[i];
1400 const TriInd n4 = t1.neighbors[
cw(i)];
1402 const VertInd v3 = t2.vertices[i];
1404 const TriInd n3 = t2.neighbors[i];
1405 const TriInd n2 = t2.neighbors[
cw(i)];
1413 setAdjacentTriangle(v, iT1);
1414 setAdjacentTriangle(v4, iTnew1);
1416 changeNeighbor(n4, iT1, iTnew1);
1417 changeNeighbor(n3, iT2, iTnew2);
1419 std::stack<TriInd> newTriangles;
1420 newTriangles.push(iT1);
1421 newTriangles.push(iTnew2);
1422 newTriangles.push(iT2);
1423 newTriangles.push(iTnew1);
1424 return newTriangles;
1427template <
typename T,
typename TNearPo
intLocator>
1429Triangulation<T, TNearPointLocator>::trianglesAt(
const V2d<T>& pos)
const
1431 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1434 const Triangle& t = triangles[i];
1435 const V2d<T>& v1 = vertices[t.vertices[0]];
1436 const V2d<T>& v2 = vertices[t.vertices[1]];
1437 const V2d<T>& v3 = vertices[t.vertices[2]];
1439 if(loc == PtTriLocation::Outside)
1449template <
typename T,
typename TNearPo
intLocator>
1450TriInd Triangulation<T, TNearPointLocator>::walkTriangles(
1452 const V2d<T>& pos)
const
1455 TriInd currTri = m_vertTris[startVertex];
1457 detail::SplitMix64RandGen prng;
1460 const Triangle& t = triangles[currTri];
1463 const Index offset(prng() % 3);
1466 const Index i((i_ + offset) % 3);
1467 const V2d<T>& vStart = vertices[t.vertices[i]];
1468 const V2d<T>& vEnd = vertices[t.vertices[
ccw(i)]];
1471 const TriInd iN = t.neighbors[i];
1472 if(edgeCheck == PtLineLocation::Right && iN != noNeighbor)
1483template <
typename T,
typename TNearPo
intLocator>
1484array<TriInd, 2> Triangulation<T, TNearPointLocator>::walkingSearchTrianglesAt(
1486 const VertInd startVertex)
const
1488 const V2d<T> v = vertices[iV];
1489 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1490 const TriInd iT = walkTriangles(startVertex, v);
1492 const Triangle& t = triangles[iT];
1493 const V2d<T>& v1 = vertices[t.vertices[0]];
1494 const V2d<T>& v2 = vertices[t.vertices[1]];
1495 const V2d<T>& v3 = vertices[t.vertices[2]];
1498 if(loc == PtTriLocation::Outside)
1500 if(loc == PtTriLocation::OnVertex)
1502 const VertInd iDupe = v1 == v ? t.vertices[0]
1503 : v2 == v ? t.vertices[1]
1505 throw DuplicateVertexError(
1531template <
typename T,
typename TNearPo
intLocator>
1538 const array<TriInd, 3>& triNs = t.
neighbors;
1539 const array<TriInd, 3>& triOpoNs = tOpo.
neighbors;
1540 const array<VertInd, 3>& triVs = t.
vertices;
1541 const array<VertInd, 3>& triOpoVs = tOpo.
vertices;
1546 const TriInd n1 = triNs[i];
1549 const VertInd v3 = triOpoVs[i];
1551 const TriInd n4 = triOpoNs[i];
1558 changeNeighbor(n1, iT, iTopo);
1559 changeNeighbor(n4, iTopo, iT);
1565 setAdjacentTriangle(v4, iT);
1566 setAdjacentTriangle(v2, iTopo);
1570template <
typename T,
typename TNearPo
intLocator>
1573 const TriInd oldNeighbor,
1574 const TriInd newNeighbor)
1576 if(iT == noNeighbor)
1580 nn[0] == oldNeighbor || nn[1] == oldNeighbor || nn[2] == oldNeighbor);
1581 if(nn[0] == oldNeighbor)
1582 nn[0] = newNeighbor;
1583 else if(nn[1] == oldNeighbor)
1584 nn[1] = newNeighbor;
1586 nn[2] = newNeighbor;
1589template <
typename T,
typename TNearPo
intLocator>
1590void Triangulation<T, TNearPointLocator>::changeNeighbor(
1594 const TriInd newNeighbor)
1596 assert(iT != noNeighbor);
1597 Triangle& t = triangles[iT];
1598 t.neighbors[
edgeNeighborInd(t.vertices, iVedge1, iVedge2)] = newNeighbor;
1601template <
typename T,
typename TNearPo
intLocator>
1602void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygon(
1603 const std::vector<VertInd>& poly,
1604 unordered_map<Edge, TriInd>& outerTris,
1607 std::vector<TriangulatePseudoPolygonTask>& iterations)
1609 assert(poly.size() > 2);
1612 iterations.push_back(make_tuple(
1614 static_cast<IndexSizeType
>(poly.size() - 1),
1618 while(!iterations.empty())
1620 triangulatePseudoPolygonIteration(poly, outerTris, iterations);
1624template <
typename T,
typename TNearPo
intLocator>
1625void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygonIteration(
1626 const std::vector<VertInd>& poly,
1627 unordered_map<Edge, TriInd>& outerTris,
1628 std::vector<TriangulatePseudoPolygonTask>& iterations)
1630 IndexSizeType iA, iB;
1633 assert(!iterations.empty());
1634 tie(iA, iB, iT, iParent, iInParent) = iterations.back();
1635 iterations.pop_back();
1636 assert(iB - iA > 1 && iT != noNeighbor && iParent != noNeighbor);
1637 Triangle& t = triangles[iT];
1639 const IndexSizeType iC = findDelaunayPoint(poly, iA, iB);
1651 const TriInd iNext = addTriangle();
1652 iterations.push_back(make_tuple(iC, iB, iNext, iT,
Index(1)));
1656 const Edge outerEdge(b, c);
1657 const TriInd outerTri = outerTris.at(outerEdge);
1658 if(outerTri != noNeighbor)
1660 assert(outerTri != iT);
1661 t.neighbors[1] = outerTri;
1662 changeNeighbor(outerTri, c, b, iT);
1665 outerTris.at(outerEdge) = iT;
1670 const TriInd iNext = addTriangle();
1671 iterations.push_back(make_tuple(iA, iC, iNext, iT,
Index(2)));
1675 const Edge outerEdge(c, a);
1676 const TriInd outerTri = outerTris.at(outerEdge);
1677 if(outerTri != noNeighbor)
1679 assert(outerTri != iT);
1680 t.neighbors[2] = outerTri;
1681 changeNeighbor(outerTri, c, a, iT);
1684 outerTris.at(outerEdge) = iT;
1689 triangles[iParent].neighbors[iInParent] = iT;
1690 t.neighbors[0] = iParent;
1691 t.vertices = detail::arr3(a, b, c);
1692 setAdjacentTriangle(c, iT);
1695template <
typename T,
typename TNearPo
intLocator>
1696IndexSizeType Triangulation<T, TNearPointLocator>::findDelaunayPoint(
1697 const std::vector<VertInd>& poly,
1698 const IndexSizeType iA,
1699 const IndexSizeType iB)
const
1701 assert(iB - iA > 1);
1702 const V2d<T>& a = vertices[poly[iA]];
1703 const V2d<T>& b = vertices[poly[iB]];
1704 IndexSizeType out = iA + 1;
1705 const V2d<T>* c = &vertices[poly[out]];
1706 for(IndexSizeType i = iA + 1; i < iB; ++i)
1708 const V2d<T>& v = vertices[poly[i]];
1715 assert(out > iA && out < iB);
1719template <
typename T,
typename TNearPo
intLocator>
1721 const std::vector<
V2d<T> >& newVertices)
1723 return insertVertices(
1727template <
typename T,
typename TNearPo
intLocator>
1730 return m_vertTris.empty() && !vertices.empty();
1733template <
typename T,
typename TNearPo
intLocator>
1734unordered_map<TriInd, LayerDepth>
1736 std::stack<TriInd> seeds,
1738 std::vector<LayerDepth>& triDepths)
const
1740 unordered_map<TriInd, LayerDepth> behindBoundary;
1741 while(!seeds.empty())
1743 const TriInd iT = seeds.top();
1745 triDepths[iT] = std::min(triDepths[iT], layerDepth);
1746 behindBoundary.erase(iT);
1752 if(iN == noNeighbor || triDepths[iN] <= layerDepth)
1754 if(fixedEdges.count(opEdge))
1756 const unordered_map<Edge, LayerDepth>::const_iterator cit =
1757 overlapCount.find(opEdge);
1758 const LayerDepth triDepth = cit == overlapCount.end()
1760 : layerDepth + cit->second + 1;
1761 behindBoundary[iN] = triDepth;
1767 return behindBoundary;
1770template <
typename T,
typename TNearPo
intLocator>
1771std::vector<LayerDepth>
1774 std::vector<LayerDepth> triDepths(
1775 triangles.size(), std::numeric_limits<LayerDepth>::max());
1776 std::stack<TriInd> seeds(TriDeque(1, m_vertTris[0]));
1780 unordered_map<LayerDepth, TriIndUSet> seedsByDepth;
1783 const unordered_map<TriInd, LayerDepth>& newSeeds =
1784 peelLayer(seeds, layerDepth, triDepths);
1786 seedsByDepth.erase(layerDepth);
1787 typedef unordered_map<TriInd, LayerDepth>::const_iterator Iter;
1788 for(Iter it = newSeeds.begin(); it != newSeeds.end(); ++it)
1790 deepestSeedDepth = std::max(deepestSeedDepth, it->second);
1791 seedsByDepth[it->second].insert(it->first);
1793 const TriIndUSet& nextLayerSeeds = seedsByDepth[layerDepth + 1];
1794 seeds = std::stack<TriInd>(
1795 TriDeque(nextLayerSeeds.begin(), nextLayerSeeds.end()));
1797 }
while(!seeds.empty() || deepestSeedDepth > layerDepth);
1802template <
typename T,
typename TNearPo
intLocator>
1806 for(
VertInd iV = superGeomVertCount; iV < vertices.size(); ++iV)
1812template <
typename T,
typename TNearPo
intLocator>
1813void Triangulation<T, TNearPointLocator>::insertVertices_Randomized(
1816 std::size_t vertexCount = vertices.size() - superGeomVertCount;
1817 std::vector<VertInd> ii(vertexCount);
1818 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
1819 detail::random_shuffle(ii.begin(), ii.end());
1820 for(std::vector<VertInd>::iterator it = ii.begin(); it != ii.end(); ++it)
1830template <
typename T>
1831inline double log2_bc(T x)
1833#ifdef CDT_CXX11_IS_SUPPORTED
1834 return std::log2(x);
1836 static double log2_constant = std::log(2.0);
1837 return std::log(
static_cast<double>(x)) / log2_constant;
1847 const int filledLayerPow2 =
1848 static_cast<int>(std::floor(log2_bc(vertexCount)) - 1);
1849 const std::size_t nodesInFilledTree =
1850 static_cast<std::size_t
>(std::pow(2., filledLayerPow2 + 1) - 1);
1851 const std::size_t nodesInLastFilledLayer =
1852 static_cast<std::size_t
>(std::pow(2., filledLayerPow2));
1853 const std::size_t nodesInLastLayer = vertexCount - nodesInFilledTree;
1854 return nodesInLastLayer >= nodesInLastFilledLayer
1855 ? nodesInLastFilledLayer + nodesInLastLayer -
1856 nodesInLastFilledLayer
1857 : nodesInLastFilledLayer;
1860template <
typename T>
1866 , m_front(m_vec.begin())
1867 , m_back(m_vec.begin())
1874 const T& front()
const
1882 if(m_front == m_vec.end())
1883 m_front = m_vec.begin();
1886 void push(
const T& t)
1888 assert(m_size < m_vec.size());
1891 if(m_back == m_vec.end())
1892 m_back = m_vec.begin();
1895#ifdef CDT_CXX11_IS_SUPPORTED
1896 void push(
const T&& t)
1898 assert(m_size < m_vec.size());
1901 if(m_back == m_vec.end())
1902 m_back = m_vec.begin();
1907 std::vector<T> m_vec;
1908 typename std::vector<T>::iterator m_front;
1909 typename std::vector<T>::iterator m_back;
1913template <
typename T>
1916 const std::vector<V2d<T> >& m_vertices;
1920 : m_vertices(vertices)
1924 return m_vertices[a].x < m_vertices[b].x;
1928template <
typename T>
1931 const std::vector<V2d<T> >& m_vertices;
1935 : m_vertices(vertices)
1939 return m_vertices[a].y < m_vertices[b].y;
1945template <
typename T,
typename TNearPo
intLocator>
1953 static_cast<IndexSizeType
>(vertices.size()) - superGeomVertCount;
1954 if(vertexCount <= 0)
1956 std::vector<VertInd> ii(vertexCount);
1957 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
1959 typedef std::vector<VertInd>::iterator It;
1961 detail::maxQueueLengthBFSKDTree(vertexCount));
1962 queue.push(make_tuple(ii.begin(), ii.end(), boxMin, boxMax,
VertInd(0)));
1965 V2d<T> newBoxMin, newBoxMax;
1971 while(!queue.empty())
1973 tie(first, last, boxMin, boxMax, parent) = queue.front();
1975 assert(first != last);
1977 const std::ptrdiff_t len = std::distance(first, last);
1980 insertVertex(*first, parent);
1983 const It midIt = first + len / 2;
1984 if(boxMax.
x - boxMin.
x >= boxMax.
y - boxMin.
y)
1986 detail::portable_nth_element(first, midIt, last, cmpX);
1988 const T split = vertices[mid].x;
1989 newBoxMin.
x = split;
1990 newBoxMin.
y = boxMin.
y;
1991 newBoxMax.
x = split;
1992 newBoxMax.
y = boxMax.
y;
1996 detail::portable_nth_element(first, midIt, last, cmpY);
1998 const T split = vertices[mid].y;
1999 newBoxMin.
x = boxMin.
x;
2000 newBoxMin.
y = split;
2001 newBoxMax.
x = boxMax.
x;
2002 newBoxMax.
y = split;
2004 insertVertex(mid, parent);
2007 queue.push(make_tuple(first, midIt, boxMin, newBoxMax, mid));
2009 if(midIt + 1 != last)
2011 queue.push(make_tuple(midIt + 1, last, newBoxMin, boxMax, mid));
2016template <
typename T,
typename TNearPo
intLocator>
2017std::pair<TriInd, TriInd> Triangulation<T, TNearPointLocator>::edgeTriangles(
2021 const TriInd triStart = m_vertTris[a];
2022 assert(triStart != noNeighbor);
2023 TriInd iT = triStart, iTNext = triStart;
2027 const Triangle& t = triangles[iT];
2028 tie(iTNext, iV) = t.
next(a);
2029 assert(iTNext != noNeighbor);
2032 return std::make_pair(iT, iTNext);
2035 }
while(iT != triStart);
2036 return std::make_pair(invalidIndex, invalidIndex);
2039template <
typename T,
typename TNearPo
intLocator>
2040bool Triangulation<T, TNearPointLocator>::hasEdge(
2044 return edgeTriangles(a, b).first != invalidIndex;
2047template <
typename T,
typename TNearPo
intLocator>
2048void Triangulation<T, TNearPointLocator>::setAdjacentTriangle(
2052 assert(t != noNeighbor);
2055 triangles[t].vertices[0] == v || triangles[t].vertices[1] == v ||
2056 triangles[t].vertices[2] == v);
2059template <
typename T,
typename TNearPo
intLocator>
2060void Triangulation<T, TNearPointLocator>::pivotVertexTriangleCW(
const VertInd v)
2062 assert(m_vertTris[v] != noNeighbor);
2063 m_vertTris[v] = triangles[m_vertTris[v]].next(v).first;
2064 assert(m_vertTris[v] != noNeighbor);
2066 triangles[m_vertTris[v]].vertices[0] == v ||
2067 triangles[m_vertTris[v]].vertices[1] == v ||
2068 triangles[m_vertTris[v]].vertices[2] == v);
2071template <
typename T,
typename TNearPo
intLocator>
2072void Triangulation<T, TNearPointLocator>::tryAddVertexToLocator(
const VertInd v)
2074 if(!m_nearPtLocator.empty())
2075 m_nearPtLocator.addPoint(v, vertices);
2078template <
typename T,
typename TNearPo
intLocator>
2079void Triangulation<T, TNearPointLocator>::tryInitNearestPointLocator()
2081 if(!vertices.empty() && m_nearPtLocator.empty())
2083 m_nearPtLocator.initialize(vertices);
array< T, 3 > arr3(const T &v0, const T &v1, const T &v2)
Needed for c++03 compatibility (no uniform initialization available)
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...
Data structure representing a 2D constrained Delaunay triangulation.
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.
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.
Triangulation()
Default constructor.
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.
#define CDT_SOURCE_LOCATION
Macro for getting source location.
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.
VertInd edge_get_v2(const Edge &e)
Get edge second vertex.
std::vector< TriInd > TriIndVec
Vector of triangle indices.
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_INLINE_IF_HEADER_ONLY bool touchesSuperTriangle(const Triangle &t)
Check if any of triangle's vertices belongs to a super-triangle.
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.
unordered_set< TriInd > TriIndUSet
Hash table of triangles.
CDT_EXPORT Index ccw(Index i)
Advance vertex or neighbor index counter-clockwise.
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 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.
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.
Edge connecting two vertices: vertex with smaller index is always first.
VertInd v2() const
V2 getter.
VertInd v1() const
V1 getter.
@ TryResolve
attempt to resolve constraint edge intersections
@ NotAllowed
constraint edge intersections are not allowed
@ DontCheck
No checks: slightly faster but less safe.
@ SuperTriangle
conventional super-triangle
@ Custom
user-specified custom geometry (e.g., grid)
Triangulation triangle (counter-clockwise winding)
VerticesArr3 vertices
triangle's three vertices
static Triangle make(const array< VertInd, 3 > &vertices, const array< TriInd, 3 > &neighbors)
Factory method.
NeighborsArr3 neighbors
triangle's three neighbors
std::pair< TriInd, VertInd > next(const VertInd i) const
Next triangle adjacent to a vertex (clockwise)
static V2d make(T x, T y)
Create vector from X and Y coordinates.
@ Auto
Automatic insertion order optimized for better performance.