diff --git a/Runtime/Triangulator.cs b/Runtime/Triangulator.cs
index a0e8f01..d9b1625 100644
--- a/Runtime/Triangulator.cs
+++ b/Runtime/Triangulator.cs
@@ -763,12 +763,9 @@ public static class Utilities
/// The allocator to use for temporary data.
public static void GenerateHalfedges(Span halfedges, ReadOnlySpan triangles, Allocator allocator)
{
- CheckAndThrowIfLengthNotEqual(halfedges, triangles);
+ ThrowCheckGenerateHalfedges(halfedges, triangles);
- for (int i = 0; i < halfedges.Length; i++)
- {
- halfedges[i] = -1;
- }
+ halfedges.Fill(-1);
using var tmp = new NativeHashMap(triangles.Length, allocator);
for (int he = 0; he < halfedges.Length; he++)
@@ -790,6 +787,56 @@ public static void GenerateHalfedges(Span halfedges, ReadOnlySpan tria
}
}
+ ///
+ /// Generates triangle using the provided .
+ /// Triangles that share a common edge are assigned the same color index.
+ /// The resulting contains values in the range [0, ).
+ /// Check the documentation for further details.
+ ///
+ /// A buffer that will be populated with triangle colors. Its length must be three times smaller than .
+ /// The halfedge data used for generating colors.
+ /// The total number of unique colors assigned.
+ /// The allocator to use for temporary data.
+ ///
+ public static void GenerateTriangleColors(Span colors, ReadOnlySpan halfedges, out int colorsCount, Allocator allocator)
+ {
+ ThrowCheckGenerateTriangleColors(colors, halfedges);
+
+ colorsCount = 0;
+ colors.Fill(-1);
+
+ using var heQueue = new NativeQueueList(allocator);
+ for (int t = 0; t < colors.Length; t++)
+ {
+ if (colors[t] == -1)
+ {
+ heQueue.Enqueue(3 * t + 0);
+ heQueue.Enqueue(3 * t + 1);
+ heQueue.Enqueue(3 * t + 2);
+ colors[t] = colorsCount;
+ BFS(colorsCount++, colors, heQueue, halfedges);
+ }
+ }
+
+ static void BFS(int color, Span colors, NativeQueueList heQueue, ReadOnlySpan halfedges)
+ {
+ while (heQueue.TryDequeue(out var he))
+ {
+ var ohe = halfedges[he];
+ var t = ohe / 3;
+ if (ohe == -1 || colors[t] != -1)
+ {
+ continue;
+ }
+
+ heQueue.Enqueue(3 * t + 0);
+ heQueue.Enqueue(3 * t + 1);
+ heQueue.Enqueue(3 * t + 2);
+ colors[t] = color;
+ }
+ }
+ }
+
///
/// Inserts a sub-mesh, defined by (, ), into the main mesh
/// represented by (, ).
@@ -837,7 +884,7 @@ public static unsafe void InsertSubMesh(NativeList positions, NativeList he % 3 == 2 ? he - 2 : he + 1;
[System.Diagnostics.Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- private static void CheckAndThrowIfLengthNotEqual(ReadOnlySpan halfedges, ReadOnlySpan triangles)
+ private static void ThrowCheckGenerateHalfedges(ReadOnlySpan halfedges, ReadOnlySpan triangles)
{
if (halfedges.Length != triangles.Length)
{
@@ -846,6 +893,17 @@ private static void CheckAndThrowIfLengthNotEqual(ReadOnlySpan halfedges, R
);
}
}
+
+ [System.Diagnostics.Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
+ private static void ThrowCheckGenerateTriangleColors(ReadOnlySpan colors, ReadOnlySpan halfedges)
+ {
+ if (3 * colors.Length != halfedges.Length)
+ {
+ throw new ArgumentException(
+ $"The provided colors[{colors.Length}] must be one-third of the length of halfedges [{halfedges.Length}]."
+ );
+ }
+ }
}
}
diff --git a/Tests/UtilitiesTests.cs b/Tests/UtilitiesTests.cs
index 8d00a6d..81b9508 100644
--- a/Tests/UtilitiesTests.cs
+++ b/Tests/UtilitiesTests.cs
@@ -47,10 +47,9 @@ public int[] GenerateHalfedgesTest(int[] triangles)
}
[Test]
- public void GenerateHalfedgesThrowIfDifferentLengthTest()
- {
- Assert.Throws(() => Utilities.GenerateHalfedges(new int[4], new int[7], Allocator.Persistent));
- }
+ public void GenerateHalfedgesThrowTest() => Assert.Throws(() =>
+ Utilities.GenerateHalfedges(halfedges: new int[4], triangles: new int[7], Allocator.Persistent)
+ );
private static readonly TestCaseData[] nextHalfedgeTestData =
{
@@ -116,5 +115,68 @@ public int[] InsertSubMeshTest((float2[] p, int[] t) mesh, (float2[] p, int[] t)
Assert.That(positions.AsArray(), Is.EqualTo(mesh.p.Concat(subMesh.p)));
return triangles.AsReadOnly().ToArray();
}
+
+ private static readonly TestCaseData[] generateTriangleColorsTestData =
+ {
+ new(new int[]{ }, 0)
+ {
+ ExpectedResult = new int[]{ },
+ TestName = "Test case 0 - 0 triangles 0 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ -1, -1, -1 }, 1)
+ {
+ ExpectedResult = new int[]{ 0 },
+ TestName = "Test case 1 - 1 triangle 1 color (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ -1, -1, -1, -1, -1, -1 }, 2)
+ {
+ ExpectedResult = new int[]{ 0, 1 },
+ TestName = "Test case 2a - 2 triangles 2 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ 3, -1, -1, 0, -1, -1 }, 1)
+ {
+ ExpectedResult = new int[]{ 0, 0 },
+ TestName = "Test case 2b - 2 triangles 1 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 3)
+ {
+ ExpectedResult = new int[]{ 0, 1, 2 },
+ TestName = "Test case 3a - 3 triangles 3 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ 3, -1, -1, 0, -1, -1, -1, -1, -1 }, 2)
+ {
+ ExpectedResult = new int[]{ 0, 0, 1 },
+ TestName = "Test case 3b - 3 triangles 2 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ 6, -1, -1, -1, -1, -1, 0, -1, -1 }, 2)
+ {
+ ExpectedResult = new int[]{ 0, 1, 0 },
+ TestName = "Test case 3c - 3 triangles 2 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ -1, -1, -1, 6, -1, -1, 3, -1, -1 }, 2)
+ {
+ ExpectedResult = new int[]{ 0, 1, 1 },
+ TestName = "Test case 3d - 3 triangles 2 colors (GenerateTriangleColorsTest)"
+ },
+ new(new int[]{ 3, -1, -1, 0, 6, -1, 4, -1, -1 }, 1)
+ {
+ ExpectedResult = new int[]{ 0, 0, 0 },
+ TestName = "Test case 3e - 3 triangles 1 color (GenerateTriangleColorsTest)"
+ },
+ };
+
+ [Test, TestCaseSource(nameof(generateTriangleColorsTestData))]
+ public int[] GenerateTriangleColorsTest(int[] halfedges, int expectedCount)
+ {
+ var colors = new int[halfedges.Length / 3];
+ Utilities.GenerateTriangleColors(colors, halfedges, out var count, Allocator.Persistent);
+ Assert.That(count, Is.EqualTo(expectedCount));
+ return colors;
+ }
+
+ [Test]
+ public void GenerateTriangleColorsThrowTest() => Assert.Throws(() =>
+ Utilities.GenerateTriangleColors(colors: new int[1], halfedges: new int[30], out _, Allocator.Persistent)
+ );
}
}