From d4488e8923e70fa1f358eda761d5be40c1780628 Mon Sep 17 00:00:00 2001 From: artem-ogre Date: Thu, 7 Jul 2022 14:09:09 +0200 Subject: [PATCH] #84 #86 Performance and API improvments - Don't re-calculate triangles by vertex when finalizing triangulation (don't pay for what you don't use) - If needed calculating triangles by vertex can be done with new `calculateTrianglesByVertex` helper - Detect if triangulation was finalized and throw exceptions if it was when adding new vertices or edges --- CDT/extras/VerifyTopology.h | 8 ++++-- CDT/include/CDT.h | 54 ++++++++++++++++++++++++++++++++----- CDT/include/CDT.hpp | 28 ++++++++++++++++--- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/CDT/extras/VerifyTopology.h b/CDT/extras/VerifyTopology.h index f3694afd..f4739173 100644 --- a/CDT/extras/VerifyTopology.h +++ b/CDT/extras/VerifyTopology.h @@ -32,9 +32,13 @@ template > inline bool verifyTopology(const CDT::Triangulation& cdt) { // Check if vertices' adjacent triangles contain vertex + const VerticesTriangles vertTris = + cdt.isFinalized() + ? calculateTrianglesByVertex(cdt.triangles, cdt.vertices.size()) + : cdt.vertTris; for(VertInd iV(0); iV < VertInd(cdt.vertices.size()); ++iV) { - const TriIndVec& vTris = cdt.vertTris[iV]; + const TriIndVec& vTris = vertTris[iV]; typedef TriIndVec::const_iterator TriIndCit; for(TriIndCit it = vTris.begin(); it != vTris.end(); ++it) { @@ -64,7 +68,7 @@ inline bool verifyTopology(const CDT::Triangulation& cdt) typedef VerticesArr3::const_iterator VCit; for(VCit it = t.vertices.begin(); it != t.vertices.end(); ++it) { - const TriIndVec& tt = cdt.vertTris[*it]; + const TriIndVec& tt = vertTris[*it]; if(std::find(tt.begin(), tt.end(), iT) == tt.end()) return false; } diff --git a/CDT/include/CDT.h b/CDT/include/CDT.h index 318fe959..aedb5cf2 100644 --- a/CDT/include/CDT.h +++ b/CDT/include/CDT.h @@ -89,6 +89,9 @@ const static VertInd noVertex(std::numeric_limits::max()); typedef unsigned short LayerDepth; typedef LayerDepth BoundaryOverlapCount; +/// Triangles by vertex index +typedef std::vector VerticesTriangles; + /** * Data structure representing a 2D constrained Delaunay triangulation * @@ -101,12 +104,17 @@ template > class CDT_EXPORT Triangulation { public: - typedef std::vector > V2dVec; ///< Vertices vector - typedef std::vector VerticesTriangles; ///< Triangles by vertex - V2dVec vertices; ///< triangulation's vertices - TriangleVec triangles; ///< triangulation's triangles - EdgeUSet fixedEdges; ///< triangulation's constraints (fixed edges) - VerticesTriangles vertTris; ///< triangles adjacent to each vertex + typedef std::vector > V2dVec; ///< Vertices vector + V2dVec vertices; ///< triangulation's vertices + TriangleVec triangles; ///< triangulation's triangles + EdgeUSet fixedEdges; ///< triangulation's constraints (fixed edges) + /** + * triangles adjacent to each vertex + * @note will be reset to empty when super-triangle is removed and + * triangulation is finalized. To re-calculate adjacent triangles use + * @ref CDT::calculateTrianglesByVertex helper + */ + VerticesTriangles vertTris; /** Stores count of overlapping boundaries for a fixed edge. If no entry is * present for an edge: no boundaries overlap. @@ -276,6 +284,13 @@ class CDT_EXPORT Triangulation */ void initializedWithCustomSuperGeometry(); + /** + * Check if the triangulation was finalized with `erase...` method and + * super-triangle was removed. + * @return true if triangulation is finalized, false otherwise + */ + bool isFinalized() const; + /** * @defgroup Advanced * Advanced methods for manually modifying the triangulation from @@ -419,6 +434,15 @@ class CDT_EXPORT Triangulation T m_minDistToConstraintEdge; }; +/** + * Calculate triangles adjacent to vertices (triangles by vertex index) + * @param triangles triangulation + * @param verticesSize total number of vertices to pre-allocate the output + * @return triangles by vertex index + */ +CDT_EXPORT VerticesTriangles +calculateTrianglesByVertex(const TriangleVec& triangles, VertInd verticesSize); + /** * Information about removed duplicated vertices. * @@ -721,6 +745,12 @@ void Triangulation::insertVertices( TGetVertexCoordX getX, TGetVertexCoordY getY) { + if(isFinalized()) + { + throw std::runtime_error( + "Triangulation was finalized with 'erase...' method. Inserting new " + "vertices is not possible"); + } detail::randGenerator.seed(9001); // ensure deterministic behavior if(vertices.empty()) { @@ -763,6 +793,12 @@ void Triangulation::insertEdges( TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd) { + if(isFinalized()) + { + throw std::runtime_error( + "Triangulation was finalized with 'erase...' method. Inserting new " + "edges is not possible"); + } for(; first != last; ++first) { // +3 to account for super-triangle vertices @@ -785,6 +821,12 @@ void Triangulation::conformToEdges( TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd) { + if(isFinalized()) + { + throw std::runtime_error( + "Triangulation was finalized with 'erase...' method. Conforming to " + "new edges is not possible"); + } for(; first != last; ++first) { // +3 to account for super-triangle vertices diff --git a/CDT/include/CDT.hpp b/CDT/include/CDT.hpp index d8c2c2a5..3b4eb6ee 100644 --- a/CDT/include/CDT.hpp +++ b/CDT/include/CDT.hpp @@ -251,7 +251,7 @@ void Triangulation::finalizeTriangulation( triangles.erase(triangles.end() - removedTriangles.size(), triangles.end()); // adjust triangles // vertices' adjacent triangles will be re-calculated - vertTris = VerticesTriangles(vertices.size()); + vertTris = VerticesTriangles(); for(TriInd iT = 0; iT < triangles.size(); ++iT) { Triangle& t = triangles[iT]; @@ -270,13 +270,11 @@ void Triangulation::finalizeTriangulation( } if(m_superGeomType == SuperGeometryType::SuperTriangle) { + // account for removed super-triangle VerticesArr3& vv = t.vertices; for(VerticesArr3::iterator v = vv.begin(); v != vv.end(); ++v) { - // account for removed super-triangle *v -= 3; - // re-calculate vertices' adjacent triangles - vertTris[*v].push_back(iT); } } } @@ -1473,6 +1471,28 @@ void Triangulation::insertVertices( newVertices.begin(), newVertices.end(), getX_V2d, getY_V2d); } +template +bool Triangulation::isFinalized() const +{ + return !vertices.empty() && vertTris.empty(); +} + +CDT_INLINE_IF_HEADER_ONLY VerticesTriangles calculateTrianglesByVertex( + const TriangleVec& triangles, + const VertInd verticesSize) +{ + VerticesTriangles vertTris(verticesSize); + for(TriInd iT = 0; iT < triangles.size(); ++iT) + { + const VerticesArr3& vv = triangles[iT].vertices; + for(VerticesArr3::const_iterator v = vv.begin(); v != vv.end(); ++v) + { + vertTris[*v].push_back(iT); + } + } + return vertTris; +} + template DuplicatesInfo RemoveDuplicates(std::vector >& vertices) {