Exemple #1
0
        // Triangulates a list of polygons that may contain holes by ear clipping algorithm
        // first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
        // time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
        // space complexity: O(n)
        // params:
        //    inpolys : a list of polygons to be triangulated (can contain holes)
        //              vertices of all non-hole polys have to be in counter-clockwise order
        //              vertices of all hole polys have to be in clockwise order
        //    triangles : a list of triangles (result)
        // Returns true on success, false on failure
        private static bool Triangulate_EC(TPPLPolyList inpolys, out TPPLPolyList triangles)
        {
            triangles = new TPPLPolyList();

            if (!RemoveHoles(inpolys, out TPPLPolyList outpolys))
            {
                return(false);
            }
            foreach (var poly in outpolys)
            {
                if (!Triangulate_EC(poly, out triangles))
                {
                    return(false);
                }
            }
            return(true);
        }
Exemple #2
0
        // Converts a polygon triangulation to a decomposition of fewer convex partitions by removing
        // some internal edges with the Hertel-Mehlhorn algorithm.
        // The algorithm gives at most four times the number of parts as the optimal algorithm,
        // though in practice it works much better than that and often gives optimal partition.
        // time complexity O(n^2), n is the number of vertices
        // space complexity: O(n)
        // params:
        //    triangles : a triangulation of a polygon
        //           vertices have to be in counter-clockwise order
        //    parts : resulting list of convex polygons
        // Returns true on success, false on failure
        private static bool HertelMehlhorn(TPPLPolyList triangles, out TPPLPolyList parts)
        {
            int     i11;
            int     i12;
            int     i13;
            int     i21 = 0;
            int     i22 = 0;
            int     i23;
            Vector2 d1, d2, p1, p2, p3;
            bool    isdiagonal;

            for (int iter1 = 0; iter1 < triangles.Count; iter1++)
            {
                TPPLPoly poly1 = triangles[iter1];
                for (i11 = 0; i11 < poly1.NumPoints; i11++)
                {
                    d1  = poly1.GetPoint(i11);
                    i12 = (i11 + 1) % poly1.NumPoints;
                    d2  = poly1.GetPoint(i12);
                    TPPLPoly poly2 = null;

                    isdiagonal = false;
                    int iter2;
                    for (iter2 = iter1 + 1; iter2 < triangles.Count; iter2++)
                    {
                        poly2 = triangles[iter2];

                        for (i21 = 0; i21 < poly2.NumPoints; i21++)
                        {
                            if ((d2.x != poly2.GetPoint(i21).x) || (d2.y != poly2.GetPoint(i21).y))
                            {
                                continue;
                            }
                            i22 = (i21 + 1) % poly2.NumPoints;
                            if ((d1.x != poly2.GetPoint(i22).x) || (d1.y != poly2.GetPoint(i22).y))
                            {
                                continue;
                            }
                            isdiagonal = true;
                            break;
                        }
                        if (isdiagonal)
                        {
                            break;
                        }
                    }

                    if (!isdiagonal)
                    {
                        continue;
                    }

                    p2 = poly1.GetPoint(i11);
                    if (i11 == 0)
                    {
                        i13 = poly1.NumPoints - 1;
                    }
                    else
                    {
                        i13 = i11 - 1;
                    }
                    p1 = poly1.GetPoint(i13);
                    if (i22 == (poly2.NumPoints - 1))
                    {
                        i23 = 0;
                    }
                    else
                    {
                        i23 = i22 + 1;
                    }
                    p3 = poly2.GetPoint(i23);

                    if (!IsConvex(p1, p2, p3))
                    {
                        continue;
                    }

                    p2 = poly1.GetPoint(i12);
                    if (i12 == (poly1.NumPoints - 1))
                    {
                        i13 = 0;
                    }
                    else
                    {
                        i13 = i12 + 1;
                    }
                    p3 = poly1.GetPoint(i13);
                    if (i21 == 0)
                    {
                        i23 = poly2.NumPoints - 1;
                    }
                    else
                    {
                        i23 = i21 - 1;
                    }
                    p1 = poly2.GetPoint(i23);

                    if (!IsConvex(p1, p2, p3))
                    {
                        continue;
                    }

                    TPPLPoly newpoly = new TPPLPoly(poly1.NumPoints + poly2.NumPoints - 2);
                    int      k       = 0;
                    for (int j = i12; j != i11; j = (j + 1) % poly1.NumPoints)
                    {
                        newpoly[k] = poly1.GetPoint(j);
                        k++;
                    }
                    for (int j = i22; j != i21; j = (j + 1) % poly2.NumPoints)
                    {
                        newpoly[k] = poly2.GetPoint(j);
                        k++;
                    }

                    triangles.RemoveAt(iter2);
                    if (iter1 > iter2)
                    {
                        iter1--;
                    }
                    triangles[iter1] = newpoly;
                    poly1            = newpoly;
                    i11 = -1;

                    continue;
                }
            }

            parts = triangles;
            return(true);
        }
Exemple #3
0
        // Simple heuristic procedure for removing holes from a list of polygons
        // works by creating a diagonal from the rightmost hole vertex to some visible vertex
        // time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
        // space complexity: O(n)
        // params:
        //    inpolys : a list of polygons that can contain holes
        //              vertices of all non-hole polys have to be in counter-clockwise order
        //              vertices of all hole polys have to be in clockwise order
        //    outpolys : a list of polygons without holes
        // Returns true on success, false on failure
        private static bool RemoveHoles(TPPLPolyList inpolys, out TPPLPolyList outpolys)
        {
            TPPLPolyList polys = new TPPLPolyList(inpolys);

            // Check for trivial case (no holes)
            bool hasholes = false;

            foreach (var poly in inpolys)
            {
                if (poly.IsHole())
                {
                    hasholes = true;
                    break;
                }
            }
            if (!hasholes)
            {
                outpolys = new TPPLPolyList(inpolys);
                return(true);
            }

            while (true)
            {
                int holeIndex = 0;
                int polyIndex = 0;

                int holepointindex = 0;
                int polypointindex = 0;

                //find the hole point with the largest x
                hasholes = false;
                for (int index = 0; index < polys.Count; index++)
                {
                    var poly = polys[index];

                    if (!poly.IsHole())
                    {
                        continue;
                    }

                    if (!hasholes)
                    {
                        hasholes       = true;
                        holeIndex      = index;
                        holepointindex = 0;
                    }

                    for (int i = 0; i < poly.NumPoints; i++)
                    {
                        if (poly.GetPoint(i).x > polys[holeIndex].GetPoint(holepointindex).x)
                        {
                            holeIndex      = index;
                            holepointindex = i;
                        }
                    }
                }
                if (!hasholes)
                {
                    break;
                }
                Vector2 holepoint = polys[holeIndex].GetPoint(holepointindex);

                Vector2 bestpolypoint = new Vector2();
                bool    pointfound    = false;
                for (int index = 0; index < polys.Count; index++)
                {
                    var poly = polys[index];

                    if (poly.IsHole())
                    {
                        continue;
                    }
                    for (int i = 0; i < poly.NumPoints; i++)
                    {
                        if (poly.GetPoint(i).x <= holepoint.x)
                        {
                            continue;
                        }
                        if (!InCone(poly.GetPoint((i + poly.NumPoints - 1) % poly.NumPoints),
                                    poly.GetPoint(i),
                                    poly.GetPoint((i + 1) % poly.NumPoints),
                                    holepoint))
                        {
                            continue;
                        }
                        Vector2 polypoint = poly.GetPoint(i);
                        if (pointfound)
                        {
                            Vector2 v1 = Normalize(polypoint - holepoint);
                            Vector2 v2 = Normalize(bestpolypoint - holepoint);
                            if (v2.x > v1.x)
                            {
                                continue;
                            }
                        }
                        bool pointvisible = true;
                        foreach (var poly2 in polys)
                        {
                            if (poly2.IsHole())
                            {
                                continue;
                            }
                            for (int j = 0; j < poly2.NumPoints; j++)
                            {
                                Vector2 linep1 = poly2.GetPoint(j);
                                Vector2 linep2 = poly2.GetPoint((j + 1) % poly2.NumPoints);
                                if (Intersects(holepoint, polypoint, linep1, linep2))
                                {
                                    pointvisible = false;
                                    break;
                                }
                            }
                            if (!pointvisible)
                            {
                                break;
                            }
                        }
                        if (pointvisible)
                        {
                            pointfound     = true;
                            bestpolypoint  = polypoint;
                            polyIndex      = index;
                            polypointindex = i;
                        }
                    }
                }

                if (!pointfound)
                {
                    outpolys = null;
                    return(false);
                }

                TPPLPoly newpoly = new TPPLPoly(polys[holeIndex].NumPoints + polys[polyIndex].NumPoints + 2);
                int      i2      = 0;
                for (int i = 0; i <= polypointindex; i++)
                {
                    newpoly[i2] = polys[polyIndex].GetPoint(i);
                    i2++;
                }
                for (int i = 0; i <= polys[holeIndex].NumPoints; i++)
                {
                    newpoly[i2] = polys[holeIndex].GetPoint((i + holepointindex) % polys[holeIndex].NumPoints);
                    i2++;
                }
                for (int i = polypointindex; i < polys[polyIndex].NumPoints; i++)
                {
                    newpoly[i2] = polys[polyIndex].GetPoint(i);
                    i2++;
                }

                polys.RemoveAt(holeIndex);
                if (polyIndex > holeIndex)
                {
                    polyIndex--;
                }
                polys.RemoveAt(polyIndex);
                polys.Add(newpoly);
            }

            outpolys = polys;
            return(true);
        }
Exemple #4
0
        // Triangulates a polygon by ear clipping
        // time complexity O(n^2), n is the number of vertices
        // space complexity: O(n)
        // params:
        //    poly : an input polygon to be triangulated
        //           vertices have to be in counter-clockwise order
        //    triangles : a list of triangles (result)
        // returns true on success, false on failure
        private static bool Triangulate_EC(TPPLPoly poly, out TPPLPolyList triangles)
        {
            triangles = new TPPLPolyList();

            if (!poly.Valid())
            {
                return(false);
            }

            int numvertices = poly.NumPoints;

            if (numvertices < 3)
            {
                return(false);
            }
            if (numvertices == 3)
            {
                triangles.Add(poly);
                return(true);
            }

            PartitionVertex[] vertices = new PartitionVertex[numvertices];
            PartitionVertex   ear      = null;

            for (int i = 0; i < numvertices; i++)
            {
                vertices[i] = new PartitionVertex();
            }
            for (int i = 0; i < numvertices; i++)
            {
                vertices[i].isActive = true;
                vertices[i].p        = poly.GetPoint(i);
                if (i == (numvertices - 1))
                {
                    vertices[i].next = vertices[0];
                }
                else
                {
                    vertices[i].next = vertices[i + 1];
                }
                if (i == 0)
                {
                    vertices[i].previous = vertices[numvertices - 1];
                }
                else
                {
                    vertices[i].previous = vertices[i - 1];
                }
            }
            for (int i = 0; i < numvertices; i++)
            {
                UpdateVertex(vertices[i], vertices, numvertices);
            }

            for (int i = 0; i < numvertices - 3; i++)
            {
                bool earfound = false;
                //find the most extruded ear
                for (int j = 0; j < numvertices; j++)
                {
                    if (!vertices[j].isActive)
                    {
                        continue;
                    }
                    if (!vertices[j].isEar)
                    {
                        continue;
                    }
                    if (!earfound)
                    {
                        earfound = true;
                        ear      = vertices[j];
                    }
                    else
                    {
                        if (vertices[j].angle > ear.angle)
                        {
                            ear = vertices[j];
                        }
                    }
                }
                if (!earfound)
                {
                    return(false);
                }

                triangles.Add(new TPPLPoly(ear.previous.p, ear.p, ear.next.p));

                ear.isActive      = false;
                ear.previous.next = ear.next;
                ear.next.previous = ear.previous;

                if (i == numvertices - 4)
                {
                    break;
                }

                UpdateVertex(ear.previous, vertices, numvertices);
                UpdateVertex(ear.next, vertices, numvertices);
            }
            for (int i = 0; i < numvertices; i++)
            {
                if (vertices[i].isActive)
                {
                    triangles.Add(new TPPLPoly(vertices[i].previous.p, vertices[i].p, vertices[i].next.p));
                    break;
                }
            }

            return(true);
        }