Exemplo n.º 1
0
            public PolyNode GetRightestConnection(PolyNode incoming)
            {
                if (NConnected == 0)
                {
                    Debug.Assert(false);                  // This means the connection graph is inconsistent
                }
                if (NConnected == 1)
                {
                    //b2Assert(false);
                    // Because of the possibility of collapsing nearby points,
                    // we may end up with "spider legs" dangling off of a region.
                    // The correct behavior here is to turn around.
                    return(incoming);
                }
                FVector2 inDir = Position - incoming.Position;

                float inLength = inDir.Length();

                inDir.Normalize();

                Debug.Assert(inLength > Box2D.Settings.b2_epsilon);

                PolyNode result = null;

                for (int i = 0; i < NConnected; ++i)
                {
                    if (Connected[i] == incoming)
                    {
                        continue;
                    }
                    FVector2 testDir       = Connected[i].Position - Position;
                    float    testLengthSqr = testDir.LengthSquared();
                    testDir.Normalize();
                    Debug.Assert(testLengthSqr >= Box2D.Settings.b2_epsilon * Box2D.Settings.b2_epsilon);
                    float myCos = FVector2.Dot(inDir, testDir);
                    float mySin = MathUtils.Cross(inDir, testDir);
                    if (result != null)
                    {
                        FVector2 resultDir = result.Position - Position;
                        resultDir.Normalize();
                        float resCos = FVector2.Dot(inDir, resultDir);
                        float resSin = MathUtils.Cross(inDir, resultDir);
                        if (IsRighter(mySin, myCos, resSin, resCos))
                        {
                            result = Connected[i];
                        }
                    }
                    else
                    {
                        result = Connected[i];
                    }
                }

                Debug.Assert(result != null);

                return(result);
            }
Exemplo n.º 2
0
        /// <summary>
        /// Triangulates a polygon using simple ear-clipping algorithm. Returns
        /// size of Triangle array unless the polygon can't be triangulated.
        /// This should only happen if the polygon self-intersects,
        /// though it will not _always_ return null for a bad polygon - it is the
        /// caller's responsibility to check for self-intersection, and if it
        /// doesn't, it should at least check that the return value is non-null
        /// before using. You're warned!
        ///
        /// Triangles may be degenerate, especially if you have identical points
        /// in the input to the algorithm.  Check this before you use them.
        ///
        /// This is totally unoptimized, so for large polygons it should not be part
        /// of the simulation loop.
        ///
        /// Warning: Only works on simple polygons.
        /// </summary>
        /// <returns></returns>
        public static List <Triangle> TriangulatePolygon(Vertices vertices)
        {
            List <Triangle> results = new List <Triangle>();

            if (vertices.Count < 3)
            {
                return(new List <Triangle>());
            }

            //Recurse and split on pinch points
            Vertices pA, pB;
            Vertices pin = new Vertices(vertices);

            if (ResolvePinchPoint(pin, out pA, out pB))
            {
                List <Triangle> mergeA = TriangulatePolygon(pA);
                List <Triangle> mergeB = TriangulatePolygon(pB);

                if (mergeA.Count == -1 || mergeB.Count == -1)
                {
                    throw new Exception("Can't triangulate your polygon.");
                }

                for (int i = 0; i < mergeA.Count; ++i)
                {
                    results.Add(new Triangle(mergeA[i]));
                }
                for (int i = 0; i < mergeB.Count; ++i)
                {
                    results.Add(new Triangle(mergeB[i]));
                }

                return(results);
            }

            Triangle[] buffer     = new Triangle[vertices.Count - 2];
            int        bufferSize = 0;

            float[] xrem = new float[vertices.Count];
            float[] yrem = new float[vertices.Count];
            for (int i = 0; i < vertices.Count; ++i)
            {
                xrem[i] = vertices[i].X;
                yrem[i] = vertices[i].Y;
            }

            int vNum = vertices.Count;

            while (vNum > 3)
            {
                // Find an ear
                int   earIndex       = -1;
                float earMaxMinCross = -10.0f;
                for (int i = 0; i < vNum; ++i)
                {
                    if (IsEar(i, xrem, yrem, vNum))
                    {
                        int      lower = Remainder(i - 1, vNum);
                        int      upper = Remainder(i + 1, vNum);
                        FVector2 d1    = new FVector2(xrem[upper] - xrem[i], yrem[upper] - yrem[i]);
                        FVector2 d2    = new FVector2(xrem[i] - xrem[lower], yrem[i] - yrem[lower]);
                        FVector2 d3    = new FVector2(xrem[lower] - xrem[upper], yrem[lower] - yrem[upper]);

                        d1.Normalize();
                        d2.Normalize();
                        d3.Normalize();
                        float cross12;
                        MathUtils.Cross(ref d1, ref d2, out cross12);
                        cross12 = Math.Abs(cross12);

                        float cross23;
                        MathUtils.Cross(ref d2, ref d3, out cross23);
                        cross23 = Math.Abs(cross23);

                        float cross31;
                        MathUtils.Cross(ref d3, ref d1, out cross31);
                        cross31 = Math.Abs(cross31);

                        //Find the maximum minimum angle
                        float minCross = Math.Min(cross12, Math.Min(cross23, cross31));
                        if (minCross > earMaxMinCross)
                        {
                            earIndex       = i;
                            earMaxMinCross = minCross;
                        }
                    }
                }

                // If we still haven't found an ear, we're screwed.
                // Note: sometimes this is happening because the
                // remaining points are collinear.  Really these
                // should just be thrown out without halting triangulation.
                if (earIndex == -1)
                {
                    for (int i = 0; i < bufferSize; i++)
                    {
                        results.Add(new Triangle(buffer[i]));
                    }

                    return(results);
                }

                // Clip off the ear:
                // - remove the ear tip from the list

                --vNum;
                float[] newx     = new float[vNum];
                float[] newy     = new float[vNum];
                int     currDest = 0;
                for (int i = 0; i < vNum; ++i)
                {
                    if (currDest == earIndex)
                    {
                        ++currDest;
                    }
                    newx[i] = xrem[currDest];
                    newy[i] = yrem[currDest];
                    ++currDest;
                }

                // - add the clipped triangle to the triangle list
                int      under = (earIndex == 0) ? (vNum) : (earIndex - 1);
                int      over  = (earIndex == vNum) ? 0 : (earIndex + 1);
                Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under],
                                              yrem[under]);
                buffer[bufferSize] = toAdd;
                ++bufferSize;

                // - replace the old list with the new one
                xrem = newx;
                yrem = newy;
            }

            Triangle tooAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]);

            buffer[bufferSize] = tooAdd;
            ++bufferSize;

            for (int i = 0; i < bufferSize; i++)
            {
                results.Add(new Triangle(buffer[i]));
            }

            return(results);
        }