Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/CDT.Core/Triangulation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ public DuplicateVertexException(int v1, int v2)
}
}

/// <summary>
/// Thrown when a mutating method is called after the triangulation has been finalized
/// (i.e., after any <c>Erase*</c> method has been called).
/// </summary>
public sealed class TriangulationFinalizedException : TriangulationException
{
/// <inheritdoc/>
public TriangulationFinalizedException()
: base("The triangulation has already been finalized. No further modifications are allowed after calling an Erase method.")
{ }
}

/// <summary>Thrown when intersecting constraint edges are detected and <see cref="IntersectingConstraintEdges.NotAllowed"/> is set.</summary>
public sealed class IntersectingConstraintsException : TriangulationException
{
Expand Down Expand Up @@ -154,6 +166,7 @@ public Triangulation(
/// <summary>Inserts a list of vertices into the triangulation.</summary>
public void InsertVertices(IReadOnlyList<V2d<T>> newVertices)
{
if (IsFinalized) throw new TriangulationFinalizedException();
if (newVertices.Count == 0) return;

bool isFirstInsertion = _kdTree == null && _verticesCount == 0;
Expand Down Expand Up @@ -217,6 +230,7 @@ public void InsertVertices(IReadOnlyList<V2d<T>> newVertices)
/// <summary>Inserts constraint edges (constrained Delaunay triangulation).</summary>
public void InsertEdges(IReadOnlyList<Edge> edges)
{
if (IsFinalized) throw new TriangulationFinalizedException();
var remaining = new List<Edge>(4);
var tppTasks = new List<TriangulatePseudoPolygonTask>(8);
var polyL = new List<int>(8);
Expand Down Expand Up @@ -246,6 +260,7 @@ public void InsertEdges(IReadOnlyList<Edge> edges)
/// </summary>
public void ConformToEdges(IReadOnlyList<Edge> edges)
{
if (IsFinalized) throw new TriangulationFinalizedException();
var remaining = new List<ConformToEdgeTask>(8);
var flipStack = new Stack<int>(4);
var flippedFixed = new List<Edge>(8);
Expand All @@ -270,6 +285,7 @@ public void ConformToEdges(IReadOnlyList<Edge> edges)
/// <summary>Removes the super-triangle to produce a convex hull triangulation.</summary>
public void EraseSuperTriangle()
{
if (IsFinalized) throw new TriangulationFinalizedException();
if (_superGeomType != SuperGeometryType.SuperTriangle) return;
var toErase = new HashSet<int>();
for (int i = 0; i < _trianglesCount; i++)
Expand All @@ -283,6 +299,7 @@ public void EraseSuperTriangle()
/// <summary>Removes all outer triangles (flood-fill from super-triangle vertex until a constraint edge).</summary>
public void EraseOuterTriangles()
{
if (IsFinalized) throw new TriangulationFinalizedException();
if (_vertTris[0] == Indices.NoNeighbor)
throw new TriangulationException("No vertex triangle data – already finalized?");
var seeds = new Stack<int>();
Expand All @@ -297,6 +314,7 @@ public void EraseOuterTriangles()
/// </summary>
public void EraseOuterTrianglesAndHoles()
{
if (IsFinalized) throw new TriangulationFinalizedException();
var depths = CalculateTriangleDepths();
var toErase = new HashSet<int>();
for (int i = 0; i < _trianglesCount; i++)
Expand Down
75 changes: 75 additions & 0 deletions test/CDT.Tests/TriangulationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,81 @@ public void FivePoints_ValidTopology()
Assert.True(TopologyVerifier.VerifyTopology(cdt));
Assert.Equal(5, cdt.Vertices.Length);
}

// -------------------------------------------------------------------------
// IsFinalized guard checks
// -------------------------------------------------------------------------

[Fact]
public void InsertVertices_AfterFinalized_ThrowsTriangulationFinalizedException()
{
var cdt = CreateCdt();
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(0.5, 1)]);
cdt.EraseSuperTriangle();

Assert.True(cdt.IsFinalized);
Assert.Throws<TriangulationFinalizedException>(() =>
cdt.InsertVertices([Pt(2, 0)]));
}

[Fact]
public void InsertEdges_AfterFinalized_ThrowsTriangulationFinalizedException()
{
var cdt = CreateCdt();
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
cdt.EraseSuperTriangle();

Assert.True(cdt.IsFinalized);
Assert.Throws<TriangulationFinalizedException>(() =>
cdt.InsertEdges([new Edge(0, 2)]));
}

[Fact]
public void ConformToEdges_AfterFinalized_ThrowsTriangulationFinalizedException()
{
var cdt = CreateCdt();
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
cdt.EraseSuperTriangle();

Assert.True(cdt.IsFinalized);
Assert.Throws<TriangulationFinalizedException>(() =>
cdt.ConformToEdges([new Edge(0, 2)]));
}

[Fact]
public void EraseSuperTriangle_AfterFinalized_ThrowsTriangulationFinalizedException()
{
var cdt = CreateCdt();
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(0.5, 1)]);
cdt.EraseSuperTriangle();

Assert.True(cdt.IsFinalized);
Assert.Throws<TriangulationFinalizedException>(() => cdt.EraseSuperTriangle());
}

[Fact]
public void EraseOuterTriangles_AfterFinalized_ThrowsTriangulationFinalizedException()
{
var cdt = CreateCdt();
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
cdt.InsertEdges([new Edge(0, 1), new Edge(1, 2), new Edge(2, 3), new Edge(3, 0)]);
cdt.EraseOuterTriangles();

Assert.True(cdt.IsFinalized);
Assert.Throws<TriangulationFinalizedException>(() => cdt.EraseOuterTriangles());
}

[Fact]
public void EraseOuterTrianglesAndHoles_AfterFinalized_ThrowsTriangulationFinalizedException()
{
var cdt = CreateCdt();
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
cdt.InsertEdges([new Edge(0, 1), new Edge(1, 2), new Edge(2, 3), new Edge(3, 0)]);
cdt.EraseOuterTrianglesAndHoles();

Assert.True(cdt.IsFinalized);
Assert.Throws<TriangulationFinalizedException>(() => cdt.EraseOuterTrianglesAndHoles());
}
}

/// <summary>Triangulation tests for <see cref="double"/>.</summary>
Expand Down