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 List <DTPolygon> Subtract(DTPolygon subject, DTPolygon clippingPolygon)
        {
            if (!DTUtility.BoundsCheck(subject.Contour, clippingPolygon.Contour))
            {
                // There is no overlap at all, so output a copy of the subject polygon
                return(new List <DTPolygon>()
                {
                    new DTPolygon(new List <Vector2>(subject.Contour))
                });
            }

            clipper.Clear();

            // Add subject polygon paths
            clipper.AddPath(subject.Contour.ToIntPointList(), PolyType.ptSubject, true);
            foreach (var hole in subject.Holes)
            {
                clipper.AddPath(hole.ToIntPointList(), PolyType.ptSubject, true);
            }

            // Add clipping polygon paths
            clipper.AddPath(clippingPolygon.Contour.ToIntPointList(), PolyType.ptClip, true);
            foreach (var hole in clippingPolygon.Holes)
            {
                clipper.AddPath(hole.ToIntPointList(), PolyType.ptClip, true);
            }

            // Execute subtraction and store result in a PolyTree so that we can easily identify holes
            PolyTree clipperOutput = new PolyTree();

            clipper.Execute(ClipType.ctDifference, clipperOutput, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);

            // Convert Polytree into list of DTPolygons
            return(clipperOutput.ToDTPolygons());
        }
        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);
        }
    // Removes unnecessary vertices
    public static DTPolygon Simplify(this DTPolygon inPoly)
    {
        DTProfilerMarkers.SimplifyPolygon.Begin();

        if (inPoly.Contour.Count == 0)
        {
            DTProfilerMarkers.SimplifyPolygon.End();
            return(null);
        }
        var simplifiedContour = inPoly.Contour.Simplify();

        if (simplifiedContour == null)
        {
            DTProfilerMarkers.SimplifyPolygon.End();
            return(null);
        }

        List <List <Vector2> > simplifiedHoles = new List <List <Vector2> >();

        foreach (var hole in inPoly.Holes)
        {
            var simplifiedHole = hole.Simplify();
            if (simplifiedContour.Count != 0)
            {
                simplifiedHoles.Add(simplifiedHole);
            }
        }

        DTPolygon simplifiedPolygon = new DTPolygon(simplifiedContour, simplifiedHoles);

        DTProfilerMarkers.SimplifyPolygon.End();
        return(simplifiedPolygon);
    }
Ejemplo n.º 5
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));
        }
Ejemplo n.º 6
0
 private static DTPolygon Translate(DTPolygon poly, Vector2 t)
 {
     return(new DTPolygon(
                poly.Contour.Select(v => { return v + t; }).ToList(),
                poly.Holes.Select(hole => {
         return hole.Select(v => { return v + t; }).ToList();
     }).ToList()));
 }
Ejemplo n.º 7
0
        public static void DO_Subtraction(IPolygonSubtractor sub, DO_Tri_Tri dtObject, float x, float y)
        {
            DTPolygon box = new DTPolygon(square.Contour, L(smallSquare.Contour));

            dtObject.transform.position = new Vector3(x, y, 0);
            dtObject.ApplyPolygonList(L(box));

            Explosion explosion = new Explosion(x + 1, y + 1, 0.2f, 8);

            IterEE.ExecuteExplosions(L(explosion), L(dtObject), sub);
        }
    public static T CreateRingObject <T> (bool hasHole = true, float radius = 1.0f,
                                          int numEdges = 24) where T : DestructibleObject
    {
        float variationAmplitude = 0.0f * radius;
        float angleStep          = 2 * Mathf.PI / numEdges;

        List <Vector2> exterior = new List <Vector2>();
        List <Vector2> hole     = new List <Vector2>();

        for (int i = 0; i < numEdges; ++i)
        {
            float   rOuter   = UnityEngine.Random.Range(radius - variationAmplitude, radius + variationAmplitude);
            float   rInner   = UnityEngine.Random.Range(radius - variationAmplitude, radius + variationAmplitude) * 0.5f;
            Vector2 dirOuter = new Vector2(Mathf.Cos(i * angleStep), Mathf.Sin(i * angleStep));
            Vector2 dirInner = new Vector2(dirOuter.x, -dirOuter.y);

            // CW exterior
            exterior.Add(dirOuter * rOuter);

            // CCW hole
            if (hasHole)
            {
                hole.Add(dirInner * rInner);
            }
        }

        DTPolygon polygon;

        if (hasHole)
        {
            polygon = new DTPolygon(exterior, new List <List <Vector2> >()
            {
                hole
            });
        }
        else
        {
            polygon = new DTPolygon(exterior);
        }

        GameObject go = new GameObject();
        T          destructibleObject = go.AddComponent <T>();

        destructibleObject.ApplyPolygonList(new List <DTPolygon> {
            polygon
        });

        return(destructibleObject);
    }
Ejemplo n.º 9
0
        public static void ConvexBasic(IPolygonSubtractor sub)
        {
            // Basic corner clips (produces an 'L' shape)
            DTPolygon clip0 = Translate(square, V(-1, -1));                        // bottom left
            DTPolygon clip1 = Translate(square, V(1, -1));                         // bottom right
            DTPolygon clip2 = Translate(square, V(1, 1));                          // top right
            DTPolygon clip3 = Translate(square, V(-1, 1));                         // top left
            // Basic edge clips (produces a 'C' shape)
            DTPolygon clip4 = Translate(narrowRect, V(0, -1));                     // bottom
            DTPolygon clip5 = Translate(shortRect, V(1, 0));                       // right
            DTPolygon clip6 = Translate(narrowRect, V(0, 1));                      // top
            DTPolygon clip7 = Translate(shortRect, V(-1, 0));                      // left
            // Diamond clip (produces 4 triangles)
            DTPolygon clip8 = P(V(0, -1.5f), V(1.5f, 0), V(0, 1.5f), V(-1.5f, 0)); // start with bottom vertex

            // Basic corner clips (produces an 'L' shape)
            List <DTPolygon> expected0 = L(P(V(0, 0), V(0, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0)));
            List <DTPolygon> expected1 = L(P(V(-1, -1), V(0, -1), V(0, 0), V(1, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected2 = L(P(V(-1, -1), V(1, -1), V(1, 0), V(0, 0), V(0, 1), V(-1, 1)));
            List <DTPolygon> expected3 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0, 1), V(0, 0), V(-1, 0)));
            // Basic edge clips (produces a 'C' shape)
            List <DTPolygon> expected4 = L(P(V(-1, -1), V(-0.5f, -1), V(-0.5f, 0), V(0.5f, 0), V(0.5f, -1), V(1, -1), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected5 = L(P(V(-1, -1), V(1, -1), V(1, -0.5f), V(0, -0.5f), V(0, 0.5f), V(1, 0.5f), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected6 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0.5f, 1), V(0.5f, 0), V(-0.5f, 0), V(-0.5f, 1), V(-1, 1)));
            List <DTPolygon> expected7 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0.5f), V(0, 0.5f), V(0, -0.5f), V(-1, -0.5f)));
            // Diamond clip (produces 4 triangles)
            List <DTPolygon> expected8 = L(
                P(V(-1, -0.5f), V(-1, -1), V(-0.5f, -1)),
                P(V(0.5f, -1), V(1, -1), V(1, -0.5f)),
                P(V(1, 0.5f), V(1, 1), V(0.5f, 1)),
                P(V(-0.5f, 1), V(-1, 1), V(-1, 0.5f))
                );

            // Complete removal
            List <DTPolygon> empty = new List <DTPolygon>();

            VerifyPolygons(sub.Subtract(square, clip0), expected0);
            VerifyPolygons(sub.Subtract(square, clip1), expected1);
            VerifyPolygons(sub.Subtract(square, clip2), expected2);
            VerifyPolygons(sub.Subtract(square, clip3), expected3);
            VerifyPolygons(sub.Subtract(square, clip4), expected4);
            VerifyPolygons(sub.Subtract(square, clip5), expected5);
            VerifyPolygons(sub.Subtract(square, clip6), expected6);
            VerifyPolygons(sub.Subtract(square, clip7), expected7);
            VerifyPolygons(sub.Subtract(square, clip8), expected8);

            // Complete removal
            VerifyPolygons(sub.Subtract(smallSquare, square), empty);
        }
Ejemplo n.º 10
0
    public Explosion(float x, float y, float radius, int numPoints)
    {
        Position = new Vector2(x, y);
        Radius   = radius;

        List <Vector2> circle = new List <Vector2>();
        float          step   = 2 * Mathf.PI / numPoints;

        for (int i = 0; i < numPoints; ++i)
        {
            float angle = i * step;
            circle.Add(new Vector2(x + radius * Mathf.Cos(angle), y + radius * Mathf.Sin(angle)));
        }

        DTPolygon = new DTPolygon(circle);
    }
Ejemplo n.º 11
0
        protected void ApplyCollider(DTPolygon dtPolygon)
        {
            PolygonCollider2D polygonCollider = GetComponent <PolygonCollider2D>();

            polygonCollider.pathCount = 1 + dtPolygon.Holes.Count;
            polygonCollider.SetPath(0, dtPolygon.Contour);
            for (int i = 0; i < dtPolygon.Holes.Count; i++)
            {
                polygonCollider.SetPath(i + 1, dtPolygon.Holes[i]);
            }

            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);
        }
Ejemplo n.º 13
0
        public DTConvexPolygroup PolygonToTriangleList(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 DTConvexPolygroup());
            }
            // Don't triangulate if this is already a triangle
            else if (subject.Contour.Count == 3 && subject.Holes.Count == 0)
            {
                return(new DTConvexPolygroup(new List <DTPolygon>()
                {
                    subject
                }));
            }

            // 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 poly group
            return(new DTConvexPolygroup(triangleNetOutput.Triangles.Select(t => t.ToVertexList()).ToList()));
        }
Ejemplo n.º 14
0
 public DTMesh PolygonToMesh(DTPolygon subject)
 {
     return(PolygonToTriangleList(subject).ToMesh());
 }
Ejemplo n.º 15
0
 public DTConvexPolygroup PolygonToTriangleList(DTPolygon subject)
 {
     Triangulate_EC(subject.ToTPPLPolyList(), out TPPLPolyList triangles);
     return(triangles.ToPolygroup());
 }
Ejemplo n.º 16
0
        public static void ConvexCasesProducingHoles(IPolygonSubtractor sub)
        {
            // Diamond hole in center
            DTPolygon clip0 = smallDiamond;
            // Diamond holes touching edge
            DTPolygon clip1 = Translate(smallDiamond, V(0, -0.5f)); // bottom
            DTPolygon clip2 = Translate(smallDiamond, V(0.5f, 0));  // right
            DTPolygon clip3 = Translate(smallDiamond, V(0, 0.5f));  // top
            DTPolygon clip4 = Translate(smallDiamond, V(-0.5f, 0)); // left
            // Exact diamond clip (produces 4 triangles)
            DTPolygon clip5 = diamond;

            // Diamond hole in center
            List <DTPolygon> expected0 = L(new DTPolygon(
                                               square.Contour,
                                               L(smallDiamond.Contour.AsEnumerable().Reverse().ToList())
                                               ));
            // Diamond holes touching edge
            List <DTPolygon> expected1     = L(P(V(-1, -1), V(0, -1), V(-0.5f, -0.5f), V(0, 0), V(0.5f, -0.5f), V(0, -1), V(1, -1), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected1Hole = L(new DTPolygon(
                                                   square.Contour,
                                                   L(clip1.Contour.AsEnumerable().Reverse().ToList())
                                                   ));
            List <DTPolygon> expected2     = L(P(V(-1, -1), V(1, -1), V(1, 0), V(0.5f, -0.5f), V(0, 0), V(0.5f, 0.5f), V(1, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected2Hole = L(new DTPolygon(
                                                   square.Contour,
                                                   L(clip2.Contour.AsEnumerable().Reverse().ToList())
                                                   ));
            List <DTPolygon> expected3     = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0, 1), V(0.5f, 0.5f), V(0, 0), V(-0.5f, 0.5f), V(0, 1), V(-1, 1)));
            List <DTPolygon> expected3Hole = L(new DTPolygon(
                                                   square.Contour,
                                                   L(clip3.Contour.AsEnumerable().Reverse().ToList())
                                                   ));
            List <DTPolygon> expected4     = L(P(V(-1, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0), V(-0.5f, 0.5f), V(0, 0), V(-0.5f, -0.5f), V(-1, 0)));
            List <DTPolygon> expected4Hole = L(new DTPolygon(
                                                   square.Contour,
                                                   L(clip4.Contour.AsEnumerable().Reverse().ToList())
                                                   ));
            // Exact diamond clip (produces 4 triangles)
            List <DTPolygon> expected5 = L(
                P(V(-1, 0), V(-1, -1), V(0, -1)),
                P(V(0, -1), V(1, -1), V(1, 0)),
                P(V(1, 0), V(1, 1), V(0, 1)),
                P(V(0, 1), V(-1, 1), V(-1, 0))
                );
            List <DTPolygon> expected5Hole = L(new DTPolygon(
                                                   square.Contour,
                                                   L(clip5.Contour.AsEnumerable().Reverse().ToList())
                                                   ));
            List <DTPolygon> expected5Single0 = L(P(V(-1, -1), V(0, -1), V(-1, 0), V(0, 1), V(1, 0), V(0, -1), V(1, -1), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected5Single1 = L(P(V(-1, -1), V(1, -1), V(1, 0), V(0, -1), V(-1, 0), V(0, 1), V(1, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected5Single2 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0, 1), V(1, 0), V(0, -1), V(-1, 0), V(0, 1), V(-1, 1)));
            List <DTPolygon> expected5Single3 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0), V(0, 1), V(1, 0), V(0, -1), V(-1, 0)));

            VerifyPolygons(sub.Subtract(square, clip0), expected0);
            VerifyPolygons(sub.Subtract(square, clip1), expected1, expected1Hole);
            VerifyPolygons(sub.Subtract(square, clip2), expected2, expected2Hole);
            VerifyPolygons(sub.Subtract(square, clip3), expected3, expected3Hole);
            VerifyPolygons(sub.Subtract(square, clip4), expected4, expected4Hole);
            VerifyPolygons(sub.Subtract(square, clip5), expected5, expected5Hole, expected5Single0, expected5Single1, expected5Single2, expected5Single3);
        }
Ejemplo n.º 17
0
        public static void ConvexDegenerateNoIntersection(IPolygonSubtractor sub)
        {
            // Half-overlapping edges
            DTPolygon clip0 = Translate(diamond, V(0.5f, -1.5f));          // bottom right edge shared, Q shifted down-left
            DTPolygon clip1 = Translate(diamond, V(1.5f, -0.5f));          // bottom right edge shared, Q shifted up-right
            DTPolygon clip2 = Translate(diamond, V(1.5f, 0.5f));           // top right edge shared, Q shifted down-right
            DTPolygon clip3 = Translate(diamond, V(0.5f, 1.5f));           // top right edge shared, Q shifted up-left
            DTPolygon clip4 = Translate(diamond, V(-0.5f, 1.5f));          // top left edge shared, Q shifted up-right
            DTPolygon clip5 = Translate(diamond, V(-1.5f, 0.5f));          // top left edge shared, Q shifted down-left
            DTPolygon clip6 = Translate(diamond, V(-1.5f, -0.5f));         // bottom left edge shared, Q shifted up-left
            DTPolygon clip7 = Translate(diamond, V(-0.5f, -1.5f));         // bottom left edge shared, Q shifted down-right
            // P edge completely inside Q edge
            DTPolygon clip8  = Translate(diamond, V(0.75f, -0.75f));       // bottom right edge inside Q edge
            DTPolygon clip9  = Translate(diamond, V(0.75f, 0.75f));        // top right edge inside Q edge
            DTPolygon clip10 = Translate(diamond, V(-0.75f, 0.75f));       // top left edge inside Q edge
            DTPolygon clip11 = Translate(diamond, V(-0.75f, -0.75f));      // bottom left edge inside Q edge
            // P edge completely contains Q edge
            DTPolygon clip12 = Translate(smallDiamond, V(0.75f, -0.75f));  // bottom right edge contains Q edge
            DTPolygon clip13 = Translate(smallDiamond, V(0.75f, 0.75f));   // top right edge contains Q edge
            DTPolygon clip14 = Translate(smallDiamond, V(-0.75f, 0.75f));  // top left edge contains Q edge
            DTPolygon clip15 = Translate(smallDiamond, V(-0.75f, -0.75f)); // bottom left edge contains Q edge
            // P edge and Q edge are the same
            DTPolygon clip16 = Translate(diamond, V(1, -1));               // bottom right edge same
            DTPolygon clip17 = Translate(diamond, V(1, 1));                // top right edge same
            DTPolygon clip18 = Translate(diamond, V(-1, 1));               // top left edge same
            DTPolygon clip19 = Translate(diamond, V(-1, -1));              // bottom left edge same
            // Single shared vertex (octagon)
            DTPolygon clip20 = Translate(octagon, V(-2, -2));              // octagon, bottom left vertex same
            DTPolygon clip21 = Translate(octagon, V(2, -2));               // octagon, bottom right vertex same
            DTPolygon clip22 = Translate(octagon, V(2, 2));                // octagon, top left vertex same
            DTPolygon clip23 = Translate(octagon, V(-2, 2));               // octagon, top right vertex same
            // Single shared vertex (diamond)
            DTPolygon clip24 = Translate(diamond, V(-1, -2));              // diamond top, square bottom left vertex same
            DTPolygon clip25 = Translate(diamond, V(1, -2));               // diamond top, square bottom right vertex same
            DTPolygon clip26 = Translate(diamond, V(-1, 2));               // diamond bottom, square top left vertex same
            DTPolygon clip27 = Translate(diamond, V(1, 2));                // diamond bottom, square top right vertex same
            // Q single vertex inside P edge
            DTPolygon clip28 = Translate(square, V(1.5f, -1.5f));          // bottom right edge contains Q vertex
            DTPolygon clip29 = Translate(square, V(1.5f, 1.5f));           // top right edge contains Q vertex
            DTPolygon clip30 = Translate(square, V(-1.5f, 1.5f));          // top left edge contains Q vertex
            DTPolygon clip31 = Translate(square, V(-1.5f, -1.5f));         // bottom left edge contains Q vertex
            // P single vertex inside Q edge
            DTPolygon clip32 = Translate(diamond, V(-1.5f, -1.5f));        // bottom left vertex in Q edge
            DTPolygon clip33 = Translate(diamond, V(1.5f, -1.5f));         // bottom right vertex in Q edge
            DTPolygon clip34 = Translate(diamond, V(1.5f, 1.5f));          // top right vertex in Q edge
            DTPolygon clip35 = Translate(diamond, V(-1.5f, 1.5f));         // top left vertex in Q edge

            List <DTPolygon> expectedSquare       = L(square);
            List <DTPolygon> expectedDiamond      = L(diamond);
            List <DTPolygon> expectedSmallDiamond = L(smallDiamond);
            List <DTPolygon> expectedOctagon      = L(octagon);

            VerifyPolygons(sub.Subtract(diamond, clip0), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip1), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip2), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip3), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip4), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip5), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip6), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip7), expectedDiamond);
            VerifyPolygons(sub.Subtract(smallDiamond, clip8), expectedSmallDiamond);
            VerifyPolygons(sub.Subtract(smallDiamond, clip9), expectedSmallDiamond);
            VerifyPolygons(sub.Subtract(smallDiamond, clip10), expectedSmallDiamond);
            VerifyPolygons(sub.Subtract(smallDiamond, clip11), expectedSmallDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip12), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip13), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip14), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip15), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip16), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip17), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip18), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip19), expectedDiamond);
            VerifyPolygons(sub.Subtract(octagon, clip20), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip21), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip22), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip23), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip24), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip25), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip26), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip27), expectedOctagon);
            VerifyPolygons(sub.Subtract(diamond, clip28), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip29), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip30), expectedDiamond);
            VerifyPolygons(sub.Subtract(diamond, clip31), expectedDiamond);
            VerifyPolygons(sub.Subtract(octagon, clip32), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip33), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip34), expectedOctagon);
            VerifyPolygons(sub.Subtract(octagon, clip35), expectedOctagon);
        }
Ejemplo n.º 18
0
        public static void ConvexDegenerateIntersection(IPolygonSubtractor sub)
        {
            // Shared corners (produces an 'L' shape)
            DTPolygon clip0 = Translate(smallSquare, V(-0.5f, -0.5f)); // bottom left
            DTPolygon clip1 = Translate(smallSquare, V(0.5f, -0.5f));  // bottom right
            DTPolygon clip2 = Translate(smallSquare, V(0.5f, 0.5f));   // top right
            DTPolygon clip3 = Translate(smallSquare, V(-0.5f, 0.5f));  // top left
            // Q edge inside P edge (produces a 'C' shape)
            DTPolygon clip4 = Translate(smallSquare, V(0, -0.5f));     // bottom
            DTPolygon clip5 = Translate(smallSquare, V(0.5f, 0));      // right
            DTPolygon clip6 = Translate(smallSquare, V(0, 0.5f));      // top
            DTPolygon clip7 = Translate(smallSquare, V(-0.5f, 0));     // left
            // Half same
            DTPolygon clip8  = Translate(shortRect, V(0, -0.5f));      // bottom half
            DTPolygon clip9  = Translate(narrowRect, V(0.5f, 0));      // right half
            DTPolygon clip10 = Translate(shortRect, V(0, 0.5f));       // top half
            DTPolygon clip11 = Translate(narrowRect, V(-0.5f, 0));     // left half
            // Diamond on corners
            DTPolygon clip12 = Translate(diamond, V(-1, -1));          // bottom left
            DTPolygon clip13 = Translate(diamond, V(1, -1));           // bottom right
            DTPolygon clip14 = Translate(diamond, V(1, 1));            // top right
            DTPolygon clip15 = Translate(diamond, V(-1, 1));           // top left
            // Diamond on edges
            DTPolygon clip16 = Translate(diamond, V(0, -1));           // bottom
            DTPolygon clip17 = Translate(diamond, V(1, 0));            // right
            DTPolygon clip18 = Translate(diamond, V(0, 1));            // top
            DTPolygon clip19 = Translate(diamond, V(-1, 0));           // left

            // Basic corner clips (produces an 'L' shape)
            List <DTPolygon> expected0 = L(P(V(0, 0), V(0, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0)));
            List <DTPolygon> expected1 = L(P(V(-1, -1), V(0, -1), V(0, 0), V(1, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected2 = L(P(V(-1, -1), V(1, -1), V(1, 0), V(0, 0), V(0, 1), V(-1, 1)));
            List <DTPolygon> expected3 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0, 1), V(0, 0), V(-1, 0)));
            // Basic edge clips (produces a 'C' shape)
            List <DTPolygon> expected4 = L(P(V(-1, -1), V(-0.5f, -1), V(-0.5f, 0), V(0.5f, 0), V(0.5f, -1), V(1, -1), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected5 = L(P(V(-1, -1), V(1, -1), V(1, -0.5f), V(0, -0.5f), V(0, 0.5f), V(1, 0.5f), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected6 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0.5f, 1), V(0.5f, 0), V(-0.5f, 0), V(-0.5f, 1), V(-1, 1)));
            List <DTPolygon> expected7 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0.5f), V(0, 0.5f), V(0, -0.5f), V(-1, -0.5f)));
            // Half same
            List <DTPolygon> expected8  = L(P(V(-1, 0), V(1, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected9  = L(P(V(-1, -1), V(0, -1), V(0, 1), V(-1, 1)));
            List <DTPolygon> expected10 = L(P(V(-1, -1), V(1, -1), V(1, 0), V(-1, 0)));
            List <DTPolygon> expected11 = L(P(V(0, -1), V(1, -1), V(1, 1), V(0, 1)));
            // Diamond on corners
            List <DTPolygon> expected12 = L(P(V(0, -1), V(1, -1), V(1, 1), V(-1, 1), V(-1, 0)));
            List <DTPolygon> expected13 = L(P(V(-1, -1), V(0, -1), V(1, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected14 = L(P(V(-1, -1), V(1, -1), V(1, 0), V(0, 1), V(-1, 1)));
            List <DTPolygon> expected15 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0, 1), V(-1, 0)));
            // Diamond on edges
            List <DTPolygon> expected16 = L(P(V(-1, -1), V(0, 0), V(1, -1), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected17 = L(P(V(-1, -1), V(1, -1), V(0, 0), V(1, 1), V(-1, 1)));
            List <DTPolygon> expected18 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(0, 0), V(-1, 1)));
            List <DTPolygon> expected19 = L(P(V(-1, -1), V(1, -1), V(1, 1), V(-1, 1), V(0, 0)));

            // Complete removal
            List <DTPolygon> empty = new List <DTPolygon>();

            // Complete removal
            VerifyPolygons(sub.Subtract(square, square), empty);

            VerifyPolygons(sub.Subtract(square, clip0), expected0);
            VerifyPolygons(sub.Subtract(square, clip1), expected1);
            VerifyPolygons(sub.Subtract(square, clip2), expected2);
            VerifyPolygons(sub.Subtract(square, clip3), expected3);
            VerifyPolygons(sub.Subtract(square, clip4), expected4);
            VerifyPolygons(sub.Subtract(square, clip5), expected5);
            VerifyPolygons(sub.Subtract(square, clip6), expected6);
            VerifyPolygons(sub.Subtract(square, clip7), expected7);
            VerifyPolygons(sub.Subtract(square, clip8), expected8);
            VerifyPolygons(sub.Subtract(square, clip9), expected9);
            VerifyPolygons(sub.Subtract(square, clip10), expected10);
            VerifyPolygons(sub.Subtract(square, clip11), expected11);
            VerifyPolygons(sub.Subtract(square, clip12), expected12);
            VerifyPolygons(sub.Subtract(square, clip13), expected13);
            VerifyPolygons(sub.Subtract(square, clip14), expected14);
            VerifyPolygons(sub.Subtract(square, clip15), expected15);
            VerifyPolygons(sub.Subtract(square, clip16), expected16);
            VerifyPolygons(sub.Subtract(square, clip17), expected17);
            VerifyPolygons(sub.Subtract(square, clip18), expected18);
            VerifyPolygons(sub.Subtract(square, clip19), expected19);
        }
    public static DTPolygon IdentifyHoles(this DTPolygon inPoly)
    {
        DTProfilerMarkers.IdentifyHoles.Begin();

        List <Vector2>         workingContour = new List <Vector2>(inPoly.Contour);
        List <List <Vector2> > loops          = new List <List <Vector2> >();

        // Repeat until all loops are found
        while (workingContour.Count > 0)
        {
            // Simplify contour to remove edges that overlap the previous edge
            workingContour = workingContour.Simplify();
            if (workingContour == null)
            {
                break;
            }
            Dictionary <Vector2, int> vertices = new Dictionary <Vector2, int>(new ApproximateVector2Comparer());
            for (int i = 0; i < workingContour.Count; ++i)
            {
                Vector2 v = workingContour[i];

                // If this is a repeated vertex, we've found a loop
                if (vertices.ContainsKey(v))
                {
                    // Separate this loop from the working contour
                    int start = vertices[v];
                    int count = i - start;
                    loops.Add(workingContour.GetRange(start, count));
                    workingContour.RemoveRange(start, count);
                    vertices[v] = i;
                    // Stop so that we can simplify the polygon and start from the beginning to find the next loop
                    break;
                }

                vertices[v] = i;

                // Add the final remaining loop
                if (vertices.Count == workingContour.Count)
                {
                    if (loops.Count == 0)
                    {
                        // If there were no other loops, then the contour does not contain unidentified holes
                        DTProfilerMarkers.IdentifyHoles.End();
                        return(inPoly);
                    }

                    loops.Add(workingContour);
                    workingContour = new List <Vector2>();
                }
            }
        }

        // Start with holes already in the original polygon
        DTPolygon outPoly = new DTPolygon();

        foreach (var hole in inPoly.Holes)
        {
            outPoly.Holes.Add(hole);
        }

        // We now have a list of loops. Check which ones are inside the others, and mark those as holes as well.
        for (int i = 0; i < loops.Count; ++i)
        {
            if (loops[i] == null)
            {
                continue;
            }
            for (int j = i + 1; j < loops.Count; ++j)
            {
                if (loops[j] == null)
                {
                    continue;
                }
                if (QuickPolyInPoly(loops[i], loops[j]))
                {
                    loops[i].SetCW();
                    outPoly.Holes.Add(loops[i]);
                    loops[i] = null;
                    break;
                }
                else if (QuickPolyInPoly(loops[j], loops[i]))
                {
                    loops[j].SetCW();
                    outPoly.Holes.Add(loops[j]);
                    loops[j] = null;
                    break;
                }
            }
        }

        // Join any remaining loops and make the result the contour of the new polygon
        for (int i = 1; i < loops.Count; ++i)
        {
            if (loops[i] != null)
            {
                loops[i].SetCCW();
                outPoly.Contour = JoinContours(outPoly.Contour, loops[i]);
            }
        }

        DTProfilerMarkers.IdentifyHoles.End();
        return(outPoly);
    }
 // Returns true if the contour is convex and there are no holes. Flat angles are allowed.
 public static bool IsConvex(this DTPolygon poly)
 {
     return(poly.Holes.Count == 0 && poly.Contour.IsConvex());
 }
 public List <DTPolygon> Subtract(DTPolygon subject, DTPolygon clippingPolygon)
 {
     SubtractInternal(subject.Contour, clippingPolygon.Contour, out List <DTPolygon> outputPolygons);
     return(outputPolygons);
 }
        // Returns true if the subject polygon was modified at all
        private bool SubtractInternal(List <Vector2> subject, List <Vector2> clippingPolygon, out List <DTPolygon> outputPolygons)
        {
            if (!DTUtility.BoundsCheck(subject, clippingPolygon))
            {
                // There is no overlap at all, so output a copy of the subject polygon
                outputPolygons = new List <DTPolygon>()
                {
                    new DTPolygon(new List <Vector2>(subject))
                };
                return(false);
            }

            polyP = subject;
            polyQ = clippingPolygon;

            pIndex = 0;
            qIndex = 0;

            // The first entry intersection point of the first output polgon. If we return to this point, break the loop
            bool firstIntersectionFound  = false;
            int? firstIntersectionPIndex = null;
            int? firstIntersectionQIndex = null;

            // List of disjoint output polygons after subtraction
            outputPolygons = new List <DTPolygon>();

            // Working output polygon vertices
            polygonBegin = null;
            List <Vector2> pVertices = new List <Vector2>();
            List <Vector2> qVertices = new List <Vector2>();

            for (int i = 0; i <= 2 * (polyP.Count + polyQ.Count); ++i)
            {
                if (polygonBegin.HasValue)
                {
                    Vector2?exitIntersection = ExitIntersection();
                    if (exitIntersection.HasValue)
                    {
                        // Exit intersection point for output polygon: construct output polygon
                        DTPolygon poly = new DTPolygon();
                        poly.Contour.Add(polygonBegin.Value);
                        poly.Contour.AddRange(pVertices);
                        poly.Contour.Add(exitIntersection.Value);
                        poly.Contour.AddRange(qVertices.AsEnumerable().Reverse());

                        // Simplify polygon
                        poly = poly.Simplify();
                        if (poly != null)
                        {
                            outputPolygons.Add(poly);
                        }

                        // Clear working polygon vertices
                        polygonBegin = null;
                        pVertices.Clear();
                        qVertices.Clear();
                    }
                }
                else
                {
                    Vector2?entranceIntersection = EntranceIntersection();
                    if (entranceIntersection.HasValue)
                    {
                        // Loop exit condition: revisiting first intersection
                        if (firstIntersectionFound &&
                            ModP(pIndex) == ModP(firstIntersectionPIndex.Value) &&
                            ModQ(qIndex) == ModQ(firstIntersectionQIndex.Value))
                        {
                            break;
                        }

                        // Entry intersection point for output polygon
                        polygonBegin = entranceIntersection.Value;
                        pVertices.Clear();
                        qVertices.Clear();

                        // Keep track of this point if it is the entry intersection for the 1st output polygon
                        if (!firstIntersectionFound)
                        {
                            firstIntersectionFound  = true;
                            firstIntersectionPIndex = pIndex;
                            firstIntersectionQIndex = qIndex;
                        }
                    }
                }

                void advanceP()
                {
                    if (polygonBegin.HasValue)
                    {
                        pVertices.Add(P);
                    }
                    ++pIndex;
                }

                void advanceQ()
                {
                    if (polygonBegin.HasValue)
                    {
                        qVertices.Add(Q);
                    }
                    ++qIndex;
                }

                float pSide = (P - QPrev).Cross(QEdge);
                float qSide = (Q - PPrev).Cross(PEdge);
                float cross = QEdge.Cross(PEdge);

                if (cross <= 0)
                {
                    // QEdge heading inward

                    if (qSide < 0)
                    {
                        // Q inside P's half-plane, heading away from PEdge
                        advanceP();
                    }
                    else
                    {
                        // Q outside P's half-plane or on P's line, heading toward PEdge
                        advanceQ();
                    }
                }
                else
                {
                    // QEdge heading outward

                    if (pSide < 0)
                    {
                        // P inside Q's half-plane, heading away from QEdge
                        advanceQ();
                    }
                    else
                    {
                        // P outside Q's half-plane or on Q's line, heading toward QEdge
                        advanceP();
                    }
                }
            }

            // There were no intersections, so either one poly is entirely contained within the other, or there is no overlap at all
            if (outputPolygons.Count == 0)
            {
                if (polyP.Inside(polyQ))
                {
                    // P is entirely within Q, so do nothing. The entire polygon has been subtracted
                    return(true);
                }
                else if (polyQ.Inside(polyP))
                {
                    // Q is entirely within P, so output a copy of P, with Q (reversed) set as a hole
                    outputPolygons.Add(new DTPolygon(
                                           new List <Vector2>(polyP),
                                           new List <List <Vector2> >()
                    {
                        polyQ.AsEnumerable().Reverse().ToList()
                    }));
                    return(true);
                }
                else
                {
                    if (polyP.Simplify() == polyQ.Simplify())
                    {
                        // The polygons are equal, so do nothing. The entire polygon has been subtracted
                        return(true);
                    }
                    else
                    {
                        // There is no overlap at all, so output a copy of P
                        outputPolygons.Add(new DTPolygon(new List <Vector2>(polyP)));
                        return(false);
                    }
                }
            }

            return(true);
        }