Skip to content

Commit

Permalink
Refine after faces deletion + split fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Islam0mar committed Aug 22, 2023
1 parent 23b928b commit aaac2dd
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 38 deletions.
2 changes: 1 addition & 1 deletion CDT/include/CDTUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ bool isEncroachingOnEdge(
* the angle between v and edge end points is obtuse
*/
return (edgeStart.x - v.x) * (edgeEnd.x - v.x) +
(edgeStart.y - v.y) * (edgeEnd.y - v.y) <=
(edgeStart.y - v.y) * (edgeEnd.y - v.y) <
T(0);
}

Expand Down
30 changes: 23 additions & 7 deletions CDT/include/Triangulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,22 @@ class CDT_EXPORT Triangulation
*/
void refineTriangles(
VertInd maxVerticesToInsert,
TriIndUSet& toErase,
RefinementCriterion::Enum refinementCriterion =
RefinementCriterion::SmallestAngle,
T refinementThreshold = 20 / 180.0 * M_PI);
/**
* Collect triangles adjacent to super triangle
*/
TriIndUSet collectSuperTriangle();
/**
* Collect outside of constrained boundary using growing
*/
TriIndUSet collectOuterTriangles();
/**
* Collect outside of constrained boundary and auto-detected holes
*/
TriIndUSet collectOuterTrianglesAndHoles();
/**
* Erase triangles adjacent to super triangle
*
Expand Down Expand Up @@ -385,6 +398,13 @@ class CDT_EXPORT Triangulation
TriIndVec& VertTrisInternal();
/// @}

/**
* Remove super-triangle (if used) and triangles with specified indices.
* Adjust internal triangulation state accordingly.
* @removedTriangles indices of triangles to remove
*/
void finalizeTriangulation(const TriIndUSet& removedTriangles);

private:
/*____ Detail __*/
void addSuperTriangle(const Box2d<T>& box);
Expand Down Expand Up @@ -534,6 +554,7 @@ class CDT_EXPORT Triangulation
EdgeQueue encroachedEdges,
VertInd& newVertBudget,
VertInd steinerVerticesOffset,
TriIndUSet& toErase,
const V2d<T>* circumcenterOrNull = NULL,
RefinementCriterion::Enum refinementCriterion =
RefinementCriterion::SmallestAngle,
Expand All @@ -542,7 +563,8 @@ class CDT_EXPORT Triangulation
Edge e,
TriInd iT,
TriInd iTopo,
VertInd steinerVerticesOffset);
VertInd steinerVerticesOffset,
TriIndUSet& toErase);
void changeNeighbor(TriInd iT, TriInd oldNeighbor, TriInd newNeighbor);
void changeNeighbor(
TriInd iT,
Expand All @@ -565,12 +587,6 @@ class CDT_EXPORT Triangulation
IndexSizeType iB) const;
TriInd addTriangle(const Triangle& t); // note: invalidates iterators!
TriInd addTriangle(); // note: invalidates triangle iterators!
/**
* Remove super-triangle (if used) and triangles with specified indices.
* Adjust internal triangulation state accordingly.
* @removedTriangles indices of triangles to remove
*/
void finalizeTriangulation(const TriIndUSet& removedTriangles);
TriIndUSet growToBoundary(std::stack<TriInd> seeds) const;
void fixEdge(const Edge& edge, BoundaryOverlapCount overlaps);
void fixEdge(const Edge& edge);
Expand Down
113 changes: 91 additions & 22 deletions CDT/include/Triangulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,33 +128,34 @@ void Triangulation<T, TNearPointLocator>::eraseDummies()
}

template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::eraseSuperTriangle()
TriIndUSet Triangulation<T, TNearPointLocator>::collectSuperTriangle()
{
TriIndUSet toErase;
if(m_superGeomType != SuperGeometryType::SuperTriangle)
return;
return toErase;

// find triangles adjacent to super-triangle's vertices
TriIndUSet toErase;
for(TriInd iT(0); iT < TriInd(triangles.size()); ++iT)
{
Triangle& t = triangles[iT];
if(t.vertices[0] < 3 || t.vertices[1] < 3 || t.vertices[2] < 3)
toErase.insert(iT);
}
finalizeTriangulation(toErase);
return toErase;
}

template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::eraseOuterTriangles()
TriIndUSet Triangulation<T, TNearPointLocator>::collectOuterTriangles()
{
// make dummy triangles adjacent to super-triangle's vertices
assert(m_vertTris[0] != noNeighbor);
const std::stack<TriInd> seed(std::deque<TriInd>(1, m_vertTris[0]));
const TriIndUSet toErase = growToBoundary(seed);
finalizeTriangulation(toErase);
return toErase;
}

template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::eraseOuterTrianglesAndHoles()
TriIndUSet Triangulation<T, TNearPointLocator>::collectOuterTrianglesAndHoles()
{
const std::vector<LayerDepth> triDepths = calculateTriangleDepths();
TriIndUSet toErase;
Expand All @@ -164,6 +165,30 @@ void Triangulation<T, TNearPointLocator>::eraseOuterTrianglesAndHoles()
if(triDepths[iT] % 2 == 0)
toErase.insert(static_cast<TriInd>(iT));
}
return toErase;
}

template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::eraseSuperTriangle()
{
if(m_superGeomType != SuperGeometryType::SuperTriangle)
return;

const TriIndUSet toErase = collectSuperTriangle();
finalizeTriangulation(toErase);
}

template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::eraseOuterTriangles()
{
const TriIndUSet toErase = collectOuterTriangles();
finalizeTriangulation(toErase);
}

template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::eraseOuterTrianglesAndHoles()
{
const TriIndUSet toErase = collectOuterTrianglesAndHoles();
finalizeTriangulation(toErase);
}

Expand Down Expand Up @@ -1274,9 +1299,9 @@ bool Triangulation<T, TNearPointLocator>::isRefinementNeeded(
switch(refinementCriterion)
{
case RefinementCriterion::SmallestAngle:
return smallestAngle(a, b, c) <= refinementThreshold;
return smallestAngle(a, b, c) < refinementThreshold;
case RefinementCriterion::LargestArea:
return area(a, b, c) >= refinementThreshold;
return area(a, b, c) > refinementThreshold;
}
assert(false); // unreachable code
return false;
Expand Down Expand Up @@ -1334,6 +1359,7 @@ TriIndVec Triangulation<T, TNearPointLocator>::resolveEncroachedEdges(
EdgeQueue encroachedEdges,
VertInd& remainingVertexBudget,
const VertInd steinerVerticesOffset,
TriIndUSet& toErase,
const V2d<T>* const circumcenterOrNull,
const RefinementCriterion::Enum refinementCriterion,
const T badTriangleThreshold)
Expand All @@ -1352,8 +1378,8 @@ TriIndVec Triangulation<T, TNearPointLocator>::resolveEncroachedEdges(
TriInd iT, iTopo;
std::tie(iT, iTopo) = edgeTriangles(edge.v1(), edge.v2());
assert(iT != invalidIndex && iTopo != invalidIndex);
const VertInd i =
splitEncroachedEdge(edge, iT, iTopo, steinerVerticesOffset);
const VertInd i = splitEncroachedEdge(
edge, iT, iTopo, steinerVerticesOffset, toErase);
--remainingVertexBudget;

const TriInd start = m_vertTris[i];
Expand Down Expand Up @@ -1399,15 +1425,25 @@ VertInd Triangulation<T, TNearPointLocator>::splitEncroachedEdge(
const Edge splitEdge,
const TriInd iT,
const TriInd iTopo,
const VertInd steinerVerticesOffset)
const VertInd steinerVerticesOffset,
TriIndUSet& toErase)
{
const VertInd iMid = static_cast<VertInd>(vertices.size());
const V2d<T>& start = vertices[splitEdge.v1()];
const V2d<T>& end = vertices[splitEdge.v2()];
T split = T(0.5);
// check if any of the split edge vertices are Steiner vertices
if(splitEdge.v1() >= steinerVerticesOffset ||
splitEdge.v2() >= steinerVerticesOffset)
// check if constrained subsegment is connnected to another constrained
// subsegment (small angle)
VertInd v3 = opposedVertex(triangles[iT], iTopo);
VertInd v4 = opposedVertex(triangles[iTopo], iT);
if((splitEdge.v1() < steinerVerticesOffset &&
splitEdge.v2() >= steinerVerticesOffset &&
(fixedEdges.find(Edge(v3, splitEdge.v1())) != fixedEdges.end() ||
fixedEdges.find(Edge(v4, splitEdge.v1())) != fixedEdges.end())) ||
(splitEdge.v2() < steinerVerticesOffset &&
splitEdge.v1() >= steinerVerticesOffset &&
(fixedEdges.find(Edge(v3, splitEdge.v2())) != fixedEdges.end() ||
fixedEdges.find(Edge(v4, splitEdge.v2())) != fixedEdges.end())))
{
// In Ruppert's paper, he used D(0.01) factor to divide edge length, but
// that introduces FP rounding erros, so it's avoided.
Expand All @@ -1423,7 +1459,6 @@ VertInd Triangulation<T, TNearPointLocator>::splitEncroachedEdge(
{
nearestPowerOfTwo *= T(0.5);
}
assert(abs(nearestPowerOfTwo - pow(2, round(log(d) / log(2.0)))) < 1e6);
split = nearestPowerOfTwo / len;
if(splitEdge.v1() >= steinerVerticesOffset)
split = T(1) - split;
Expand Down Expand Up @@ -1460,6 +1495,10 @@ VertInd Triangulation<T, TNearPointLocator>::splitEncroachedEdge(
std::stack<TriInd> triStack = insertVertexOnEdge(iMid, iT, iTopo);
tryAddVertexToLocator(iMid);
ensureDelaunayByEdgeFlips(mid, iMid, triStack);
if(toErase.find(iT) != toErase.end())
toErase.insert(TriInd(triangles.size() - 2));
if(toErase.find(iTopo) != toErase.end())
toErase.insert(TriInd(triangles.size() - 1));
return iMid;
}

Expand Down Expand Up @@ -2265,6 +2304,7 @@ void Triangulation<T, TNearPointLocator>::tryInitNearestPointLocator()
template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::refineTriangles(
const VertInd maxVerticesToInsert,
TriIndUSet& toErase,
const RefinementCriterion::Enum refinementCriterion,
const T refinementThreshold)
{
Expand All @@ -2278,15 +2318,22 @@ void Triangulation<T, TNearPointLocator>::refineTriangles(
VertInd remainingVertexBudget = maxVerticesToInsert;
const VertInd steinerVerticesOffset = vertices.size();
resolveEncroachedEdges(
detectEncroachedEdges(), remainingVertexBudget, steinerVerticesOffset);
detectEncroachedEdges(),
remainingVertexBudget,
steinerVerticesOffset,
toErase,
NULL,
refinementCriterion,
refinementThreshold);

std::queue<TriInd> badTriangles;
for(TriInd iT(0), n = triangles.size(); iT < n; ++iT)
{
const Triangle& t = triangles[iT];
if(t.vertices[0] < 3 || t.vertices[1] < 3 || t.vertices[2] < 3)
if(toErase.find(iT) != toErase.end())
continue;

const Triangle& t = triangles[iT];

if(isRefinementNeeded(t, refinementCriterion, refinementThreshold))
{
const V2d<T> vert = circumcenter(
Expand Down Expand Up @@ -2316,29 +2363,51 @@ void Triangulation<T, TNearPointLocator>::refineTriangles(
vertices[t.vertices[0]],
vertices[t.vertices[1]],
vertices[t.vertices[2]]);

if(locatePointTriangle(vert, vertices[0], vertices[1], vertices[2]) ==
PtTriLocation::Outside)
{
continue;
}

const VertInd iVert = static_cast<VertInd>(vertices.size());
const VertInd walkStart = m_nearPtLocator.nearPoint(vert, vertices);
const array<TriInd, 2> trisAt =
walkingSearchTrianglesAt(vert, walkStart);

if(toErase.find(trisAt[0]) != toErase.end() ||
toErase.find(trisAt[1]) != toErase.end())
continue;

const TriIndVec badTris = resolveEncroachedEdges(
detectEncroachedEdges(vert),
remainingVertexBudget,
steinerVerticesOffset,
toErase,
&vert,
refinementCriterion,
refinementThreshold);

for(IndexSizeType i(0); i < TriInd(badTris.size()); ++i)
{
badTriangles.push(badTris[i]);
}

if(badTris.empty() && remainingVertexBudget > 0)
if(vertices.size() == iVert && remainingVertexBudget > 0)
{
const VertInd iVert = static_cast<VertInd>(vertices.size());
--remainingVertexBudget;
addNewVertex(vert, noNeighbor);
insertVertex(iVert);
std::stack<TriInd> triStack =
trisAt[1] == noNeighbor
? insertVertexInsideTriangle(iVert, trisAt[0])
: insertVertexOnEdge(iVert, trisAt[0], trisAt[1]);
ensureDelaunayByEdgeFlips(vert, iVert, triStack);
tryAddVertexToLocator(iVert);
if(toErase.find(trisAt[0]) != toErase.end())
toErase.insert(TriInd(triangles.size() - 2));
if(toErase.find(trisAt[1]) != toErase.end())
toErase.insert(TriInd(triangles.size() - 1));

TriInd start = m_vertTris[iVert];
TriInd currTri = start;
do
Expand Down
Loading

0 comments on commit aaac2dd

Please sign in to comment.