public override void ApplyPolygonList(List <DTPolygon> dtPolygonList)
        {
            if (dtPolygon == dtPolygonList[0])
            {
                return;
            }
            dtPolygon = dtPolygonList[0];

            DTProfilerMarkers.Triangulation.Begin();
            DTMesh triMesh = GetTriangulator().PolygonToMesh(dtPolygon);

            DTProfilerMarkers.Triangulation.End();

            DTConvexPolygroup triPolygroup = triMesh.ToPolygroup();

            // Collider from polygon
            DTProfilerMarkers.HertelMehlhorn.Begin();
            DTConvexPolygroup hmPolygroup = HertelMehlhorn.PolyPartitionHM.Instance.ExecuteToPolygroup(triPolygroup);

            DTProfilerMarkers.HertelMehlhorn.End();

            DTProfilerMarkers.ApplyCollider.Begin();
            ApplyCollider(hmPolygroup);
            DTProfilerMarkers.ApplyCollider.End();

            // Create mesh from triangulated polygon
            ApplyRenderMesh(triMesh);
        }
        public override void ApplyPolygonList(List <DTPolygon> dtPolygonList)
        {
            if (dtPolygon == dtPolygonList[0])
            {
                return;
            }
            dtPolygon = dtPolygonList[0];

            DTProfilerMarkers.Triangulation.Begin();
            DTMesh dtMesh = GetTriangulator().PolygonToMesh(dtPolygon);

            DTProfilerMarkers.Triangulation.End();

            // Collider from polygon
            DTProfilerMarkers.HertelMehlhorn.Begin();
            DTMesh hmMesh = HertelMehlhorn.CustomHM.Instance.ExecuteToMesh(dtMesh);

            DTProfilerMarkers.HertelMehlhorn.End();

            DTProfilerMarkers.ApplyCollider.Begin();
            ApplyCollider(hmMesh);
            DTProfilerMarkers.ApplyCollider.End();

            // Create mesh from triangulated polygon
            ApplyRenderMesh(dtMesh);
        }
示例#3
0
        public DTMesh PolygonToMesh(DTPolygon subject)
        {
            // Mark any unmarked holes in the contour, otherwise Triangle.NET won't handle them properly
            subject = DTUtility.IdentifyHoles(subject);
            if (subject.Contour.Count < 3)
            {
                return(new DTMesh());
            }
            // Don't triangulate if this is already a triangle
            else if (subject.Contour.Count == 3 && subject.Holes.Count == 0)
            {
                return(new DTMesh(subject.Contour, new List <List <int> >()
                {
                    new List <int>()
                    {
                        0, 1, 2
                    }
                }));
            }
            // If the polygon is convex, use simple fanning technique to triangulate
            else if (subject.IsConvex())
            {
                DTMesh mesh = new DTMesh(subject.Contour, new List <List <int> >());
                for (int i = 1; i < subject.Contour.Count - 1; i++)
                {
                    mesh.Partitions.Add(new List <int>()
                    {
                        0, i, i + 1
                    });
                }
                return(mesh);
            }

            // Format polygon input and execute
            Polygon polygon = new Polygon();

            polygon.Add(new Contour(subject.Contour.ToVertexList()), false);
            foreach (var hole in subject.Holes)
            {
                if (hole.Count >= 3)
                {
                    try {
                        polygon.Add(new Contour(hole.ToVertexList()), true);
                    }
                    catch (Exception) { }
                }
            }
            DTProfilerMarkers.TriangleNet.Begin();
            IMesh triangleNetOutput = polygon.Triangulate();

            ++callCount;
            DTProfilerMarkers.TriangleNet.End();

            // Convert Triangle.NET output into DTMesh
            List <Vector2>     vertices  = triangleNetOutput.Vertices.ToVector2List();
            List <List <int> > triangles = triangleNetOutput.Triangles.ToPartitionList();

            return(new DTMesh(vertices, triangles));
        }
    public static DTConvexPolygroup ToPolygroup(this DTMesh mesh)
    {
        DTProfilerMarkers.MeshToPolygroup.Begin();
        DTConvexPolygroup polygroup = new DTConvexPolygroup(
            mesh.Partitions.Select(part => part.Select(i => mesh.Vertices[i]).ToList()).ToList());

        DTProfilerMarkers.MeshToPolygroup.End();
        return(polygroup);
    }
示例#5
0
        protected void ApplyRenderMesh(DTMesh dtMesh)
        {
            if (dtRenderMesh == dtMesh)
            {
                return;
            }
            dtRenderMesh = dtMesh;

            MeshFilter mf = GetComponent <MeshFilter>();

            mf.sharedMesh = new Mesh()
            {
                vertices  = dtMesh.Vertices.Select(v => new Vector3(v.x, v.y)).ToArray(),
                uv        = dtMesh.Vertices.ToArray(),
                triangles = dtMesh.Partitions.SelectMany(t => t.GetRange(0, 3).AsEnumerable().Reverse()).ToArray()
            };
        }
示例#6
0
        protected void ApplyCollider(DTMesh dtMesh)
        {
            PolygonCollider2D polygonCollider = GetComponent <PolygonCollider2D>();

            polygonCollider.pathCount = dtMesh.Partitions.Count;
            int i = 0;

            foreach (var partition in dtMesh.Partitions)
            {
                polygonCollider.SetPath(i++, partition.Select(vIndex => dtMesh.Vertices[vIndex]).ToArray());
            }

            if (GetComponent <Rigidbody2D>().mass < MassCutoff)
            {
                Destroy(gameObject);
            }
        }
        public override void ApplyPolygonList(List <DTPolygon> dtPolygonList)
        {
            if (dtPolygon == dtPolygonList[0])
            {
                return;
            }
            dtPolygon = dtPolygonList[0];

            // Collider from polygon
            DTProfilerMarkers.ApplyCollider.Begin();
            ApplyCollider(dtPolygon);
            DTProfilerMarkers.ApplyCollider.End();

            // Create mesh from triangulated polygon
            DTProfilerMarkers.Triangulation.Begin();
            DTMesh dtMesh = GetTriangulator().PolygonToMesh(dtPolygon);

            DTProfilerMarkers.Triangulation.End();
            ApplyRenderMesh(dtMesh);
        }
    public static DTMesh ToMesh(this DTConvexPolygroup polygroup)
    {
        DTProfilerMarkers.PolygroupToMesh.Begin();

        // List of unique vertices for the mesh
        List <Vector2> vertices = new List <Vector2>();

        // Maps each vertex to its index in the vertices list
        Dictionary <Vector2, int> vertexMap = new Dictionary <Vector2, int>(new ApproximateVector2Comparer());

        // List of partitions, each of which is a list of vertex indices
        List <List <int> > partitions = new List <List <int> >(polygroup.Count);

        foreach (var poly in polygroup)
        {
            // Indices of the vertices in this partition
            List <int> indices = new List <int>();
            foreach (var v in poly)
            {
                // Get the mapped index of the vertex. If the vertex is not yet mapped, map it to the index at the end
                // of the vertices list
                if (!vertexMap.TryGetValue(v, out int index))
                {
                    index = vertices.Count;
                    vertexMap.Add(v, index);
                    vertices.Add(v);
                }
                indices.Add(index);
            }
            partitions.Add(indices);
        }

        DTMesh mesh = new DTMesh(vertices, partitions);

        DTProfilerMarkers.PolygroupToMesh.End();
        return(mesh);
    }
        public override void ApplyPolygonList(List <DTPolygon> clippedPolygonList)
        {
            // The clipped polygons could potentially be concave or have holes, so we will triangulate each one before applying
            DTProfilerMarkers.Triangulation.Begin();
            DTConvexPolygroup triangleList = DTUtility.TriangulateAll(clippedPolygonList, GetTriangulator());

            DTProfilerMarkers.Triangulation.End();

            // Our Hertel-Mehlhorn implementation takes a DTMesh, so convert before instead of after
            DTMesh triangulatedMesh = triangleList.ToMesh();

            // Collider from polygon
            DTProfilerMarkers.HertelMehlhorn.Begin();
            hmMesh = HertelMehlhorn.CustomHM.Instance.ExecuteToMesh(triangulatedMesh);
            DTProfilerMarkers.HertelMehlhorn.End();

            // Collider from polygon
            DTProfilerMarkers.ApplyCollider.Begin();
            ApplyCollider(hmMesh);
            DTProfilerMarkers.ApplyCollider.End();

            // Create mesh from triangulated polygon
            ApplyRenderMesh(triangulatedMesh);
        }
示例#10
0
 public DTConvexPolygroup ExecuteToPolygroup(DTMesh input)
 {
     return(ExecuteToPolygroup(input.ToPolygroup()));
 }
示例#11
0
 public DTMesh ExecuteToMesh(DTMesh input)
 {
     return(ExecuteToMesh(input.ToPolygroup()));
 }
        // Note: allows output to have consecutive colinear edges in a partition
        public DTMesh ExecuteToMesh(DTMesh input)
        {
            List <int> clearedPolys = new List <int>();
            Dictionary <SimplifiedEdge, Edge> realEdges = new Dictionary <SimplifiedEdge, Edge>();

            List <int>[] tempPartitions = new List <int> [input.Partitions.Count];
            int[]        polyRemapper   = new int[input.Partitions.Count];

            // Local function that gets the remapped polygon index for the given original index
            int getRemappedIndex(int i)
            {
                Stack <int> collapseStack = new Stack <int>();

                while (i != polyRemapper[i])
                {
                    collapseStack.Push(i);
                    i = polyRemapper[i];
                }
                // Lazily collapse remapping chains (entries that remap multiple times should remap only once)
                while (collapseStack.Count > 0)
                {
                    polyRemapper[collapseStack.Pop()] = i;
                }
                return(i);
            }

            // Determine internal edges and map them to their connected polygons
            for (int polyIndex = 0; polyIndex < input.Partitions.Count; polyIndex++)
            {
                List <int> poly = input.Partitions[polyIndex];
                tempPartitions[polyIndex] = new List <int>(poly);
                polyRemapper[polyIndex]   = polyIndex;

                // Add all the initial partitions (triangles if the input was a triangulation)
                for (int vertexIndex = 0; vertexIndex < poly.Count; vertexIndex++)
                {
                    int v     = poly[vertexIndex];
                    int vNext = poly.GetCircular(vertexIndex + 1);

                    SimplifiedEdge e = new SimplifiedEdge(v, vNext);
                    if (!realEdges.ContainsKey(e))
                    {
                        // If this is the first time visiting this edge, make a new entry and add the right polygon
                        realEdges[e] = new Edge(e, polyIndex);
                    }
                    else
                    {
                        // If we have already visited this edge, add the left polygon and make the edge bidirectional
                        realEdges[e].IsBidirectional = true;
                        realEdges[e].LeftPoly        = polyIndex;
                    }
                }
            }

            // Iterate internal edges and check if they can be removed without creating concave partitions
            foreach (var internalEdgePair in realEdges.Where(edgePair => edgePair.Value.IsBidirectional))
            {
                SimplifiedEdge simpleEdge = internalEdgePair.Key;
                Edge           realEdge   = internalEdgePair.Value;

                // Find the index within the right polygon where the shared edge ends (P1)
                int        rightPolyIndex = getRemappedIndex(realEdge.RightPoly);
                List <int> rightPoly      = tempPartitions[rightPolyIndex];
                int        rightPolyStart = -1;
                for (int i = 0; i < rightPoly.Count; i++)
                {
                    int p = rightPoly[i];
                    if (p == simpleEdge.P1)
                    {
                        rightPolyStart = i;
                        break;
                    }
                }

                // Find the index within the left polygon where the shared edge ends (P0)
                int        leftPolyIndex = getRemappedIndex(realEdge.LeftPoly);
                List <int> leftPoly      = tempPartitions[leftPolyIndex];
                int        leftPolyStart = -1;
                for (int i = 0; i < leftPoly.Count; i++)
                {
                    int p = leftPoly[i];
                    if (p == simpleEdge.P0)
                    {
                        leftPolyStart = i;
                        break;
                    }
                }

                // Determine if the angle at the edge's P0 would become reflex if this edge were removed
                Vector2 rightPolyLastEdge = input.Vertices[rightPoly.GetCircular(rightPolyStart - 1)] - input.Vertices[rightPoly.GetCircular(rightPolyStart - 2)];
                Vector2 leftPolyFirstEdge = input.Vertices[leftPoly.GetCircular(leftPolyStart + 1)] - input.Vertices[leftPoly.GetCircular(leftPolyStart)];
                bool    p0Reflex          = Vector3.Cross(rightPolyLastEdge, leftPolyFirstEdge).z > 0;

                // Determine if the angle at the edge's P1 would become reflex if this edge were removed
                Vector2 leftPolyLastEdge   = input.Vertices[leftPoly.GetCircular(leftPolyStart - 1)] - input.Vertices[leftPoly.GetCircular(leftPolyStart - 2)];
                Vector2 rightPolyFirstEdge = input.Vertices[rightPoly.GetCircular(rightPolyStart + 1)] - input.Vertices[rightPoly.GetCircular(rightPolyStart)];
                bool    p1Reflex           = Vector3.Cross(leftPolyLastEdge, rightPolyFirstEdge).z > 0;

                if (!p0Reflex && !p1Reflex)
                {
                    // Remove the edge and merge the two polygons since the result will be convex

                    // Add points from rightPoly in CW order from the removed edge's P1 to P0, including P1 but not P0
                    List <int> newPoly = rightPoly.GetRange(rightPolyStart, rightPoly.Count - rightPolyStart);
                    newPoly.AddRange(rightPoly.GetRange(0, rightPolyStart));
                    newPoly.RemoveAt(newPoly.Count - 1);

                    // Add points from left in CW order from the removed edge's P0 to P1, including P0 but not P1
                    newPoly.AddRange(leftPoly.GetRange(leftPolyStart, leftPoly.Count - leftPolyStart));
                    newPoly.AddRange(leftPoly.GetRange(0, leftPolyStart));
                    newPoly.RemoveAt(newPoly.Count - 1);

                    // Modify the right polygon
                    rightPoly.Clear();
                    rightPoly.AddRange(newPoly);

                    // Clear the left polygon
                    leftPoly.Clear();
                    clearedPolys.Add(leftPolyIndex);

                    // Remap the left polygon index to match the right
                    polyRemapper[leftPolyIndex] = rightPolyIndex;
                }
            }

            // Return a new mesh that copies the vertices of the original, but uses the merged partitions
            // (ignores the left partitions that we cleared)
            return(new DTMesh(new List <Vector2>(input.Vertices),
                              tempPartitions.Where(partition => partition.Count > 0).ToList()));
        }