예제 #1
0
        /// <summary>
        /// Decomposes a non-convex polygon into a number of convex polygons, up
        /// to maxPolys (remaining pieces are thrown out).
        /// Each resulting polygon will have no more than Box2D.Settings.MaxPolygonVertices
        /// vertices.
        /// Warning: Only works on simple polygons
        /// </summary>
        /// <param name="vertices">The vertices.</param>
        /// <param name="maxPolys">The maximum number of polygons.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <returns></returns>
        public static List <Vertices> ConvexPartition(Vertices vertices, int maxPolys, float tolerance)
        {
            if (vertices.Count < 3)
            {
                return new List <Vertices> {
                           vertices
                }
            }
            ;

            /*
             * if (vertices.IsConvex() && vertices.Count <= Box2D.Settings.MaxPolygonVertices)
             * {
             *  if (vertices.IsCounterClockWise())
             *  {
             *      Vertices tempP = new Vertices(vertices);
             *      tempP.Reverse();
             *      tempP = SimplifyTools.CollinearSimplify(tempP);
             *      tempP.ForceCounterClockWise();
             *      return new List<Vertices> { tempP };
             *  }
             *  vertices = SimplifyTools.CollinearSimplify(vertices);
             *  vertices.ForceCounterClockWise();
             *  return new List<Vertices> { vertices };
             * }
             */
            List <Triangle> triangulated;

            if (vertices.IsCounterClockWise())
            {
                Vertices tempP = new Vertices(vertices);

                tempP.Reverse();
                triangulated = TriangulatePolygon(tempP);
            }
            else
            {
                triangulated = TriangulatePolygon(vertices);
            }
            if (triangulated.Count < 1)
            {
                //Still no luck?  Oh well...
                throw new Exception("Can't triangulate your polygon.");
            }

            List <Vertices> polygonizedTriangles = PolygonizeTriangles(triangulated, maxPolys, tolerance);

            //The polygonized triangles are not guaranteed to be without collinear points. We remove
            //them to be sure.
            for (int i = 0; i < polygonizedTriangles.Count; i++)
            {
                polygonizedTriangles[i] = SimplifyTools.CollinearSimplify(polygonizedTriangles[i], 0);
            }

            //Remove empty vertice collections
            for (int i = polygonizedTriangles.Count - 1; i >= 0; i--)
            {
                if (polygonizedTriangles[i].Count == 0)
                {
                    polygonizedTriangles.RemoveAt(i);
                }
            }

            return(polygonizedTriangles);
        }
예제 #2
0
        /// <summary>
        /// Decompose the polygon into several smaller non-concave polygon.
        /// If the polygon is already convex, it will return the original polygon, unless it is over Box2D.Settings.MaxPolygonVertices.
        /// Precondition: Counter Clockwise polygon
        /// </summary>
        /// <param name="vertices"></param>
        /// <returns></returns>
        public static List <Vertices> ConvexPartition(Vertices vertices)
        {
            //We force it to CCW as it is a precondition in this algorithm.
            vertices.ForceCounterClockWise();

            List <Vertices> list = new List <Vertices>();
            float           d, lowerDist, upperDist;
            FVector2        p;
            FVector2        lowerInt = new FVector2();
            FVector2        upperInt = new FVector2(); // intersection points
            int             lowerIndex = 0, upperIndex = 0;
            Vertices        lowerPoly, upperPoly;

            for (int i = 0; i < vertices.Count; ++i)
            {
                if (Reflex(i, vertices))
                {
                    lowerDist = upperDist = float.MaxValue; // std::numeric_limits<qreal>::max();
                    for (int j = 0; j < vertices.Count; ++j)
                    {
                        // if line intersects with an edge
                        if (Left(At(i - 1, vertices), At(i, vertices), At(j, vertices)) &&
                            RightOn(At(i - 1, vertices), At(i, vertices), At(j - 1, vertices)))
                        {
                            // find the point of intersection
                            p = LineTools.LineIntersect(At(i - 1, vertices), At(i, vertices), At(j, vertices),
                                                        At(j - 1, vertices));
                            if (Right(At(i + 1, vertices), At(i, vertices), p))
                            {
                                // make sure it's inside the poly
                                d = SquareDist(At(i, vertices), p);
                                if (d < lowerDist)
                                {
                                    // keep only the closest intersection
                                    lowerDist  = d;
                                    lowerInt   = p;
                                    lowerIndex = j;
                                }
                            }
                        }

                        if (Left(At(i + 1, vertices), At(i, vertices), At(j + 1, vertices)) &&
                            RightOn(At(i + 1, vertices), At(i, vertices), At(j, vertices)))
                        {
                            p = LineTools.LineIntersect(At(i + 1, vertices), At(i, vertices), At(j, vertices),
                                                        At(j + 1, vertices));
                            if (Left(At(i - 1, vertices), At(i, vertices), p))
                            {
                                d = SquareDist(At(i, vertices), p);
                                if (d < upperDist)
                                {
                                    upperDist  = d;
                                    upperIndex = j;
                                    upperInt   = p;
                                }
                            }
                        }
                    }

                    // if there are no vertices to connect to, choose a point in the middle
                    if (lowerIndex == (upperIndex + 1) % vertices.Count)
                    {
                        FVector2 sp = ((lowerInt + upperInt) / 2);

                        lowerPoly = Copy(i, upperIndex, vertices);
                        lowerPoly.Add(sp);
                        upperPoly = Copy(lowerIndex, i, vertices);
                        upperPoly.Add(sp);
                    }
                    else
                    {
                        double highestScore = 0, bestIndex = lowerIndex;
                        while (upperIndex < lowerIndex)
                        {
                            upperIndex += vertices.Count;
                        }
                        for (int j = lowerIndex; j <= upperIndex; ++j)
                        {
                            if (CanSee(i, j, vertices))
                            {
                                double score = 1 / (SquareDist(At(i, vertices), At(j, vertices)) + 1);
                                if (Reflex(j, vertices))
                                {
                                    if (RightOn(At(j - 1, vertices), At(j, vertices), At(i, vertices)) &&
                                        LeftOn(At(j + 1, vertices), At(j, vertices), At(i, vertices)))
                                    {
                                        score += 3;
                                    }
                                    else
                                    {
                                        score += 2;
                                    }
                                }
                                else
                                {
                                    score += 1;
                                }
                                if (score > highestScore)
                                {
                                    bestIndex    = j;
                                    highestScore = score;
                                }
                            }
                        }
                        lowerPoly = Copy(i, (int)bestIndex, vertices);
                        upperPoly = Copy((int)bestIndex, i, vertices);
                    }
                    list.AddRange(ConvexPartition(lowerPoly));
                    list.AddRange(ConvexPartition(upperPoly));
                    return(list);
                }
            }

            // polygon is already convex
            if (vertices.Count > Box2D.Settings.b2_maxPolygonVertices)
            {
                lowerPoly = Copy(0, vertices.Count / 2, vertices);
                upperPoly = Copy(vertices.Count / 2, 0, vertices);
                list.AddRange(ConvexPartition(lowerPoly));
                list.AddRange(ConvexPartition(upperPoly));
            }
            else
            {
                list.Add(vertices);
            }

            //The polygons are not guaranteed to be without collinear points. We remove
            //them to be sure.
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = SimplifyTools.CollinearSimplify(list[i], 0);
            }

            //Remove empty vertice collections
            for (int i = list.Count - 1; i >= 0; i--)
            {
                if (list[i].Count == 0)
                {
                    list.RemoveAt(i);
                }
            }

            return(list);
        }