Esempio n. 1
0
        // Perform Voronoi based Smoothing. Does not add/remove points but merely relocates internal vertices so they are uniform distributed.
        internal static bool Condition(Allocator allocator, ref NativeArray <float2> pgPoints, int pgPointCount, NativeArray <int2> pgEdges, int pgEdgeCount, ref NativeArray <float2> vertices, ref int vertexCount, ref NativeArray <int> indices, ref int indexCount)
        {
            // Build Triangles and Edges.
            float maxArea = 0, cmxArea = 0, minArea = 0, cmnArea = 0, avgArea = 0, minEdge = 0, maxEdge = 0, avgEdge = 0;
            bool  polygonCentroid = true, validGraph = true;
            int   triangleCount = 0, delaEdgeCount = 0, affectingEdgeCount = 0;
            var   triangles    = new NativeArray <UTriangle>(indexCount, allocator); // Intentionally added more room than actual Triangles needed here.
            var   delaEdges    = new NativeArray <int4>(indexCount, allocator);
            var   voronoiEdges = new NativeArray <int4>(indexCount, allocator);
            var   connectedTri = new NativeArray <int4>(vertexCount, allocator);
            var   voronoiCheck = new NativeArray <int>(indexCount, allocator);
            var   affectsEdges = new NativeArray <int>(indexCount, allocator);
            var   triCentroids = new NativeArray <int>(vertexCount, allocator);

            ModuleHandle.BuildTrianglesAndEdges(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref delaEdges, ref delaEdgeCount, ref maxArea, ref avgArea, ref minArea);
            var refinedEdges = new NativeArray <int4>(delaEdgeCount, allocator);

            // Sort the Delaunay Edges.
            unsafe
            {
                ModuleHandle.InsertionSort <int4, DelaEdgeCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(delaEdges), 0, delaEdgeCount - 1,
                    new DelaEdgeCompare());
            }

            // TrimEdges. Update Triangle Info for Shared Edges and remove Duplicates.
            RefineEdges(ref refinedEdges, ref delaEdges, ref delaEdgeCount, ref voronoiEdges);

            // Now for each point, generate Voronoi diagram.
            for (int i = 0; i < vertexCount; ++i)
            {
                // Try moving this to Centroid of the Voronoi Polygon.
                GetAffectingEdges(i, delaEdges, delaEdgeCount, ref affectsEdges, ref voronoiCheck, ref affectingEdgeCount);
                var bounded = affectingEdgeCount != 0;

                // Check for Boundedness
                for (int j = 0; j < affectingEdgeCount; ++j)
                {
                    // Edge Index.
                    var ei = affectsEdges[j];
                    if (delaEdges[ei].z == -1 || delaEdges[ei].w == -1)
                    {
                        bounded = false;
                        break;
                    }
                }

                // If this is bounded point, relocate to Voronoi Diagram's Centroid
                if (bounded)
                {
                    polygonCentroid = ConnectTriangles(ref connectedTri, ref affectsEdges, ref voronoiCheck, voronoiEdges, affectingEdgeCount);
                    if (!polygonCentroid)
                    {
                        break;
                    }

                    float2 point = float2.zero;
                    float  area = 0, distance = 0;
                    for (int k = 0; k < affectingEdgeCount; ++k)
                    {
                        CentroidByPolygon(connectedTri[k], triangles, ref point, ref area, ref distance);
                    }
                    point      /= (3 * area);
                    pgPoints[i] = point;
                }
            }

            // Do Delaunay Again.
            int srcIndexCount = indexCount, srcVertexCount = vertexCount;

            indexCount = 0; vertexCount = 0; triangleCount = 0;
            if (polygonCentroid)
            {
                validGraph = Tessellator.Tessellate(allocator, pgPoints, pgPointCount, pgEdges, pgEdgeCount, ref vertices, ref vertexCount, ref indices, ref indexCount);
                if (validGraph)
                {
                    ModuleHandle.BuildTriangles(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref cmxArea, ref avgArea, ref cmnArea, ref maxEdge, ref avgEdge, ref minEdge);
                }
                // This Edge validation prevents artifacts by forcing a fallback. todo: Fix the actual bug in Outline generation.
                validGraph = validGraph && (cmxArea < maxArea * kMaxAreaTolerance) && (maxEdge < avgEdge * kMaxEdgeTolerance);
            }

            // Cleanup.
            triangles.Dispose();
            delaEdges.Dispose();
            refinedEdges.Dispose();
            voronoiCheck.Dispose();
            voronoiEdges.Dispose();
            affectsEdges.Dispose();
            triCentroids.Dispose();
            connectedTri.Dispose();
            return(validGraph && srcIndexCount == indexCount && srcVertexCount == vertexCount);
        }
Esempio n. 2
0
        internal static bool Condition(Allocator allocator, float factorArea, float targetArea, ref NativeArray <float2> pgPoints, ref int pgPointCount, ref NativeArray <int2> pgEdges, ref int pgEdgeCount, ref NativeArray <float2> vertices, ref int vertexCount, ref NativeArray <int> indices, ref int indexCount, ref float maxArea)
        {
            // Process Triangles.
            maxArea = 0.0f;
            var minArea    = 0.0f;
            var avgArea    = 0.0f;
            var refined    = false;
            var validGraph = true;

            // Temporary Stuffs.
            int triangleCount = 0, invalidTriangle = -1, inputPointCount = pgPointCount;
            var encroach  = new NativeArray <UEncroachingSegment>(ModuleHandle.kMaxEdgeCount, allocator);
            var triangles = new NativeArray <UTriangle>(ModuleHandle.kMaxTriangleCount, allocator);

            ModuleHandle.BuildTriangles(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref maxArea, ref avgArea, ref minArea);
            factorArea = factorArea != 0 ? math.clamp(factorArea, kMinAreaFactor, kMaxAreaFactor) : factorArea;
            var criArea = maxArea * factorArea;

            criArea = math.max(criArea, targetArea);

            // Refine
            while (!refined && validGraph)
            {
                // Check if any of the Triangle is Invalid or Segment is invalid. If yes, Refine.
                for (int i = 0; i < triangleCount; ++i)
                {
                    if (RequiresRefining(triangles[i], criArea))
                    {
                        invalidTriangle = i;
                        break;
                    }
                }

                // Find any Segment that can be Split based on the Input Length.
                // todo.

                if (invalidTriangle != -1)
                {
                    // Get all Segments that are encroached.
                    var t             = triangles[invalidTriangle];
                    var encroachCount = 0;
                    FetchEncroachedSegments(pgPoints, pgPointCount, pgEdges, pgEdgeCount, ref encroach, ref encroachCount, t.c);

                    // Split each Encroached Segments. If no segments are encroached. Split the Triangle.
                    if (encroachCount != 0)
                    {
                        for (int i = 0; i < encroachCount; ++i)
                        {
                            SplitSegments(ref pgPoints, ref pgPointCount, ref pgEdges, ref pgEdgeCount, encroach[i]);
                        }
                    }
                    else
                    {
                        // Update Triangulation.
                        var split = t.c.center;
                        pgPoints[pgPointCount++] = split;
                    }

                    // Tessellate again.
                    indexCount = 0; vertexCount = 0;
                    validGraph = Tessellator.Tessellate(allocator, pgPoints, pgPointCount, pgEdges, pgEdgeCount, ref vertices, ref vertexCount, ref indices, ref indexCount);

                    // Build Internal Triangles.
                    encroachCount = 0; triangleCount = 0; invalidTriangle = -1;
                    if (validGraph)
                    {
                        ModuleHandle.BuildTriangles(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref maxArea, ref avgArea, ref minArea);
                    }

                    // More than enough Steiner points inserted. This handles all sort of weird input sprites very well (even random point cloud).
                    if (pgPointCount - inputPointCount > kMaxSteinerCount)
                    {
                        break;
                    }
                }
                else
                {
                    refined = true;
                }
            }

            // Dispose off
            triangles.Dispose();
            encroach.Dispose();
            return(refined);
        }