Skip to content

Commit ca9bf15

Browse files
author
Michael Conrad
authored
Merge pull request #16 from MichaCo/copilot/add-finalized-check-to-api
Guard all mutating public API methods against post-finalization calls
2 parents c0cd08a + a99bb2d commit ca9bf15

2 files changed

Lines changed: 93 additions & 0 deletions

File tree

src/CDT.Core/Triangulation.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ public DuplicateVertexException(int v1, int v2)
3535
}
3636
}
3737

38+
/// <summary>
39+
/// Thrown when a mutating method is called after the triangulation has been finalized
40+
/// (i.e., after any <c>Erase*</c> method has been called).
41+
/// </summary>
42+
public sealed class TriangulationFinalizedException : TriangulationException
43+
{
44+
/// <inheritdoc/>
45+
public TriangulationFinalizedException()
46+
: base("The triangulation has already been finalized. No further modifications are allowed after calling an Erase method.")
47+
{ }
48+
}
49+
3850
/// <summary>Thrown when intersecting constraint edges are detected and <see cref="IntersectingConstraintEdges.NotAllowed"/> is set.</summary>
3951
public sealed class IntersectingConstraintsException : TriangulationException
4052
{
@@ -154,6 +166,7 @@ public Triangulation(
154166
/// <summary>Inserts a list of vertices into the triangulation.</summary>
155167
public void InsertVertices(IReadOnlyList<V2d<T>> newVertices)
156168
{
169+
if (IsFinalized) throw new TriangulationFinalizedException();
157170
if (newVertices.Count == 0) return;
158171

159172
bool isFirstInsertion = _kdTree == null && _verticesCount == 0;
@@ -217,6 +230,7 @@ public void InsertVertices(IReadOnlyList<V2d<T>> newVertices)
217230
/// <summary>Inserts constraint edges (constrained Delaunay triangulation).</summary>
218231
public void InsertEdges(IReadOnlyList<Edge> edges)
219232
{
233+
if (IsFinalized) throw new TriangulationFinalizedException();
220234
var remaining = new List<Edge>(4);
221235
var tppTasks = new List<TriangulatePseudoPolygonTask>(8);
222236
var polyL = new List<int>(8);
@@ -246,6 +260,7 @@ public void InsertEdges(IReadOnlyList<Edge> edges)
246260
/// </summary>
247261
public void ConformToEdges(IReadOnlyList<Edge> edges)
248262
{
263+
if (IsFinalized) throw new TriangulationFinalizedException();
249264
var remaining = new List<ConformToEdgeTask>(8);
250265
var flipStack = new Stack<int>(4);
251266
var flippedFixed = new List<Edge>(8);
@@ -270,6 +285,7 @@ public void ConformToEdges(IReadOnlyList<Edge> edges)
270285
/// <summary>Removes the super-triangle to produce a convex hull triangulation.</summary>
271286
public void EraseSuperTriangle()
272287
{
288+
if (IsFinalized) throw new TriangulationFinalizedException();
273289
if (_superGeomType != SuperGeometryType.SuperTriangle) return;
274290
var toErase = new HashSet<int>();
275291
for (int i = 0; i < _trianglesCount; i++)
@@ -283,6 +299,7 @@ public void EraseSuperTriangle()
283299
/// <summary>Removes all outer triangles (flood-fill from super-triangle vertex until a constraint edge).</summary>
284300
public void EraseOuterTriangles()
285301
{
302+
if (IsFinalized) throw new TriangulationFinalizedException();
286303
if (_vertTris[0] == Indices.NoNeighbor)
287304
throw new TriangulationException("No vertex triangle data – already finalized?");
288305
var seeds = new Stack<int>();
@@ -297,6 +314,7 @@ public void EraseOuterTriangles()
297314
/// </summary>
298315
public void EraseOuterTrianglesAndHoles()
299316
{
317+
if (IsFinalized) throw new TriangulationFinalizedException();
300318
var depths = CalculateTriangleDepths();
301319
var toErase = new HashSet<int>();
302320
for (int i = 0; i < _trianglesCount; i++)

test/CDT.Tests/TriangulationTests.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,81 @@ public void FivePoints_ValidTopology()
222222
Assert.True(TopologyVerifier.VerifyTopology(cdt));
223223
Assert.Equal(5, cdt.Vertices.Length);
224224
}
225+
226+
// -------------------------------------------------------------------------
227+
// IsFinalized guard checks
228+
// -------------------------------------------------------------------------
229+
230+
[Fact]
231+
public void InsertVertices_AfterFinalized_ThrowsTriangulationFinalizedException()
232+
{
233+
var cdt = CreateCdt();
234+
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(0.5, 1)]);
235+
cdt.EraseSuperTriangle();
236+
237+
Assert.True(cdt.IsFinalized);
238+
Assert.Throws<TriangulationFinalizedException>(() =>
239+
cdt.InsertVertices([Pt(2, 0)]));
240+
}
241+
242+
[Fact]
243+
public void InsertEdges_AfterFinalized_ThrowsTriangulationFinalizedException()
244+
{
245+
var cdt = CreateCdt();
246+
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
247+
cdt.EraseSuperTriangle();
248+
249+
Assert.True(cdt.IsFinalized);
250+
Assert.Throws<TriangulationFinalizedException>(() =>
251+
cdt.InsertEdges([new Edge(0, 2)]));
252+
}
253+
254+
[Fact]
255+
public void ConformToEdges_AfterFinalized_ThrowsTriangulationFinalizedException()
256+
{
257+
var cdt = CreateCdt();
258+
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
259+
cdt.EraseSuperTriangle();
260+
261+
Assert.True(cdt.IsFinalized);
262+
Assert.Throws<TriangulationFinalizedException>(() =>
263+
cdt.ConformToEdges([new Edge(0, 2)]));
264+
}
265+
266+
[Fact]
267+
public void EraseSuperTriangle_AfterFinalized_ThrowsTriangulationFinalizedException()
268+
{
269+
var cdt = CreateCdt();
270+
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(0.5, 1)]);
271+
cdt.EraseSuperTriangle();
272+
273+
Assert.True(cdt.IsFinalized);
274+
Assert.Throws<TriangulationFinalizedException>(() => cdt.EraseSuperTriangle());
275+
}
276+
277+
[Fact]
278+
public void EraseOuterTriangles_AfterFinalized_ThrowsTriangulationFinalizedException()
279+
{
280+
var cdt = CreateCdt();
281+
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
282+
cdt.InsertEdges([new Edge(0, 1), new Edge(1, 2), new Edge(2, 3), new Edge(3, 0)]);
283+
cdt.EraseOuterTriangles();
284+
285+
Assert.True(cdt.IsFinalized);
286+
Assert.Throws<TriangulationFinalizedException>(() => cdt.EraseOuterTriangles());
287+
}
288+
289+
[Fact]
290+
public void EraseOuterTrianglesAndHoles_AfterFinalized_ThrowsTriangulationFinalizedException()
291+
{
292+
var cdt = CreateCdt();
293+
cdt.InsertVertices([Pt(0, 0), Pt(1, 0), Pt(1, 1), Pt(0, 1)]);
294+
cdt.InsertEdges([new Edge(0, 1), new Edge(1, 2), new Edge(2, 3), new Edge(3, 0)]);
295+
cdt.EraseOuterTrianglesAndHoles();
296+
297+
Assert.True(cdt.IsFinalized);
298+
Assert.Throws<TriangulationFinalizedException>(() => cdt.EraseOuterTrianglesAndHoles());
299+
}
225300
}
226301

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

0 commit comments

Comments
 (0)