diff --git a/Runtime/Triangulator.cs b/Runtime/Triangulator.cs index f06d74e..9b35cf5 100644 --- a/Runtime/Triangulator.cs +++ b/Runtime/Triangulator.cs @@ -307,7 +307,7 @@ public JobHandle Schedule(JobHandle dependencies = default) dependencies = new DelaunayTriangulationJob(this).Schedule(dependencies); dependencies = Settings.RefineMesh || Settings.ConstrainEdges ? new RecalculateTriangleMappingsJob(this).Schedule(dependencies) : dependencies; - dependencies = Settings.ConstrainEdges ? ScheduleConstrainEdges(dependencies) : dependencies; + dependencies = Settings.ConstrainEdges ? new ConstrainEdgesJob(this).Schedule(dependencies) : dependencies; dependencies = (Settings.RefineMesh, Settings.ConstrainEdges) switch { @@ -414,22 +414,6 @@ private JobHandle ScheduleLocalToWorldTransformation(JobHandle dependencies) return dependencies; } - private JobHandle ScheduleConstrainEdges(JobHandle dependencies) - { - var edges = new NativeList(Allocator.TempJob); - var constraints = new NativeList(Allocator.TempJob); - dependencies = new CopyEdgesJob(this, edges).Schedule(dependencies); - dependencies = new ResizeEdgeConstraintsJob(this).Schedule(dependencies); - dependencies = new ConstructConstraintEdgesJob(this).Schedule(this, dependencies); - dependencies = new CopyConstraintsJob(this, constraints).Schedule(dependencies); - dependencies = new FilterAlreadyConstraintEdges(edges, constraints).Schedule(dependencies); - dependencies = new ConstrainEdgesJob(this, edges, constraints).Schedule(dependencies); - dependencies = constraints.Dispose(dependencies); - dependencies = edges.Dispose(dependencies); - - return dependencies; - } - #region Jobs [BurstCompile] private struct ValidateInputPositionsJob : IJob @@ -1380,61 +1364,42 @@ private bool ValidatePair(int i, int j) } [BurstCompile] - private struct CopyEdgesJob : IJob + private struct ConstrainEdgesJob : IJob { + private NativeReference status; [ReadOnly] + private NativeArray outputPositions; + private NativeList triangles; private NativeHashMap> edgesToTriangles; - private NativeList edges; - private NativeReference.ReadOnly status; - - public CopyEdgesJob(Triangulator triangulator, NativeList edges) - { - edgesToTriangles = triangulator.edgesToTriangles; - this.edges = edges; - status = triangulator.status.AsReadOnly(); - } - - public void Execute() - { - if (status.Value != Status.OK) - { - return; - } - - using var tmp = edgesToTriangles.GetKeyArray(Allocator.Temp); - edges.CopyFrom(tmp); - } - } - - [BurstCompile] - private struct CopyConstraintsJob : IJob - { + private NativeList trianglesToEdges; + private NativeList circles; [ReadOnly] - private NativeArray internalConstraints; + private NativeArray inputConstraintEdges; + private NativeList internalConstraints; + private readonly int maxIters; + + [NativeDisableContainerSafetyRestriction] + private NativeQueue intersections; + [NativeDisableContainerSafetyRestriction] private NativeList constraints; + [NativeDisableContainerSafetyRestriction] + private NativeArray edges; - public CopyConstraintsJob(Triangulator triangulator, NativeList constraints) + public ConstrainEdgesJob(Triangulator triangluator) { - internalConstraints = triangulator.constraintEdges.AsDeferredJobArray(); - this.constraints = constraints; - } - - public void Execute() => constraints.CopyFrom(internalConstraints); - } - - [BurstCompile] - private struct ResizeEdgeConstraintsJob : IJob - { - [ReadOnly] - private NativeArray inputConstraintEdges; - private NativeList constraintEdges; - private NativeReference.ReadOnly status; + status = triangluator.status; + outputPositions = triangluator.outputPositions.AsDeferredJobArray(); + triangles = triangluator.triangles; + edgesToTriangles = triangluator.edgesToTriangles; + trianglesToEdges = triangluator.trianglesToEdges; + circles = triangluator.circles; + maxIters = triangluator.Settings.SloanMaxIters; + inputConstraintEdges = triangluator.Input.ConstraintEdges; + internalConstraints = triangluator.constraintEdges; - public ResizeEdgeConstraintsJob(Triangulator triangulator) - { - inputConstraintEdges = triangulator.Input.ConstraintEdges; - constraintEdges = triangulator.constraintEdges; - status = triangulator.status.AsReadOnly(); + intersections = default; + constraints = default; + edges = default; } public void Execute() @@ -1444,44 +1409,36 @@ public void Execute() return; } - constraintEdges.Length = inputConstraintEdges.Length / 2; - } - } + BuildInternalConstraints(); - [BurstCompile] - private struct ConstructConstraintEdgesJob : IJobParallelForDefer - { - [ReadOnly] - private NativeArray inputConstraintEdges; - private NativeArray constraintEdges; + using var _edges = edges = edgesToTriangles.GetKeyArray(Allocator.Temp); + using var _constraints = constraints = new NativeList(internalConstraints.Length, Allocator.Temp); + using var _intersections = intersections = new NativeQueue(Allocator.Temp); - public ConstructConstraintEdgesJob(Triangulator triangulator) - { - inputConstraintEdges = triangulator.Input.ConstraintEdges; - constraintEdges = triangulator.constraintEdges.AsDeferredJobArray(); - } + constraints.CopyFrom(internalConstraints); + FilterAlreadyConstraintEdges(); - public JobHandle Schedule(Triangulator triangulator, JobHandle dependencies) => - this.Schedule(triangulator.constraintEdges, triangulator.Settings.BatchCount, dependencies); + edges.Sort(); + constraints.Sort(); + for (int i = constraints.Length - 1; i >= 0; i--) + { + TryApplyConstraint(i); + } + } - public void Execute(int index) + private void BuildInternalConstraints() { - var i = inputConstraintEdges[2 * index]; - var j = inputConstraintEdges[2 * index + 1]; - // Note: +3 due to supertriangle points - constraintEdges[index] = new Edge(i + 3, j + 3); + internalConstraints.Length = inputConstraintEdges.Length / 2; + for (int index = 0; index < internalConstraints.Length; index++) + { + var i = inputConstraintEdges[2 * index + 0]; + var j = inputConstraintEdges[2 * index + 1]; + // Note: +3 due to supertriangle points + internalConstraints[index] = new Edge(i + 3, j + 3); + } } - } - [BurstCompile] - private struct FilterAlreadyConstraintEdges : IJob - { - private NativeList edges, constraints; - - public FilterAlreadyConstraintEdges(NativeList edges, NativeList constraints) => - (this.edges, this.constraints) = (edges, constraints); - - public void Execute() + private void FilterAlreadyConstraintEdges() { edges.Sort(); for (int i = constraints.Length - 1; i >= 0; i--) @@ -1493,33 +1450,64 @@ public void Execute() } } } - } - - [BurstCompile] - private struct ConstrainEdgesJob : IJob - { - private NativeReference status; - [ReadOnly] - private NativeArray outputPositions; - private NativeList triangles; - private NativeHashMap> edgesToTriangles; - private NativeList trianglesToEdges; - private NativeList circles; - private NativeList edges; - private NativeList constraints; - private readonly int maxIters; - public ConstrainEdgesJob(Triangulator triangluator, NativeList edges, NativeList constraints) + private void TryApplyConstraint(int i) { - status = triangluator.status; - outputPositions = triangluator.outputPositions.AsDeferredJobArray(); - triangles = triangluator.triangles; - edgesToTriangles = triangluator.edgesToTriangles; - trianglesToEdges = triangluator.trianglesToEdges; - circles = triangluator.circles; - this.edges = edges; - this.constraints = constraints; - maxIters = triangluator.Settings.SloanMaxIters; + intersections.Clear(); + + var c = constraints[i]; + CollectIntersections(c, intersections); + + var iter = 0; + while (intersections.TryDequeue(out var e)) + { + if (IsMaxItersExceeded(iter++, maxIters)) + { + return; + } + + var tris = edgesToTriangles[e]; + var t0 = tris[0]; + var t1 = tris[1]; + + var q0 = triangles[t0].UnsafeOtherPoint(e); + var q1 = triangles[t1].UnsafeOtherPoint(e); + var swapped = new Edge(q0, q1); + + if (!intersections.IsEmpty()) + { + if (!c.ContainsCommonPointWith(swapped)) + { + if (EdgeEdgeIntersection(c, swapped)) + { + intersections.Enqueue(e); + continue; + } + } + + var (e0, e1) = e; + var (p0, p1, p2, p3) = (outputPositions[e0], outputPositions[q0], outputPositions[e1], outputPositions[q1]); + if (!IsConvexQuadrilateral(p0, p1, p2, p3)) + { + intersections.Enqueue(e); + continue; + } + + var id = constraints.BinarySearch(swapped); + if (id >= 0) + { + constraints.RemoveAt(id); + i--; + } + } + + UnsafeSwapEdge(e); + var eId = edges.BinarySearch(e); + edges[eId] = swapped; + edges.Sort(); + } + + constraints.RemoveAtSwapBack(i); } private bool EdgeEdgeIntersection(Edge e1, Edge e2) @@ -1592,76 +1580,6 @@ private void UnsafeSwapEdge(Edge edge) circles[t0] = CalculateCircumCircle(triangles[t0], outputPositions); circles[t1] = CalculateCircumCircle(triangles[t1], outputPositions); } - - public void Execute() - { - if (status.Value != Status.OK) - { - return; - } - - edges.Sort(); - constraints.Sort(); - using var intersections = new NativeQueue(Allocator.Temp); - for (int i = constraints.Length - 1; i >= 0; i--) - { - intersections.Clear(); - - var c = constraints[i]; - CollectIntersections(c, intersections); - - var iter = 0; - while (intersections.TryDequeue(out var e)) - { - if (IsMaxItersExceeded(iter++, maxIters)) - { - return; - } - - var tris = edgesToTriangles[e]; - var t0 = tris[0]; - var t1 = tris[1]; - - var q0 = triangles[t0].UnsafeOtherPoint(e); - var q1 = triangles[t1].UnsafeOtherPoint(e); - var swapped = new Edge(q0, q1); - - if (!intersections.IsEmpty()) - { - if (!c.ContainsCommonPointWith(swapped)) - { - if (EdgeEdgeIntersection(c, swapped)) - { - intersections.Enqueue(e); - continue; - } - } - - var (e0, e1) = e; - var (p0, p1, p2, p3) = (outputPositions[e0], outputPositions[q0], outputPositions[e1], outputPositions[q1]); - if (!IsConvexQuadrilateral(p0, p1, p2, p3)) - { - intersections.Enqueue(e); - continue; - } - - var id = constraints.BinarySearch(swapped); - if (id >= 0) - { - constraints.RemoveAt(id); - i--; - } - } - - UnsafeSwapEdge(e); - var eId = edges.BinarySearch(e); - edges[eId] = swapped; - edges.Sort(); - } - - constraints.RemoveAtSwapBack(i); - } - } } private interface IRefineMeshJobMode