internal static bool LineLineIntersection(double2 a0, double2 a1, double2 b0, double2 b1)
        {
            var x0 = UTess.OrientFastDouble(a0, b0, b1);
            var y0 = UTess.OrientFastDouble(a1, b0, b1);

            if ((x0 > kEpsilon && y0 > kEpsilon) || (x0 < -kEpsilon && y0 < -kEpsilon))
            {
                return(false);
            }

            var x1 = UTess.OrientFastDouble(b0, a0, a1);
            var y1 = UTess.OrientFastDouble(b1, a0, a1);

            if ((x1 > kEpsilon && y1 > kEpsilon) || (x1 < -kEpsilon && y1 < -kEpsilon))
            {
                return(false);
            }

            // Check for degenerate collinear case
            if (math.abs(x0) < kEpsilon && math.abs(y0) < kEpsilon && math.abs(x1) < kEpsilon && math.abs(y1) < kEpsilon)
            {
                return(CheckCollinear(a0, a1, b0, b1));
            }

            return(true);
        }
        public int Compare(UEvent a, UEvent b)
        {
            float f = (a.a.x - b.a.x);

            if (0 != f)
            {
                return((f > 0) ? 1 : -1);
            }

            f = (a.a.y - b.a.y);
            if (0 != f)
            {
                return((f > 0) ? 1 : -1);
            }

            int i = a.type - b.type;

            if (0 != i)
            {
                return(i);
            }

            if (a.type != (int)UEventType.EVENT_POINT)
            {
                float o = UTess.OrientFast(a.a, a.b, b.b);
                if (0 != o)
                {
                    return((o > 0) ? 1 : -1);
                }
            }

            return(a.idx - b.idx);
        }
Exemple #3
0
        bool MergeHulls(NativeArray <UHull> hulls, ref int hullCount, NativeArray <float2> points, UEvent evt)
        {
            float2 temp = evt.a;

            evt.a = evt.b;
            evt.b = temp;
            int index = UTess.GetEqual(hulls, hullCount, evt, new TestHullEventE());

            if (index < 0)
            {
                return(false);
            }

            UHull upper = hulls[index];
            UHull lower = hulls[index - 1];

            lower.iucount = upper.iucount;
            for (int i = 0; i < lower.iucount; ++i)
            {
                lower.iuarray[i] = upper.iuarray[i];
            }

            hulls[index - 1] = lower;
            EraseHull(hulls, index, ref hullCount);
            return(true);
        }
 static void CopyGeometry(NativeArray <int> srcIndices, int srcIndexCount, ref NativeArray <int> dstIndices, ref int dstIndexCount, NativeArray <float2> srcVertices, int srcVertexCount, ref NativeArray <float2> dstVertices, ref int dstVertexCount)
 {
     dstIndexCount  = srcIndexCount;
     dstVertexCount = srcVertexCount;
     UTess.Copy(srcIndices, dstIndices, srcIndexCount);
     UTess.Copy(srcVertices, dstVertices, srcVertexCount);
 }
Exemple #5
0
        static float FindSplit(UHull hull, UEvent edge)
        {
            float d = 0;

            if (hull.a.x < edge.a.x)
            {
                d = UTess.OrientFast(hull.a, hull.b, edge.a);
            }
            else
            {
                d = UTess.OrientFast(edge.b, edge.a, hull.a);
            }

            if (0 != d)
            {
                return(d);
            }

            if (edge.b.x < hull.b.x)
            {
                d = UTess.OrientFast(hull.a, hull.b, edge.b);
            }
            else
            {
                d = UTess.OrientFast(edge.b, edge.a, hull.b);
            }

            if (0 != d)
            {
                return(d);
            }
            return(hull.idx - edge.idx);
        }
Exemple #6
0
        int FindNeighbor(NativeArray <int3> cells, int count, int a, int b, int c)
        {
            int x = a, y = b, z = c;

            if (b < c)
            {
                if (b < a)
                {
                    x = b;
                    y = c;
                    z = a;
                }
            }
            else if (c < a)
            {
                x = c;
                y = a;
                z = b;
            }

            if (x < 0)
            {
                return(-1);
            }

            int3 key;

            key.x = x;
            key.y = y;
            key.z = z;
            return(UTess.GetEqual(cells, count, key, new TestCellE()));
        }
 static void CopyGraph(NativeArray <float2> srcPoints, int srcPointCount, ref NativeArray <float2> dstPoints, ref int dstPointCount, NativeArray <int2> srcEdges, int srcEdgeCount, ref NativeArray <int2> dstEdges, ref int dstEdgeCount)
 {
     dstEdgeCount  = srcEdgeCount;
     dstPointCount = srcPointCount;
     UTess.Copy(srcEdges, dstEdges, srcEdgeCount);
     UTess.Copy(srcPoints, dstPoints, srcPointCount);
 }
Exemple #8
0
        int FindConstraint(int a, int b)
        {
            int2 e;

            e.x = a < b ? a : b;
            e.y = a > b ? a : b;
            return(UTess.GetEqual(m_Edges, m_Edges.Length, e, new TestEdgePointE()));
        }
 static void TransferOutput(NativeArray <int2> srcEdges, int srcEdgeCount, ref NativeArray <int2> dstEdges, ref int dstEdgeCount, NativeArray <int> srcIndices, int srcIndexCount, ref NativeArray <int> dstIndices, ref int dstIndexCount, NativeArray <float2> srcVertices, int srcVertexCount, ref NativeArray <float2> dstVertices, ref int dstVertexCount)
 {
     dstEdgeCount   = srcEdgeCount;
     dstIndexCount  = srcIndexCount;
     dstVertexCount = srcVertexCount;
     UTess.Copy(srcEdges, dstEdges, srcEdgeCount);
     UTess.Copy(srcIndices, dstIndices, srcIndexCount);
     UTess.Copy(srcVertices, dstVertices, srcVertexCount);
 }
        internal static bool CalculateEdgeIntersections(NativeArray <int2> edges, int edgeCount, NativeArray <double2> points, int pointCount, ref NativeArray <int2> results, ref NativeArray <double2> intersects, ref int resultCount)
        {
            resultCount = 0;

            for (int i = 0; i < edgeCount; ++i)
            {
                for (int j = i + 1; j < edgeCount; ++j)
                {
                    var e = edges[i];
                    var f = edges[j];
                    if (e.x == f.x || e.x == f.y || e.y == f.x || e.y == f.y)
                    {
                        continue;
                    }

                    var a = points[e.x];
                    var b = points[e.y];
                    var c = points[f.x];
                    var d = points[f.y];
                    var g = double2.zero;
                    if (LineLineIntersection(a, b, c, d))
                    {
                        if (LineLineIntersection(a, b, c, d, ref g))
                        {
                            // Until we ensure Outline is generated properly, we need this useless Check every correction.
                            if (resultCount >= intersects.Length)
                            {
                                return(false);
                            }

                            intersects[resultCount] = g;
                            results[resultCount++]  = new int2(i, j);
                        }
                    }
                }
            }

            // Basically we have self intersections all over (eg. gobo_tree_04). Better don't generate any Mesh as even though this will eventually succeed, error correction will take long time.
            if (resultCount > (edgeCount * kMaxIntersectionTolerance))
            {
                return(false);
            }

            unsafe
            {
                var tjc = new IntersectionCompare();
                tjc.edges  = edges;
                tjc.points = points;
                UTess.InsertionSort <int2, IntersectionCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(results), 0, resultCount - 1, tjc);
            }

            return(true);
        }
Exemple #11
0
        bool AddPoint(NativeArray <UHull> hulls, int hullCount, NativeArray <float2> points, float2 p, int idx)
        {
            int l = UTess.GetLower(hulls, hullCount, p, new TestHullPointL());
            int u = UTess.GetUpper(hulls, hullCount, p, new TestHullPointU());

            if (l < 0 || u < 0)
            {
                return(false);
            }
            for (int i = l; i < u; ++i)
            {
                UHull hull = hulls[i];

                int m = hull.ilcount;
                while (m > 1 && UTess.OrientFast(points[hull.ilarray[m - 2]], points[hull.ilarray[m - 1]], p) > 0)
                {
                    int3 c = new int3();
                    c.x = hull.ilarray[m - 1];
                    c.y = hull.ilarray[m - 2];
                    c.z = idx;
                    m_Cells[m_CellCount++] = c;
                    m -= 1;
                }

                hull.ilcount = m + 1;
                if (hull.ilcount > hull.ilarray.Length)
                {
                    return(false);
                }
                hull.ilarray[m] = idx;

                m = hull.iucount;
                while (m > 1 && UTess.OrientFast(points[hull.iuarray[m - 2]], points[hull.iuarray[m - 1]], p) < 0)
                {
                    int3 c = new int3();
                    c.x = hull.iuarray[m - 2];
                    c.y = hull.iuarray[m - 1];
                    c.z = idx;
                    m_Cells[m_CellCount++] = c;
                    m -= 1;
                }

                hull.iucount = m + 1;
                if (hull.iucount > hull.iuarray.Length)
                {
                    return(false);
                }
                hull.iuarray[m] = idx;

                hulls[i] = hull;
            }
            return(true);
        }
        private static readonly int    kMaxIntersectionTolerance = 4; // Maximum Intersection Tolerance per Intersection Loop Check.

        internal static void RemoveDuplicateEdges(ref NativeArray <int2> edges, ref int edgeCount, NativeArray <int> duplicates, int duplicateCount)
        {
            if (duplicateCount == 0)
            {
                for (var i = 0; i < edgeCount; ++i)
                {
                    var e = edges[i];
                    e.x      = math.min(edges[i].x, edges[i].y);
                    e.y      = math.max(edges[i].x, edges[i].y);
                    edges[i] = e;
                }
            }
            else
            {
                for (var i = 0; i < edgeCount; ++i)
                {
                    var e = edges[i];
                    var a = duplicates[e.x];
                    var b = duplicates[e.y];
                    e.x      = math.min(a, b);
                    e.y      = math.max(a, b);
                    edges[i] = e;
                }
            }

            unsafe
            {
                UTess.InsertionSort <int2, TessEdgeCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(edges), 0, edgeCount - 1,
                    new TessEdgeCompare());
            }

            var n = 1;

            for (var i = 1; i < edgeCount; ++i)
            {
                var prev = edges[i - 1];
                var next = edges[i];
                if (next.x == prev.x && next.y == prev.y)
                {
                    continue;
                }
                if (next.x == next.y)
                {
                    continue;
                }
                edges[n++] = next;
            }
            edgeCount = n;
        }
 internal static void BuildTriangles(NativeArray <float2> vertices, int vertexCount, NativeArray <int> indices, int indexCount, ref NativeArray <UTriangle> triangles, ref int triangleCount, ref float maxArea)
 {
     // Check if there are invalid triangles or segments.
     for (int i = 0; i < indexCount; i += 3)
     {
         UTriangle tri = new UTriangle();
         var       i0  = indices[i + 0];
         var       i1  = indices[i + 1];
         var       i2  = indices[i + 2];
         tri.va   = vertices[i0];
         tri.vb   = vertices[i1];
         tri.vc   = vertices[i2];
         tri.c    = UTess.CircumCircle(tri);
         tri.area = UTess.TriangleArea(tri.va, tri.vb, tri.vc);
         maxArea  = math.max(tri.area, maxArea);
         triangles[triangleCount++] = tri;
     }
 }
Exemple #14
0
        // 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;
                }
            }

            UTess.Copy(refinedEdges, delaEdges, delaEdgeCount);
        }
Exemple #15
0
        bool Flip(NativeArray <float2> points, ref NativeArray <int> stack, ref int stackCount, int a, int b, int x)
        {
            int y = OppositeOf(a, b);

            if (y < 0)
            {
                return(true);
            }

            if (b < a)
            {
                int tmp = a;
                a   = b;
                b   = tmp;
                tmp = x;
                x   = y;
                y   = tmp;
            }

            if (FindConstraint(a, b) != -1)
            {
                return(true);
            }

            if (UTess.IsInsideCircle(points[a], points[b], points[x], points[y]))
            {
                if ((2 + stackCount) >= stack.Length)
                {
                    return(false);
                }
                stack[stackCount++] = a;
                stack[stackCount++] = b;
            }

            return(true);
        }
        public int Compare(int2 a, int2 b)
        {
            var e1a = edges[a.x];
            var e1b = edges[a.y];
            var e2a = edges[b.x];
            var e2b = edges[b.y];

            xvasort[0] = points[e1a.x].x;
            xvasort[1] = points[e1a.y].x;
            xvasort[2] = points[e1b.x].x;
            xvasort[3] = points[e1b.y].x;

            xvbsort[0] = points[e2a.x].x;
            xvbsort[1] = points[e2a.y].x;
            xvbsort[2] = points[e2b.x].x;
            xvbsort[3] = points[e2b.y].x;

            fixed(double *xvasortPtr = xvasort)
            {
                UTess.InsertionSort <double, XCompare>(xvasortPtr, 0, 3, new XCompare());
            }

            fixed(double *xvbsortPtr = xvbsort)
            {
                UTess.InsertionSort <double, XCompare>(xvbsortPtr, 0, 3, new XCompare());
            }

            for (int i = 0; i < 4; ++i)
            {
                if (xvasort[i] - xvbsort[i] != 0)
                {
                    return(xvasort[i] < xvbsort[i] ? -1 : 1);
                }
            }
            return(points[e1a.x].y < points[e1a.x].y ? -1 : 1);
        }
Exemple #17
0
        bool SplitHulls(NativeArray <UHull> hulls, ref int hullCount, NativeArray <float2> points, UEvent evt)
        {
            int index = UTess.GetLower(hulls, hullCount, evt, new TestHullEventLe());

            if (index < 0)
            {
                return(false);
            }

            UHull hull = hulls[index];

            UHull newHull;

            newHull.a   = evt.a;
            newHull.b   = evt.b;
            newHull.idx = evt.idx;

            int y = hull.iuarray[hull.iucount - 1];

            newHull.iuarray = new ArraySlice <int>(m_IUArray, newHull.idx * m_NumHulls, m_NumHulls);
            newHull.iucount = hull.iucount;
            for (int i = 0; i < newHull.iucount; ++i)
            {
                newHull.iuarray[i] = hull.iuarray[i];
            }
            hull.iuarray[0] = y;
            hull.iucount    = 1;
            hulls[index]    = hull;

            newHull.ilarray    = new ArraySlice <int>(m_ILArray, newHull.idx * m_NumHulls, m_NumHulls);
            newHull.ilarray[0] = y;
            newHull.ilcount    = 1;

            InsertHull(hulls, index + 1, ref hullCount, newHull);
            return(true);
        }
        internal static void BuildTrianglesAndEdges(NativeArray <float2> vertices, int vertexCount, NativeArray <int> indices, int indexCount, ref NativeArray <UTriangle> triangles, ref int triangleCount, ref NativeArray <int4> delaEdges, ref int delaEdgeCount, ref float maxArea)
        {
            // Check if there are invalid triangles or segments.
            for (int i = 0; i < indexCount; i += 3)
            {
                UTriangle tri = new UTriangle();
                var       i0  = indices[i + 0];
                var       i1  = indices[i + 1];
                var       i2  = indices[i + 2];
                tri.va      = vertices[i0];
                tri.vb      = vertices[i1];
                tri.vc      = vertices[i2];
                tri.c       = UTess.CircumCircle(tri);
                tri.area    = UTess.TriangleArea(tri.va, tri.vb, tri.vc);
                maxArea     = math.max(tri.area, maxArea);
                tri.indices = new int3(i0, i1, i2);

                // Outputs.
                delaEdges[delaEdgeCount++] = new int4(math.min(i0, i1), math.max(i0, i1), triangleCount, -1);
                delaEdges[delaEdgeCount++] = new int4(math.min(i1, i2), math.max(i1, i2), triangleCount, -1);
                delaEdges[delaEdgeCount++] = new int4(math.min(i2, i0), math.max(i2, i0), triangleCount, -1);
                triangles[triangleCount++] = tri;
            }
        }
        // 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>(UTess.kMaxEdgeCount, allocator);
            NativeArray <double2> points            = new NativeArray <double2>(UTess.kMaxVertexCount, allocator);
            NativeArray <int2>    tJunctions        = new NativeArray <int2>(UTess.kMaxEdgeCount, allocator);
            NativeArray <int2>    edgeIntersections = new NativeArray <int2>(UTess.kMaxEdgeCount, allocator);
            NativeArray <int>     duplicates        = new NativeArray <int>(UTess.kMaxVertexCount, allocator);
            NativeArray <double2> intersects        = new NativeArray <double2>(UTess.kMaxEdgeCount, allocator);

            // Initialize.
            for (int i = 0; i < pointCount; ++i)
            {
                points[i] = inputPoints[i];
            }
            UTess.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);
                RemoveDuplicateEdges(ref edges, ref edgeCount, duplicates, duplicateCount);

                requiresFix = intersectionCount != 0 || tJunctionCount != 0;
            }

            if (validGraph)
            {
                // Finalize Output.
                outputEdgeCount  = edgeCount;
                outputPointCount = pointCount;
                UTess.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);
        }
        internal static bool CutEdges(ref NativeArray <double2> points, ref int pointCount, ref NativeArray <int2> edges, ref int edgeCount, ref NativeArray <int2> tJunctions, ref int tJunctionCount, NativeArray <int2> intersections, NativeArray <double2> intersects, int intersectionCount)
        {
            for (int i = 0; i < intersectionCount; ++i)
            {
                var intr = intersections[i];
                var e    = intr.x;
                var f    = intr.y;

                int2 j1 = int2.zero;
                j1.x = e;
                j1.y = pointCount;
                tJunctions[tJunctionCount++] = j1;
                int2 j2 = int2.zero;
                j2.x = f;
                j2.y = pointCount;
                tJunctions[tJunctionCount++] = j2;

                // Until we ensure Outline is generated properly, we need this useless Check every correction.
                if (pointCount >= points.Length)
                {
                    return(false);
                }

                points[pointCount++] = intersects[i];
            }

            unsafe
            {
                UTess.InsertionSort <int2, TessJunctionCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(tJunctions), 0, tJunctionCount - 1,
                    new TessJunctionCompare());
            }

            // Split edges along junctions
            for (int i = tJunctionCount - 1; i >= 0; --i)
            {
                var tJunction = tJunctions[i];
                var e         = tJunction.x;
                var edge      = edges[e];
                var s         = edge.x;
                var t         = edge.y;

                // Check if edge is not lexicographically sorted
                var a = points[s];
                var b = points[t];
                if (((a.x - b.x) < 0) || (a.x == b.x && (a.y - b.y) < 0))
                {
                    var tmp = s;
                    s = t;
                    t = tmp;
                }

                // Split leading edge
                edge.x = s;
                var last = edge.y = tJunction.y;
                edges[e] = edge;

                // If we are grouping edges by color, remember to track data
                // Split other edges
                while (i > 0 && tJunctions[i - 1].x == e)
                {
                    var  next = tJunctions[--i].y;
                    int2 te   = new int2();
                    te.x = last;
                    te.y = next;
                    edges[edgeCount++] = te;
                    last = next;
                }

                int2 le = new int2();
                le.x = last;
                le.y = t;
                edges[edgeCount++] = le;
            }

            return(true);
        }
Exemple #21
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 refined    = false;
            var validGraph = true;

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

            UTess.BuildTriangles(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref maxArea);
            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)
                    {
                        UTess.BuildTriangles(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref maxArea);
                    }

                    // 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);
        }
Exemple #22
0
        internal bool Triangulate(NativeArray <float2> points, int pointCount, NativeArray <int2> edges, int edgeCount)
        {
            m_NumEdges  = edgeCount;
            m_NumHulls  = edgeCount * 2;
            m_NumPoints = pointCount;
            m_CellCount = 0;
            m_Cells     = new NativeArray <int3>(UTess.kMaxTriangleCount, m_Allocator);
            m_ILArray   = new NativeArray <int>(m_NumHulls * (m_NumHulls + 1), m_Allocator); // Make room for -1 node.
            m_IUArray   = new NativeArray <int>(m_NumHulls * (m_NumHulls + 1), m_Allocator); // Make room for -1 node.

            NativeArray <UHull> hulls = new NativeArray <UHull>(m_NumPoints * 8, m_Allocator);
            int hullCount             = 0;

            NativeArray <UEvent> events = new NativeArray <UEvent>(m_NumPoints + (m_NumEdges * 2), m_Allocator);
            int eventCount = 0;

            for (int i = 0; i < m_NumPoints; ++i)
            {
                UEvent evt = new UEvent();
                evt.a                = points[i];
                evt.b                = new float2();
                evt.idx              = i;
                evt.type             = (int)UEventType.EVENT_POINT;
                events[eventCount++] = evt;
            }

            for (int i = 0; i < m_NumEdges; ++i)
            {
                int2   e = edges[i];
                float2 a = points[e.x];
                float2 b = points[e.y];
                if (a.x < b.x)
                {
                    UEvent _s = new UEvent();
                    _s.a    = a;
                    _s.b    = b;
                    _s.idx  = i;
                    _s.type = (int)UEventType.EVENT_START;

                    UEvent _e = new UEvent();
                    _e.a    = b;
                    _e.b    = a;
                    _e.idx  = i;
                    _e.type = (int)UEventType.EVENT_END;

                    events[eventCount++] = _s;
                    events[eventCount++] = _e;
                }
                else if (a.x > b.x)
                {
                    UEvent _s = new UEvent();
                    _s.a    = b;
                    _s.b    = a;
                    _s.idx  = i;
                    _s.type = (int)UEventType.EVENT_START;

                    UEvent _e = new UEvent();
                    _e.a    = a;
                    _e.b    = b;
                    _e.idx  = i;
                    _e.type = (int)UEventType.EVENT_END;

                    events[eventCount++] = _s;
                    events[eventCount++] = _e;
                }
            }

            unsafe
            {
                UTess.InsertionSort <UEvent, TessEventCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(events), 0, eventCount - 1,
                    new TessEventCompare());
                ;
            }

            var   hullOp = true;
            float minX   = events[0].a.x - (1 + math.abs(events[0].a.x)) * math.pow(2.0f, -16.0f);
            UHull hull;

            hull.a.x           = minX;
            hull.a.y           = 1;
            hull.b.x           = minX;
            hull.b.y           = 0;
            hull.idx           = -1;
            hull.ilarray       = new ArraySlice <int>(m_ILArray, m_NumHulls * m_NumHulls, m_NumHulls); // Last element
            hull.iuarray       = new ArraySlice <int>(m_IUArray, m_NumHulls * m_NumHulls, m_NumHulls);
            hull.ilcount       = 0;
            hull.iucount       = 0;
            hulls[hullCount++] = hull;


            for (int i = 0, numEvents = eventCount; i < numEvents; ++i)
            {
                switch (events[i].type)
                {
                case (int)UEventType.EVENT_POINT:
                {
                    hullOp = AddPoint(hulls, hullCount, points, events[i].a, events[i].idx);
                }
                break;

                case (int)UEventType.EVENT_START:
                {
                    hullOp = SplitHulls(hulls, ref hullCount, points, events[i]);
                }
                break;

                default:
                {
                    hullOp = MergeHulls(hulls, ref hullCount, points, events[i]);
                }
                break;
                }

                if (!hullOp)
                {
                    break;
                }
            }

            events.Dispose();
            hulls.Dispose();
            return(hullOp);
        }
Exemple #23
0
        NativeArray <int3> Constrain(ref int count)
        {
            var cells = GetCells(ref count);
            int nc    = count;

            for (int i = 0; i < nc; ++i)
            {
                int3 c = cells[i];
                int  x = c.x, y = c.y, z = c.z;
                if (y < z)
                {
                    if (y < x)
                    {
                        c.x = y;
                        c.y = z;
                        c.z = x;
                    }
                }
                else if (z < x)
                {
                    c.x = z;
                    c.y = x;
                    c.z = y;
                }

                cells[i] = c;
            }

            unsafe
            {
                UTess.InsertionSort <int3, TessCellCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(cells), 0, m_CellCount - 1,
                    new TessCellCompare());
            }

            // Out
            m_Flags       = new NativeArray <int>(nc, m_Allocator);
            m_Neighbors   = new NativeArray <int>(nc * 3, m_Allocator);
            m_Constraints = new NativeArray <int>(nc * 3, m_Allocator);
            var next   = new NativeArray <int>(nc * 3, m_Allocator);
            var active = new NativeArray <int>(nc * 3, m_Allocator);

            int side = 1, nextCount = 0, activeCount = 0;

            for (int i = 0; i < nc; ++i)
            {
                int3 c = cells[i];
                for (int j = 0; j < 3; ++j)
                {
                    int x = j, y = (j + 1) % 3;
                    x = (x == 0) ? c.x : (j == 1) ? c.y : c.z;
                    y = (y == 0) ? c.x : (y == 1) ? c.y : c.z;

                    int o = OppositeOf(y, x);
                    int a = m_Neighbors[3 * i + j] = FindNeighbor(cells, count, y, x, o);
                    int b = m_Constraints[3 * i + j] = (-1 != FindConstraint(x, y)) ? 1 : 0;
                    if (a < 0)
                    {
                        if (0 != b)
                        {
                            next[nextCount++] = i;
                        }
                        else
                        {
                            active[activeCount++] = i;
                            m_Flags[i]            = 1;
                        }
                    }
                }
            }

            while (activeCount > 0 || nextCount > 0)
            {
                while (activeCount > 0)
                {
                    int t = active[activeCount - 1];
                    activeCount--;
                    if (m_Flags[t] == -side)
                    {
                        continue;
                    }

                    m_Flags[t] = side;
                    int3 c = cells[t];
                    for (int j = 0; j < 3; ++j)
                    {
                        int f = m_Neighbors[3 * t + j];
                        if (f >= 0 && m_Flags[f] == 0)
                        {
                            if (0 != m_Constraints[3 * t + j])
                            {
                                next[nextCount++] = f;
                            }
                            else
                            {
                                active[activeCount++] = f;
                                m_Flags[f]            = side;
                            }
                        }
                    }
                }

                for (int e = 0; e < nextCount; e++)
                {
                    active[e] = next[e];
                }
                activeCount = nextCount;
                nextCount   = 0;
                side        = -side;
            }

            active.Dispose();
            next.Dispose();
            return(cells);
        }
Exemple #24
0
        // Perform Voronoi based Smoothing. Does not add/remove points but merely relocates internal vertices so they are uniform distributed.
        public 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, cmpArea = 0;
            bool  polygonCentroid = true, validGraph = true;
            int   triangleCount = 0, delaEdgeCount = 0, affectingEdgeCount = 0;
            var   triangles    = new NativeArray <UTriangle>(indexCount / 3, allocator);
            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);

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

            // Sort the Delaunay Edges.
            unsafe
            {
                UTess.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)
                {
                    UTess.BuildTriangles(vertices, vertexCount, indices, indexCount, ref triangles, ref triangleCount, ref cmpArea);
                }
            }

            // Cleanup.
            triangles.Dispose();
            delaEdges.Dispose();
            refinedEdges.Dispose();
            voronoiCheck.Dispose();
            voronoiEdges.Dispose();
            affectsEdges.Dispose();
            triCentroids.Dispose();
            connectedTri.Dispose();
            return(validGraph && srcIndexCount == indexCount && srcVertexCount == vertexCount && (cmpArea < maxArea * kAreaTolerance));
        }
Exemple #25
0
        internal bool ApplyDelaunay(NativeArray <float2> points, NativeArray <int2> edges)
        {
            NativeArray <int> stack = new NativeArray <int>(m_NumPoints * (m_NumPoints + 1), m_Allocator);
            int stackCount          = 0;
            var valid = true;

            PrepareDelaunay(edges, m_NumEdges);
            for (int a = 0; valid && (a < m_NumPoints); ++a)
            {
                UStar star = m_Stars[a];
                for (int j = 1; j < star.pointCount; j += 2)
                {
                    int b = star.points[j];

                    if (b < a)
                    {
                        continue;
                    }

                    if (FindConstraint(a, b) >= 0)
                    {
                        continue;
                    }

                    int x = star.points[j - 1], y = -1;
                    for (int k = 1; k < star.pointCount; k += 2)
                    {
                        if (star.points[k - 1] == b)
                        {
                            y = star.points[k];
                            break;
                        }
                    }

                    if (y < 0)
                    {
                        continue;
                    }

                    if (UTess.IsInsideCircle(points[a], points[b], points[x], points[y]))
                    {
                        if ((2 + stackCount) >= stack.Length)
                        {
                            valid = false;
                            break;
                        }

                        stack[stackCount++] = a;
                        stack[stackCount++] = b;
                    }
                }
            }

            var flipFlops = m_NumPoints * m_NumPoints;

            while (stackCount > 0 && valid)
            {
                int b = stack[stackCount - 1];
                stackCount--;
                int a = stack[stackCount - 1];
                stackCount--;

                int   x = -1, y = -1;
                UStar star = m_Stars[a];
                for (int i = 1; i < star.pointCount; i += 2)
                {
                    int s = star.points[i - 1];
                    int t = star.points[i];
                    if (s == b)
                    {
                        y = t;
                    }
                    else if (t == b)
                    {
                        x = s;
                    }
                }

                if (x < 0 || y < 0)
                {
                    continue;
                }

                if (!UTess.IsInsideCircle(points[a], points[b], points[x], points[y]))
                {
                    continue;
                }

                EdgeFlip(a, b);

                valid = Flip(points, ref stack, ref stackCount, x, a, y);
                valid = valid && Flip(points, ref stack, ref stackCount, a, y, x);
                valid = valid && Flip(points, ref stack, ref stackCount, y, b, x);
                valid = valid && Flip(points, ref stack, ref stackCount, b, x, y);
                valid = valid && (--flipFlops > 0);
            }

            stack.Dispose();
            return(valid);
        }
Exemple #26
0
 public bool Test(UHull h, float2 p, ref float t)
 {
     t = UTess.OrientFast(h.a, h.b, p);
     return(t > 0);
 }
Exemple #27
0
        void PrepareDelaunay(NativeArray <int2> edges, int edgeCount)
        {
            m_StarCount = m_CellCount * 3;
            m_Stars     = new NativeArray <UStar>(m_StarCount, m_Allocator);
            m_SPArray   = new NativeArray <int>(m_StarCount * m_StarCount, m_Allocator);

            var UEdgeCount = 0;
            var UEdges     = new NativeArray <int2>(m_StarCount, m_Allocator);

            // Input Edges.
            for (int i = 0; i < edgeCount; ++i)
            {
                int2 e = edges[i];
                e.x      = (edges[i].x < edges[i].y) ? edges[i].x : edges[i].y;
                e.y      = (edges[i].x > edges[i].y) ? edges[i].x : edges[i].y;
                edges[i] = e;
                InsertUniqueEdge(UEdges, e, ref UEdgeCount);
            }

            m_Edges = new NativeArray <int2>(UEdgeCount, m_Allocator);
            for (int i = 0; i < UEdgeCount; ++i)
            {
                m_Edges[i] = UEdges[i];
            }
            UEdges.Dispose();

            unsafe
            {
                UTess.InsertionSort <int2, TessEdgeCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_Edges), 0, m_Edges.Length - 1,
                    new TessEdgeCompare());
            }

            // Init Stars.
            for (int i = 0; i < m_StarCount; ++i)
            {
                UStar s = m_Stars[i];
                s.points     = new ArraySlice <int>(m_SPArray, i * m_StarCount, m_StarCount);
                s.pointCount = 0;
                m_Stars[i]   = s;
            }

            // Fill stars.
            for (int i = 0; i < m_CellCount; ++i)
            {
                int   a  = m_Cells[i].x;
                int   b  = m_Cells[i].y;
                int   c  = m_Cells[i].z;
                UStar sa = m_Stars[a];
                UStar sb = m_Stars[b];
                UStar sc = m_Stars[c];
                sa.points[sa.pointCount++] = b;
                sa.points[sa.pointCount++] = c;
                sb.points[sb.pointCount++] = c;
                sb.points[sb.pointCount++] = a;
                sc.points[sc.pointCount++] = a;
                sc.points[sc.pointCount++] = b;
                m_Stars[a] = sa;
                m_Stars[b] = sb;
                m_Stars[c] = sc;
            }
        }