示例#1
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);
        }
示例#2
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);
        }