// Trim Edges static void RefineEdges(ref NativeArray <int4> refinedEdges, ref NativeArray <int4> delaEdges, ref int delaEdgeCount, ref NativeArray <int4> voronoiEdges) { int origEdgeCount = delaEdgeCount; delaEdgeCount = 0; // Check Neighbour Triangles. for (int i = 0; i < origEdgeCount - 1; ++i) { var edge = delaEdges[i]; var neighbor = delaEdges[i + 1]; if (edge.x == neighbor.x && edge.y == neighbor.y) { // Found the Opposite Edge. i.e Nearby Triangle. edge.w = neighbor.z; ++i; } // Update new list. refinedEdges[delaEdgeCount++] = edge; } // Generate Voronoi Edges. for (int i = 0; i < delaEdgeCount; ++i) { var ti1 = refinedEdges[i].z; var ti2 = refinedEdges[i].w; // We only really care about Bounded Edges. This is simplification. Hoping this garbage works. if (ti1 != -1 && ti2 != -1) { // Get Triangles int4 e = new int4(ti2, ti1, i, 0); voronoiEdges[i] = e; } } ModuleHandle.Copy(refinedEdges, delaEdges, delaEdgeCount); }
public static float4 Tessellate(Allocator allocator, NativeArray <float2> points, NativeArray <int2> edges, ref NativeArray <float2> outVertices, ref int outVertexCount, ref NativeArray <int> outIndices, ref int outIndexCount, ref NativeArray <int2> outEdges, ref int outEdgeCount) { // Inputs are garbage, just early out. float4 ret = float4.zero; outEdgeCount = 0; outIndexCount = 0; outVertexCount = 0; if (points.Length < 3 || points.Length >= kMaxVertexCount) { return(ret); } // Ensure inputs form a proper PlanarGraph. bool validGraph = false, handleEdgeCase = false; int pgEdgeCount = 0, pgPointCount = 0; NativeArray <int2> pgEdges = new NativeArray <int2>(kMaxEdgeCount, allocator); NativeArray <float2> pgPoints = new NativeArray <float2>(kMaxVertexCount, allocator); // Valid Edges and Paths, correct the Planar Graph. If invalid create a simple convex hull rect. if (0 != edges.Length) { validGraph = PlanarGraph.Validate(allocator, points, points.Length, edges, edges.Length, ref pgPoints, ref pgPointCount, ref pgEdges, ref pgEdgeCount); } // Fallbacks are now handled by the Higher level packages. Enable if UTess needs to handle it. // #if UTESS_QUAD_FALLBACK // if (!validGraph) // { // pgPointCount = 0; // handleEdgeCase = true; // ModuleHandle.Copy(points, pgPoints, points.Length); // GraphConditioner(points, ref pgPoints, ref pgPointCount, ref pgEdges, ref pgEdgeCount, false); // } // #else // If its not a valid Graph simply return back input Data without triangulation instead of going through UTess (pointless wasted cpu cycles). if (!validGraph) { outEdgeCount = edges.Length; outVertexCount = points.Length; ModuleHandle.Copy(edges, outEdges, edges.Length); ModuleHandle.Copy(points, outVertices, points.Length); } // Do a proper Delaunay Triangulation if Inputs are valid. if (pgPointCount > 2 && pgEdgeCount > 2) { int tsIndexCount = 0, tsVertexCount = 0; NativeArray <int> tsIndices = new NativeArray <int>(kMaxIndexCount, allocator); NativeArray <float2> tsVertices = new NativeArray <float2>(kMaxVertexCount, allocator); validGraph = Tessellator.Tessellate(allocator, pgPoints, pgPointCount, pgEdges, pgEdgeCount, ref tsVertices, ref tsVertexCount, ref tsIndices, ref tsIndexCount); if (validGraph) { // Copy Out TransferOutput(pgEdges, pgEdgeCount, ref outEdges, ref outEdgeCount, tsIndices, tsIndexCount, ref outIndices, ref outIndexCount, tsVertices, tsVertexCount, ref outVertices, ref outVertexCount); if (handleEdgeCase == true) { outEdgeCount = 0; } } tsVertices.Dispose(); tsIndices.Dispose(); } // Dispose Temp Memory. pgPoints.Dispose(); pgEdges.Dispose(); return(ret); }
// Validate the Input Points ane Edges. internal static bool Validate(Allocator allocator, NativeArray <float2> inputPoints, int pointCount, NativeArray <int2> inputEdges, int edgeCount, ref NativeArray <float2> outputPoints, ref int outputPointCount, ref NativeArray <int2> outputEdges, ref int outputEdgeCount) { var protectLoop = edgeCount; var requiresFix = true; var validGraph = false; // Processing Arrays. NativeArray <int2> edges = new NativeArray <int2>(ModuleHandle.kMaxEdgeCount, allocator); NativeArray <double2> points = new NativeArray <double2>(ModuleHandle.kMaxVertexCount, allocator); NativeArray <int2> tJunctions = new NativeArray <int2>(ModuleHandle.kMaxEdgeCount, allocator); NativeArray <int2> edgeIntersections = new NativeArray <int2>(ModuleHandle.kMaxEdgeCount, allocator); NativeArray <int> duplicates = new NativeArray <int>(ModuleHandle.kMaxVertexCount, allocator); NativeArray <double2> intersects = new NativeArray <double2>(ModuleHandle.kMaxEdgeCount, allocator); // Initialize. for (int i = 0; i < pointCount; ++i) { points[i] = inputPoints[i]; } ModuleHandle.Copy(inputEdges, edges, edgeCount); // Pre-clear duplicates, otherwise the following will simply fail. RemoveDuplicateEdges(ref edges, ref edgeCount, duplicates, 0); // While PSG is clean. while (requiresFix && --protectLoop > 0) { // Edge Edge Intersection. int intersectionCount = 0; validGraph = CalculateEdgeIntersections(edges, edgeCount, points, pointCount, ref edgeIntersections, ref intersects, ref intersectionCount); if (!validGraph) { break; } // Edge Point Intersection. T-Junction. int tJunctionCount = 0; validGraph = CalculateTJunctions(edges, edgeCount, points, pointCount, tJunctions, ref tJunctionCount); if (!validGraph) { break; } // Cut Overlapping Edges. validGraph = CutEdges(ref points, ref pointCount, ref edges, ref edgeCount, ref tJunctions, ref tJunctionCount, edgeIntersections, intersects, intersectionCount); if (!validGraph) { break; } // Remove Duplicate Points. int duplicateCount = 0; RemoveDuplicatePoints(ref points, ref pointCount, ref duplicates, ref duplicateCount, allocator); RemoveDuplicateEdges(ref edges, ref edgeCount, duplicates, duplicateCount); requiresFix = intersectionCount != 0 || tJunctionCount != 0; } if (validGraph) { // Finalize Output. outputEdgeCount = edgeCount; outputPointCount = pointCount; ModuleHandle.Copy(edges, outputEdges, edgeCount); for (int i = 0; i < pointCount; ++i) { outputPoints[i] = new float2((float)points[i].x, (float)points[i].y); } } edges.Dispose(); points.Dispose(); intersects.Dispose(); duplicates.Dispose(); tJunctions.Dispose(); edgeIntersections.Dispose(); return(validGraph && protectLoop > 0); }