Skip to content

Commit

Permalink
fix: refinement with constraints without holes
Browse files Browse the repository at this point in the history
Previously, refinement was not working correctly with constraints without restoring the boundaries. The constraints were ignored when these options were selected.
  • Loading branch information
andywiecko committed Oct 9, 2024
1 parent 4b8a014 commit f4ac16a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Runtime/Triangulator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
MIT License
Copyright (c) 2021 Andrzej Więckowski, Ph.D., https://github.com/andywiecko/BurstTriangulator
Expand Down Expand Up @@ -2592,7 +2592,7 @@ public void Execute(Allocator allocator, bool refineMesh, bool constrainBoundary
{
for (int he = 0; he < constrainedHalfedges.Length; he++)
{
constrainedHalfedges[he] = halfedges[he] == -1;
constrainedHalfedges[he] |= halfedges[he] == -1;
}
}

Expand Down
46 changes: 45 additions & 1 deletion Tests/TriangulatorGenericsEditorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2301,5 +2301,49 @@ public void HalfedgesForTriangulationWithRefinementTest()
false, false, false, false, true, true,
}));
}

[Test]
public void ConstraintsArePresentWithRefinementButWithoutHolesTest()
{
#if UNITY_MATHEMATICS_FIXEDPOINT
if (typeof(T) == typeof(fp2))
{
Assert.Ignore(
"This input gets stuck with this configuration.\n" +
"\n" +
"Explanation: When constraints and refinement are enabled, but restore boundary is not, \n" +
"the refinement procedure can quickly get stuck and produce an excessive number of triangles. \n" +
"According to the literature, there are many examples suggesting that one should plant holes first, \n" +
"then refine the mesh. These small triangles fall outside of `fp2` precision."
);
}
#endif

using var positions = new NativeArray<T>(LakeSuperior.Points.DynamicCast<T>(), Allocator.Persistent);
using var holes = new NativeArray<T>(LakeSuperior.Holes.DynamicCast<T>(), Allocator.Persistent);
using var constraints = new NativeArray<int>(LakeSuperior.Constraints, Allocator.Persistent);

using var triangulator = new Triangulator<T>(Allocator.Persistent)
{
Input = { Positions = positions, ConstraintEdges = constraints, HoleSeeds = default },
Settings = { RefineMesh = true, Preprocessor = Preprocessor.None, ValidateInput = true }
};

triangulator.Run();

static int NextHalfedge(int he) => he % 3 == 2 ? he - 2 : he + 1;
var triangles = triangulator.Output.Triangles;
var constrainedHalfedges = triangulator.Output.ConstrainedHalfedges;
var visited = new bool[triangulator.Output.Positions.Length];
for (int he = 0; he < constrainedHalfedges.Length; he++)
{
if (constrainedHalfedges[he])
{
visited[triangles[he]] = visited[triangles[NextHalfedge(he)]] = true;
}
}
// Naive check if all points are "visited".
Assert.That(visited[..LakeSuperior.Points.Length], Has.All.True);
}
}
}
}
18 changes: 16 additions & 2 deletions Tests/UnsafeTriangulatorEditorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,23 @@ public class UnsafeTriangulatorEditorTestsWithRefinement<T> where T : unmanaged
[Test]
public void UnsafeTriangulatorOutputTrianglesTest([Values] bool constrain, [Values] bool refine, [Values] bool holes)
{
using var positions = new NativeArray<T>(LakeSuperior.Points.Scale(1000, typeof(T) == typeof(int2)).DynamicCast<T>(), Allocator.Persistent);
#if UNITY_MATHEMATICS_FIXEDPOINT
if (typeof(T) == typeof(fp2) && constrain && refine && !holes)
{
Assert.Ignore(
"This input gets stuck with this configuration.\n" +
"\n" +
"Explanation: When constraints and refinement are enabled, but restore boundary is not, \n" +
"the refinement procedure can quickly get stuck and produce an excessive number of triangles. \n" +
"According to the literature, there are many examples suggesting that one should plant holes first, \n" +
"then refine the mesh. These small triangles fall outside of `fp2` precision."
);
}
#endif

using var positions = new NativeArray<T>(LakeSuperior.Points.DynamicCast<T>(), Allocator.Persistent);
using var constraints = new NativeArray<int>(LakeSuperior.Constraints, Allocator.Persistent);
using var holesSeeds = new NativeArray<T>(LakeSuperior.Holes.Scale(1000, typeof(T) == typeof(int2)).DynamicCast<T>(), Allocator.Persistent);
using var holesSeeds = new NativeArray<T>(LakeSuperior.Holes.DynamicCast<T>(), Allocator.Persistent);
using var triangles = new NativeList<int>(64, Allocator.Persistent);
using var triangulator = new Triangulator<T>(Allocator.Persistent)
{
Expand Down

0 comments on commit f4ac16a

Please sign in to comment.