Exemple #1
0
        public static Delaunay Delaunay(this PlainShape shape, long maxEdge, NativeArray <IntVector> extraPoints, Allocator allocator)
        {
            var layout = shape.Split(maxEdge, extraPoints, Allocator.Temp);

            int holesCount = shape.layouts.Length;
            int totalCount = layout.pathCount + 2 * layout.extraCount + holesCount * 2 - 2;

            var triangleStack = new TriangleStack(totalCount, allocator);

            for (int i = 0; i < layout.indices.Length; ++i)
            {
                int index = layout.indices[i];
                Triangulate(index, layout.links, ref triangleStack);
                triangleStack.Reset();
            }

            var triangles = triangleStack.Convert();

            var sliceBuffer = new SliceBuffer(layout.links.Length, layout.slices, Allocator.Temp);

            sliceBuffer.AddConnections(triangles);

            sliceBuffer.Dispose();
            layout.Dispose();

            Delaunay delaunay;

            if (extraPoints.Length == 0 && maxEdge == 0)
            {
                delaunay = new Delaunay(shape.points, triangles, allocator);
            }
            else
            {
                var points = new NativeArray <IntVector>(layout.links.Length, Allocator.Temp);
                for (int i = 0; i < layout.links.Length; ++i)
                {
                    var link = layout.links[i];
                    points[link.vertex.index] = link.vertex.point;
                }
                delaunay = new Delaunay(points, triangles, allocator);
                points.Dispose();
            }

            delaunay.Build();

            return(delaunay);
        }
Exemple #2
0
        public static List ConvexPolygons(this Delaunay self, IntGeom intGeom, Allocator allocator)
        {
            int n           = self.triangles.Count;
            var dynamicList = new DynamicList(self.points.Count, n >> 1, allocator);
            var visited     = new NativeArray <bool>(n, Allocator.Temp);

            for (int i = 0; i < n; ++i)
            {
                if (visited[i])
                {
                    continue;
                }

                var first = self.triangles[i];
                visited[i] = true;
                var convexPolygon = new ConvexPolygon(first);

                while (convexPolygon.edges.Count > 0)
                {
                    var edge = convexPolygon.edges.Last();
                    convexPolygon.edges.RemoveLast();
                    if (visited[edge.neighbor])
                    {
                        continue;
                    }

                    var next = self.triangles[edge.neighbor];
                    if (convexPolygon.Add(edge, next))
                    {
                        visited[edge.neighbor] = true;
                    }
                }

                var iPoints = convexPolygon.Points(Allocator.Temp);
                var points  = intGeom.Float(iPoints, Allocator.Temp);
                var polygon = new Polygon(points, allocator);
                dynamicList.Add(polygon);

                iPoints.Dispose();
                points.Dispose();
                convexPolygon.Dispose();
            }

            visited.Dispose();

            return(dynamicList.Convert());
        }
        public static PlainShape MakeCentroidNet(this Delaunay self, Allocator allocator, long minArea = 0, bool onlyConvex = false)
        {
            int n = self.triangles.Count;

            var details = new NativeArray <Detail>(n, Allocator.Temp);

            for (int i = 0; i < n; ++i)
            {
                var triangle = self.triangles[i];
                var count    = 0;
                if (triangle.nA >= 0)
                {
                    ++count;
                }

                if (triangle.nB >= 0)
                {
                    ++count;
                }

                if (triangle.nC >= 0)
                {
                    ++count;
                }

                details[i] = new Detail(triangle.Center(), count);
            }

            int capacity = self.points.Count;

            var visitedIndex = new NativeArray <bool>(capacity, Allocator.Temp);
            var result       = new DynamicPlainShape(8 * capacity, capacity, allocator);
            var forePoints   = new NativeArray <IntVector>(4, Allocator.Temp);
            var path         = new DynamicArray <IntVector>(8, Allocator.Temp);
            var subPath      = new DynamicArray <IntVector>(8, Allocator.Temp);

            for (int i = 0; i < n; ++i)
            {
                var triangle = self.triangles[i];
                var detail   = details[i];

                for (int j = 0; j <= 2; ++j)
                {
                    var v = triangle.Vertex(j);
                    if (visitedIndex[v.index])
                    {
                        continue;
                    }

                    visitedIndex[v.index] = true;

                    if (v.isPath)
                    {
                        if (detail.count == 1 && triangle.Neighbor(j) >= 0)
                        {
                            switch (j)
                            {
                            case 0:     // a
                                var ab0 = v.point.Center(triangle.vB.point);
                                var ca0 = v.point.Center(triangle.vC.point);

                                forePoints[0] = v.point;
                                forePoints[1] = ab0;
                                forePoints[2] = detail.center;
                                forePoints[3] = ca0;
                                break;

                            case 1:     // b
                                var bc1 = v.point.Center(point: triangle.vC.point);
                                var ab1 = v.point.Center(point: triangle.vA.point);

                                forePoints[0] = v.point;
                                forePoints[1] = bc1;
                                forePoints[2] = detail.center;
                                forePoints[3] = ab1;
                                break;

                            default:     // c
                                var ca2 = v.point.Center(point: triangle.vA.point);
                                var bc2 = v.point.Center(point: triangle.vB.point);

                                forePoints[0] = v.point;
                                forePoints[1] = ca2;
                                forePoints[2] = detail.center;
                                forePoints[3] = bc2;
                                break;
                            }

                            if (minArea == 0 || forePoints.Area() > minArea)
                            {
                                result.Add(forePoints, true);
                            }
                        }
                        else
                        {
                            path.RemoveAll();
                            // first going in a counterclockwise direction
                            var current = triangle;
                            int k       = triangle.FindIndex(v.index);
                            int right   = (k + 2) % 3;
                            var prev    = triangle.Neighbor(right);
                            while (prev >= 0)
                            {
                                var prevTriangle = self.triangles[prev];
                                k = prevTriangle.FindIndex(v.index);
                                if (k < 0)
                                {
                                    break;
                                }

                                current = prevTriangle;
                                path.Add(details[prev].center);

                                right = (k + 2) % 3;
                                prev  = current.Neighbor(right);
                            }

                            var left         = (k + 1) % 3;
                            var lastPrevPair = current.Vertex(left).point;
                            path.Add(lastPrevPair.Center(v.point));

                            path.array.Reverse();

                            path.Add(details[i].center);

                            // now going in a clockwise direction
                            current = triangle;
                            k       = triangle.FindIndex(v.index);
                            left    = (k + 1) % 3;
                            var next = triangle.Neighbor(left);
                            while (next >= 0)
                            {
                                var nextTriangle = self.triangles[next];
                                k = nextTriangle.FindIndex(v.index);
                                if (k < 0)
                                {
                                    break;
                                }

                                current = nextTriangle;
                                path.Add(details[next].center);
                                left = (k + 1) % 3;
                                next = current.Neighbor(left);
                            }

                            right = (k + 2) % 3;
                            var lastNextPair = current.Vertex(right).point;
                            path.Add(lastNextPair.Center(v.point));

                            if (onlyConvex)
                            {
                                // split path into convex subPath
                                var c  = v.point;
                                var p0 = path[0];
                                var v0 = p0 - c;
                                var d0 = v0;

                                subPath.RemoveAll();

                                subPath.Add(c);
                                subPath.Add(path[0]);
                                for (int t = 1; t < path.Count; ++t)
                                {
                                    var p1 = path[t];
                                    var d1 = p1 - p0;
                                    var v1 = p1 - c;
                                    if (v0.CrossProduct(v1) <= 0 && d0.CrossProduct(d1) <= 0)
                                    {
                                        subPath.Add(p1);
                                    }
                                    else
                                    {
                                        if (minArea == 0 || subPath.slice.Area() > minArea)
                                        {
                                            result.Add(subPath.slice, true);
                                        }
                                        subPath.RemoveAll();
                                        subPath.Add(c);
                                        subPath.Add(p0);
                                        subPath.Add(p1);
                                        v0 = p0 - c;
                                    }

                                    p0 = p1;
                                    d0 = d1;
                                }

                                if (minArea == 0 || subPath.slice.Area() > minArea)
                                {
                                    result.Add(subPath.slice, true);
                                }
                            }
                            else
                            {
                                path.Add(v.point);
                                if (minArea == 0 || path.slice.Area() > minArea)
                                {
                                    result.Add(path.slice, true);
                                }
                            }
                        }
                    }
                    else
                    {
                        path.RemoveAll();
                        int start = i;
                        var next  = start;
                        do
                        {
                            var t      = self.triangles[next];
                            var center = details[next].center;
                            path.Add(center);
                            int index = (t.FindIndex(v.index) + 1) % 3;
                            next = t.Neighbor(index);
                        } while (next != start && next >= 0);
                        if (minArea == 0 || path.slice.Area() > minArea)
                        {
                            result.Add(path.slice, true);
                        }
                    }
                }
            }

            path.Dispose();
            subPath.Dispose();
            forePoints.Dispose();
            details.Dispose();
            visitedIndex.Dispose();

            return(result.Convert());
        }