From 51778656285d64aaf24a826c8cdbf6bd0b26eefe Mon Sep 17 00:00:00 2001 From: andywiecko Date: Wed, 16 Oct 2024 09:05:40 +0200 Subject: [PATCH] refactor: refinement internal methods (4) This refactor is part of a series of changes preparing for the introduction of a dynamic point insertion utility. - Adds `UnsafeBowerWatson` internal helper struct used for point insertion. --- Runtime/Triangulator.cs | 487 ++++++++++++++++++++++------------------ 1 file changed, 268 insertions(+), 219 deletions(-) diff --git a/Runtime/Triangulator.cs b/Runtime/Triangulator.cs index ac1dc82..c05b871 100644 --- a/Runtime/Triangulator.cs +++ b/Runtime/Triangulator.cs @@ -2841,289 +2841,338 @@ private bool AngleIsTooSmall(int tId, T minimumAngle) return UnsafeTriangulator.AngleIsTooSmall(pA, pB, pC, minimumAngle); } - private int UnsafeInsertPointCommon(T2 p, int initTriangle) + private void UnsafeInsertPointBulk(T2 p, int initTriangle) => new UnsafeBowerWatson(this).UnsafeInsertPointBulk(p, initTriangle); + private void UnsafeInsertPointBoundary(T2 p, int initHe) => new UnsafeBowerWatson(this).UnsafeInsertPointBoundary(p, initHe); + + private struct UnsafeBowerWatson { - var pId = outputPositions.Length; - outputPositions.Add(p); + public OutputData Output; + public NativeList Circles; - badTriangles.Clear(); - trianglesQueue.Clear(); - pathPoints.Clear(); - pathHalfedges.Clear(); + public NativeList BadTriangles; + public NativeQueue TrianglesQueue; + public NativeList PathPoints; + public NativeList PathHalfedges; + public NativeList VisitedTriangles; - visitedTriangles.Clear(); - visitedTriangles.Length = triangles.Length / 3; + public UnsafeBowerWatson(RefineMeshStep @this) + { + Output = new() + { + Triangles = @this.triangles, + Halfedges = @this.halfedges, + Positions = @this.outputPositions, + ConstrainedHalfedges = @this.constrainedHalfedges, + }; + Circles = @this.circles; + BadTriangles = @this.badTriangles; + TrianglesQueue = @this.trianglesQueue; + PathPoints = @this.pathPoints; + PathHalfedges = @this.pathHalfedges; + VisitedTriangles = @this.visitedTriangles; + } - trianglesQueue.Enqueue(initTriangle); - badTriangles.Add(initTriangle); - visitedTriangles[initTriangle] = true; - RecalculateBadTriangles(p); + private int UnsafeInsertPointCommon(T2 p, int initTriangle) + { + var pId = Output.Positions.Length; + Output.Positions.Add(p); - return pId; - } + BadTriangles.Clear(); + TrianglesQueue.Clear(); + PathPoints.Clear(); + PathHalfedges.Clear(); - private void UnsafeInsertPointBulk(T2 p, int initTriangle) - { - var pId = UnsafeInsertPointCommon(p, initTriangle); - BuildStarPolygon(); - ProcessBadTriangles(); - BuildNewTrianglesForStar(pId); - } + VisitedTriangles.Clear(); + VisitedTriangles.Length = Output.Triangles.Length / 3; - private void UnsafeInsertPointBoundary(T2 p, int initHe) - { - var pId = UnsafeInsertPointCommon(p, initHe / 3); - BuildAmphitheaterPolygon(initHe); - ProcessBadTriangles(); - BuildNewTrianglesForAmphitheater(pId); - } + TrianglesQueue.Enqueue(initTriangle); + BadTriangles.Add(initTriangle); + VisitedTriangles[initTriangle] = true; + RecalculateBadTriangles(p); - private void RecalculateBadTriangles(T2 p) - { - while (trianglesQueue.TryDequeue(out var tId)) + return pId; + } + + public void UnsafeInsertPointBulk(T2 p, int initTriangle) { - for (int i = 0; i < 3; i++) + var pId = UnsafeInsertPointCommon(p, initTriangle); + BuildStarPolygon(); + ProcessBadTriangles(); + BuildNewTrianglesForStar(pId); + } + + public void UnsafeInsertPointBoundary(T2 p, int initHe) + { + var pId = UnsafeInsertPointCommon(p, initHe / 3); + BuildAmphitheaterPolygon(initHe); + ProcessBadTriangles(); + BuildNewTrianglesForAmphitheater(pId); + } + + private void RecalculateBadTriangles(T2 p) + { + while (TrianglesQueue.TryDequeue(out var tId)) { - var he = halfedges[3 * tId + i]; - var otherId = he / 3; - if (he == -1 || constrainedHalfedges[he] || visitedTriangles[otherId]) + for (int i = 0; i < 3; i++) { - continue; - } + var he = Output.Halfedges[3 * tId + i]; + var otherId = he / 3; + if (he == -1 || Output.ConstrainedHalfedges[he] || VisitedTriangles[otherId]) + { + continue; + } - var circle = circles[otherId]; - if (utils.le(utils.Cast(utils.distancesq(circle.Center, p)), circle.RadiusSq)) - { - badTriangles.Add(otherId); - trianglesQueue.Enqueue(otherId); - visitedTriangles[otherId] = true; + var circle = Circles[otherId]; + if (utils.le(utils.Cast(utils.distancesq(circle.Center, p)), circle.RadiusSq)) + { + BadTriangles.Add(otherId); + TrianglesQueue.Enqueue(otherId); + VisitedTriangles[otherId] = true; + } } } } - } - private void BuildAmphitheaterPolygon(int initHe) - { - var id = initHe; - var initPoint = triangles[id]; - while (true) + private void BuildAmphitheaterPolygon(int initHe) { - id = NextHalfedge(id); - if (triangles[id] == initPoint) - { - break; - } + var triangles = Output.Triangles; - var he = halfedges[id]; - if (he == -1 || !badTriangles.Contains(he / 3)) + var id = initHe; + var initPoint = triangles[id]; + while (true) { - pathPoints.Add(triangles[id]); - pathHalfedges.Add(he); - continue; + id = NextHalfedge(id); + if (triangles[id] == initPoint) + { + break; + } + + var he = Output.Halfedges[id]; + if (he == -1 || !BadTriangles.Contains(he / 3)) + { + PathPoints.Add(triangles[id]); + PathHalfedges.Add(he); + continue; + } + id = he; } - id = he; + PathPoints.Add(triangles[initHe]); + PathHalfedges.Add(-1); } - pathPoints.Add(triangles[initHe]); - pathHalfedges.Add(-1); - } - private void BuildStarPolygon() - { - // Find the "first" halfedge of the polygon. - var initHe = -1; - for (int i = 0; i < badTriangles.Length; i++) + private void BuildStarPolygon() { - var tId = badTriangles[i]; - for (int t = 0; t < 3; t++) + var triangles = Output.Triangles; + var halfedges = Output.Halfedges; + + // Find the "first" halfedge of the polygon. + var initHe = -1; + for (int i = 0; i < BadTriangles.Length; i++) { - var he = 3 * tId + t; - var ohe = halfedges[he]; - if (ohe == -1 || !badTriangles.Contains(ohe / 3)) + var tId = BadTriangles[i]; + for (int t = 0; t < 3; t++) + { + var he = 3 * tId + t; + var ohe = halfedges[he]; + if (ohe == -1 || !BadTriangles.Contains(ohe / 3)) + { + PathPoints.Add(triangles[he]); + PathHalfedges.Add(ohe); + initHe = he; + break; + } + } + if (initHe != -1) { - pathPoints.Add(triangles[he]); - pathHalfedges.Add(ohe); - initHe = he; break; } } - if (initHe != -1) + + // Build polygon path from halfedges and points. + var id = initHe; + var initPoint = PathPoints[0]; + while (true) { - break; + id = NextHalfedge(id); + if (triangles[id] == initPoint) + { + break; + } + + var he = halfedges[id]; + if (he == -1 || !BadTriangles.Contains(he / 3)) + { + PathPoints.Add(triangles[id]); + PathHalfedges.Add(he); + continue; + } + id = he; } } - // Build polygon path from halfedges and points. - var id = initHe; - var initPoint = pathPoints[0]; - while (true) + private void ProcessBadTriangles() { - id = NextHalfedge(id); - if (triangles[id] == initPoint) + var triangles = Output.Triangles; + var halfedges = Output.Halfedges; + var constrainedHalfedges = Output.ConstrainedHalfedges; + + void RemoveHalfedge(int he, int offset) { - break; + var ohe = halfedges[he]; + var o = ohe > he ? ohe - offset : ohe; + if (o > -1) + { + halfedges[o] = -1; + } + halfedges.RemoveAt(he); } - var he = halfedges[id]; - if (he == -1 || !badTriangles.Contains(he / 3)) + // Remove bad triangles and recalculate polygon path halfedges. + BadTriangles.Sort(); + for (int t = BadTriangles.Length - 1; t >= 0; t--) { - pathPoints.Add(triangles[id]); - pathHalfedges.Add(he); - continue; + var tId = BadTriangles[t]; + triangles.RemoveAt(3 * tId + 2); + triangles.RemoveAt(3 * tId + 1); + triangles.RemoveAt(3 * tId + 0); + Circles.RemoveAt(tId); + RemoveHalfedge(3 * tId + 2, 0); + RemoveHalfedge(3 * tId + 1, 1); + RemoveHalfedge(3 * tId + 0, 2); + constrainedHalfedges.RemoveAt(3 * tId + 2); + constrainedHalfedges.RemoveAt(3 * tId + 1); + constrainedHalfedges.RemoveAt(3 * tId + 0); + + for (int i = 3 * tId; i < halfedges.Length; i++) + { + var he = halfedges[i]; + if (he == -1) + { + continue; + } + halfedges[he < 3 * tId ? he : i] -= 3; + } + + for (int i = 0; i < PathHalfedges.Length; i++) + { + if (PathHalfedges[i] > 3 * tId + 2) + { + PathHalfedges[i] -= 3; + } + } } - id = he; } - } - private void ProcessBadTriangles() - { - static void RemoveHalfedge(NativeList halfedges, int he, int offset) + private void BuildNewTrianglesForStar(int pId) { - var ohe = halfedges[he]; - var o = ohe > he ? ohe - offset : ohe; - if (o > -1) + var triangles = Output.Triangles; + var halfedges = Output.Halfedges; + var constrainedHalfedges = Output.ConstrainedHalfedges; + + // Build triangles/circles for inserted point pId. + var initTriangles = triangles.Length; + triangles.Length += 3 * PathPoints.Length; + Circles.Length += PathPoints.Length; + for (int i = 0; i < PathPoints.Length - 1; i++) { - halfedges[o] = -1; + triangles[initTriangles + 3 * i + 0] = pId; + triangles[initTriangles + 3 * i + 1] = PathPoints[i]; + triangles[initTriangles + 3 * i + 2] = PathPoints[i + 1]; + Circles[initTriangles / 3 + i] = new(CalculateCircumCircle(pId, PathPoints[i], PathPoints[i + 1], Output.Positions.AsArray())); } - halfedges.RemoveAt(he); - } - - // Remove bad triangles and recalculate polygon path halfedges. - badTriangles.Sort(); - for (int t = badTriangles.Length - 1; t >= 0; t--) - { - var tId = badTriangles[t]; - triangles.RemoveAt(3 * tId + 2); - triangles.RemoveAt(3 * tId + 1); - triangles.RemoveAt(3 * tId + 0); - circles.RemoveAt(tId); - RemoveHalfedge(halfedges, 3 * tId + 2, 0); - RemoveHalfedge(halfedges, 3 * tId + 1, 1); - RemoveHalfedge(halfedges, 3 * tId + 0, 2); - constrainedHalfedges.RemoveAt(3 * tId + 2); - constrainedHalfedges.RemoveAt(3 * tId + 1); - constrainedHalfedges.RemoveAt(3 * tId + 0); - - for (int i = 3 * tId; i < halfedges.Length; i++) + triangles[^3] = pId; + triangles[^2] = PathPoints[^1]; + triangles[^1] = PathPoints[0]; + Circles[^1] = new(CalculateCircumCircle(pId, PathPoints[^1], PathPoints[0], Output.Positions.AsArray())); + + // Build half-edges for inserted point pId. + var heOffset = halfedges.Length; + halfedges.Length += 3 * PathPoints.Length; + constrainedHalfedges.Length += 3 * PathPoints.Length; + for (int i = 0; i < PathPoints.Length - 1; i++) { - var he = halfedges[i]; - if (he == -1) + var he = PathHalfedges[i]; + halfedges[3 * i + 1 + heOffset] = he; + if (he != -1) { - continue; + halfedges[he] = 3 * i + 1 + heOffset; + constrainedHalfedges[3 * i + 1 + heOffset] = constrainedHalfedges[he]; } - halfedges[he < 3 * tId ? he : i] -= 3; - } - - for (int i = 0; i < pathHalfedges.Length; i++) - { - if (pathHalfedges[i] > 3 * tId + 2) + else { - pathHalfedges[i] -= 3; + constrainedHalfedges[3 * i + 1 + heOffset] = true; } + halfedges[3 * i + 2 + heOffset] = 3 * i + 3 + heOffset; + halfedges[3 * i + 3 + heOffset] = 3 * i + 2 + heOffset; } - } - } - - private void BuildNewTrianglesForStar(int pId) - { - // Build triangles/circles for inserted point pId. - var initTriangles = triangles.Length; - triangles.Length += 3 * pathPoints.Length; - circles.Length += pathPoints.Length; - for (int i = 0; i < pathPoints.Length - 1; i++) - { - triangles[initTriangles + 3 * i + 0] = pId; - triangles[initTriangles + 3 * i + 1] = pathPoints[i]; - triangles[initTriangles + 3 * i + 2] = pathPoints[i + 1]; - circles[initTriangles / 3 + i] = new(CalculateCircumCircle(pId, pathPoints[i], pathPoints[i + 1], outputPositions.AsArray())); - } - triangles[^3] = pId; - triangles[^2] = pathPoints[^1]; - triangles[^1] = pathPoints[0]; - circles[^1] = new(CalculateCircumCircle(pId, pathPoints[^1], pathPoints[0], outputPositions.AsArray())); - - // Build half-edges for inserted point pId. - var heOffset = halfedges.Length; - halfedges.Length += 3 * pathPoints.Length; - constrainedHalfedges.Length += 3 * pathPoints.Length; - for (int i = 0; i < pathPoints.Length - 1; i++) - { - var he = pathHalfedges[i]; - halfedges[3 * i + 1 + heOffset] = he; - if (he != -1) + var phe = PathHalfedges[^1]; + halfedges[heOffset + 3 * (PathPoints.Length - 1) + 1] = phe; + if (phe != -1) { - halfedges[he] = 3 * i + 1 + heOffset; - constrainedHalfedges[3 * i + 1 + heOffset] = constrainedHalfedges[he]; + halfedges[phe] = heOffset + 3 * (PathPoints.Length - 1) + 1; + constrainedHalfedges[heOffset + 3 * (PathPoints.Length - 1) + 1] = constrainedHalfedges[phe]; } else { - constrainedHalfedges[3 * i + 1 + heOffset] = true; + constrainedHalfedges[heOffset + 3 * (PathPoints.Length - 1) + 1] = true; } - halfedges[3 * i + 2 + heOffset] = 3 * i + 3 + heOffset; - halfedges[3 * i + 3 + heOffset] = 3 * i + 2 + heOffset; - } - var phe = pathHalfedges[^1]; - halfedges[heOffset + 3 * (pathPoints.Length - 1) + 1] = phe; - if (phe != -1) - { - halfedges[phe] = heOffset + 3 * (pathPoints.Length - 1) + 1; - constrainedHalfedges[heOffset + 3 * (pathPoints.Length - 1) + 1] = constrainedHalfedges[phe]; + halfedges[heOffset] = heOffset + 3 * (PathPoints.Length - 1) + 2; + halfedges[heOffset + 3 * (PathPoints.Length - 1) + 2] = heOffset; } - else - { - constrainedHalfedges[heOffset + 3 * (pathPoints.Length - 1) + 1] = true; - } - halfedges[heOffset] = heOffset + 3 * (pathPoints.Length - 1) + 2; - halfedges[heOffset + 3 * (pathPoints.Length - 1) + 2] = heOffset; - } - private void BuildNewTrianglesForAmphitheater(int pId) - { - // Build triangles/circles for inserted point pId. - var initTriangles = triangles.Length; - triangles.Length += 3 * (pathPoints.Length - 1); - circles.Length += pathPoints.Length - 1; - for (int i = 0; i < pathPoints.Length - 1; i++) + private void BuildNewTrianglesForAmphitheater(int pId) { - triangles[initTriangles + 3 * i + 0] = pId; - triangles[initTriangles + 3 * i + 1] = pathPoints[i]; - triangles[initTriangles + 3 * i + 2] = pathPoints[i + 1]; - circles[initTriangles / 3 + i] = new(CalculateCircumCircle(pId, pathPoints[i], pathPoints[i + 1], outputPositions.AsArray())); - } + var triangles = Output.Triangles; + var halfedges = Output.Halfedges; + var constrainedHalfedges = Output.ConstrainedHalfedges; + + // Build triangles/circles for inserted point pId. + var initTriangles = triangles.Length; + triangles.Length += 3 * (PathPoints.Length - 1); + Circles.Length += PathPoints.Length - 1; + for (int i = 0; i < PathPoints.Length - 1; i++) + { + triangles[initTriangles + 3 * i + 0] = pId; + triangles[initTriangles + 3 * i + 1] = PathPoints[i]; + triangles[initTriangles + 3 * i + 2] = PathPoints[i + 1]; + Circles[initTriangles / 3 + i] = new(CalculateCircumCircle(pId, PathPoints[i], PathPoints[i + 1], Output.Positions.AsArray())); + } - // Build half-edges for inserted point pId. - var heOffset = halfedges.Length; - halfedges.Length += 3 * (pathPoints.Length - 1); - constrainedHalfedges.Length += 3 * (pathPoints.Length - 1); - for (int i = 0; i < pathPoints.Length - 2; i++) - { - var he = pathHalfedges[i]; - halfedges[3 * i + 1 + heOffset] = he; - if (he != -1) + // Build half-edges for inserted point pId. + var heOffset = halfedges.Length; + halfedges.Length += 3 * (PathPoints.Length - 1); + constrainedHalfedges.Length += 3 * (PathPoints.Length - 1); + for (int i = 0; i < PathPoints.Length - 2; i++) { - halfedges[he] = 3 * i + 1 + heOffset; - constrainedHalfedges[3 * i + 1 + heOffset] = constrainedHalfedges[he]; + var he = PathHalfedges[i]; + halfedges[3 * i + 1 + heOffset] = he; + if (he != -1) + { + halfedges[he] = 3 * i + 1 + heOffset; + constrainedHalfedges[3 * i + 1 + heOffset] = constrainedHalfedges[he]; + } + else + { + constrainedHalfedges[3 * i + 1 + heOffset] = true; + } + halfedges[3 * i + 2 + heOffset] = 3 * i + 3 + heOffset; + halfedges[3 * i + 3 + heOffset] = 3 * i + 2 + heOffset; + } + + var phe = PathHalfedges[^2]; + halfedges[heOffset + 3 * (PathPoints.Length - 2) + 1] = phe; + if (phe != -1) + { + halfedges[phe] = heOffset + 3 * (PathPoints.Length - 2) + 1; + constrainedHalfedges[heOffset + 3 * (PathPoints.Length - 2) + 1] = constrainedHalfedges[phe]; } else { - constrainedHalfedges[3 * i + 1 + heOffset] = true; + constrainedHalfedges[heOffset + 3 * (PathPoints.Length - 2) + 1] = true; } - halfedges[3 * i + 2 + heOffset] = 3 * i + 3 + heOffset; - halfedges[3 * i + 3 + heOffset] = 3 * i + 2 + heOffset; - } - - var phe = pathHalfedges[^2]; - halfedges[heOffset + 3 * (pathPoints.Length - 2) + 1] = phe; - if (phe != -1) - { - halfedges[phe] = heOffset + 3 * (pathPoints.Length - 2) + 1; - constrainedHalfedges[heOffset + 3 * (pathPoints.Length - 2) + 1] = constrainedHalfedges[phe]; - } - else - { - constrainedHalfedges[heOffset + 3 * (pathPoints.Length - 2) + 1] = true; + halfedges[heOffset] = -1; + halfedges[heOffset + 3 * (PathPoints.Length - 2) + 2] = -1; } - halfedges[heOffset] = -1; - halfedges[heOffset + 3 * (pathPoints.Length - 2) + 2] = -1; } private void AdaptQueues(NativeList heQueue, NativeList tQueue)