Esempio n. 1
0
        private static double DistancePointLine(FVector2 p, FVector2 A, FVector2 B)
        {
            // if start == end, then use point-to-point distance
            if (A.X == B.X && A.Y == B.Y)
            {
                return(DistancePointPoint(p, A));
            }

            // otherwise use comp.graphics.algorithms Frequently Asked Questions method

            /*(1)             AC dot AB
             *          r =   ---------
             ||AB||^2
             *
             *                  r has the following meaning:
             *                  r=0 Point = A
             *                  r=1 Point = B
             *                  r<0 Point is on the backward extension of AB
             *                  r>1 Point is on the forward extension of AB
             *                  0<r<1 Point is interior to AB
             */

            double r = ((p.X - A.X) * (B.X - A.X) + (p.Y - A.Y) * (B.Y - A.Y))
                       /
                       ((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));

            if (r <= 0.0)
            {
                return(DistancePointPoint(p, A));
            }
            if (r >= 1.0)
            {
                return(DistancePointPoint(p, B));
            }


            /*(2)
             *                      (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
             *                  s = -----------------------------
             *                                  Curve^2
             *
             *                  Then the distance from C to Point = |s|*Curve.
             */

            double s = ((A.Y - p.Y) * (B.X - A.X) - (A.X - p.X) * (B.Y - A.Y))
                       /
                       ((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));

            return(Math.Abs(s) * Math.Sqrt(((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y))));
        }
Esempio n. 2
0
        /// <summary>
        /// Build vertices to represent an oriented box.
        /// </summary>
        /// <param name="hx">the half-width.</param>
        /// <param name="hy">the half-height.</param>
        /// <param name="center">the center of the box in local coordinates.</param>
        /// <param name="angle">the rotation of the box in local coordinates.</param>
        public static Vertices CreateRectangle(float hx, float hy, FVector2 center, float angle)
        {
            Vertices vertices = CreateRectangle(hx, hy);

            Transform xf = new Transform();

            xf.p = center;
            xf.q.Set(angle);

            // Transform vertices
            for (int i = 0; i < 4; ++i)
            {
                vertices[i] = MathUtils.Mul(ref xf, vertices[i]);
            }

            return(vertices);
        }
Esempio n. 3
0
        /// <summary>
        /// Return the angle between two vectors on a plane
        /// The angle is from vector 1 to vector 2, positive anticlockwise
        /// The result is between -pi -> pi
        /// </summary>
        public static double VectorAngle(ref FVector2 p1, ref FVector2 p2)
        {
            double theta1 = Math.Atan2(p1.Y, p1.X);
            double theta2 = Math.Atan2(p2.Y, p2.X);
            double dtheta = theta2 - theta1;

            while (dtheta > Math.PI)
            {
                dtheta -= (2 * Math.PI);
            }
            while (dtheta < -Math.PI)
            {
                dtheta += (2 * Math.PI);
            }

            return(dtheta);
        }
Esempio n. 4
0
        /// <summary>
        /// Searches for the next shape.
        /// </summary>
        /// <param name="detectedPolygons">Already detected polygons.</param>
        /// <param name="start">Search start coordinate.</param>
        /// <param name="entrance">Returns the found entrance coordinate. Null if no other shapes found.</param>
        /// <returns>True if a new shape was found.</returns>
        private bool SearchNextHullEntrance(List <DetectedVertices> detectedPolygons, FVector2 start, out FVector2?entrance)
        {
            int x;

            bool foundTransparent = false;
            bool inPolygon        = false;

            for (int i = (int)start.X + (int)start.Y * _width; i <= _dataLength; i++)
            {
                if (IsSolid(ref i))
                {
                    if (foundTransparent)
                    {
                        x        = i % _width;
                        entrance = new FVector2(x, (i - x) / (float)_width);

                        inPolygon = false;
                        for (int polygonIdx = 0; polygonIdx < detectedPolygons.Count; polygonIdx++)
                        {
                            if (InPolygon(detectedPolygons[polygonIdx], entrance.Value))
                            {
                                inPolygon = true;
                                break;
                            }
                        }

                        if (inPolygon)
                        {
                            foundTransparent = false;
                        }
                        else
                        {
                            return(true);
                        }
                    }
                }
                else
                {
                    foundTransparent = true;
                }
            }

            entrance = null;
            return(false);
        }
Esempio n. 5
0
        private bool IsNearPixel(ref FVector2 current, ref FVector2 near)
        {
            for (int i = 0; i < _CLOSEPIXELS_LENGTH; i++)
            {
                int x = (int)current.X + ClosePixels[i, 0];
                int y = (int)current.Y + ClosePixels[i, 1];

                if (x >= 0 && x <= _width && y >= 0 && y <= _height)
                {
                    if (x == (int)near.X && y == (int)near.Y)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Esempio n. 6
0
        private bool SearchNearPixels(bool searchingForSolidPixel, ref FVector2 current, out FVector2 foundPixel)
        {
            for (int i = 0; i < _CLOSEPIXELS_LENGTH; i++)
            {
                int x = (int)current.X + ClosePixels[i, 0];
                int y = (int)current.Y + ClosePixels[i, 1];

                if (!searchingForSolidPixel ^ IsSolid(ref x, ref y))
                {
                    foundPixel = new FVector2(x, y);
                    return(true);
                }
            }

            // Nothing found.
            foundPixel = FVector2.Zero;
            return(false);
        }
Esempio n. 7
0
        private bool SearchHullEntrance(out FVector2 entrance)
        {
            // Search for first solid pixel.
            for (int y = 0; y <= _height; y++)
            {
                for (int x = 0; x <= _width; x++)
                {
                    if (IsSolid(ref x, ref y))
                    {
                        entrance = new FVector2(x, y);
                        return(true);
                    }
                }
            }

            // If there are no solid pixels.
            entrance = FVector2.Zero;
            return(false);
        }
Esempio n. 8
0
        //From Mark Bayazit's convex decomposition algorithm
        public static FVector2 LineIntersect(FVector2 p1, FVector2 p2, FVector2 q1, FVector2 q2)
        {
            FVector2 i   = FVector2.Zero;
            float    a1  = p2.Y - p1.Y;
            float    b1  = p1.X - p2.X;
            float    c1  = a1 * p1.X + b1 * p1.Y;
            float    a2  = q2.Y - q1.Y;
            float    b2  = q1.X - q2.X;
            float    c2  = a2 * q1.X + b2 * q1.Y;
            float    det = a1 * b2 - a2 * b1;

            if (!MathUtils.FloatEquals(det, 0))
            {
                // lines are not parallel
                i.X = (b2 * c1 - b1 * c2) / det;
                i.Y = (a1 * c2 - a2 * c1) / det;
            }
            return(i);
        }
Esempio n. 9
0
        public void Transform(FMatrix transform)
        {
            // Transform main polygon
            for (int i = 0; i < this.Count; i++)
            {
                this[i] = FVector2.Transform(this[i], transform);
            }

            // Transform holes
            FVector2[] temp = null;
            if (_holes != null && _holes.Count > 0)
            {
                for (int i = 0; i < _holes.Count; i++)
                {
                    temp = _holes[i].ToArray();
                    FVector2.Transform(temp, ref transform, temp);

                    _holes[i] = new Vertices(temp);
                }
            }
        }
Esempio n. 10
0
        private bool InPolygon(DetectedVertices polygon, FVector2 point)
        {
            bool inPolygon = !DistanceToHullAcceptable(polygon, point, true);

            if (!inPolygon)
            {
                List <float> xCoords = SearchCrossingEdges(polygon, (int)point.Y);

                if (xCoords.Count > 0 && xCoords.Count % 2 == 0)
                {
                    for (int i = 0; i < xCoords.Count; i += 2)
                    {
                        if (xCoords[i] <= point.X && xCoords[i + 1] >= point.X)
                        {
                            return(true);
                        }
                    }
                }

                return(false);
            }

            return(true);
        }
Esempio n. 11
0
        private static float VecDsq(FVector2 a, FVector2 b)
        {
            FVector2 d = a - b;

            return(d.X * d.X + d.Y * d.Y);
        }
Esempio n. 12
0
        /// <summary>
        /// Decompose the polygon into triangles
        /// </summary>
        /// <param name="contour">The list of points describing the polygon</param>
        /// <returns></returns>
        public static List <Vertices> ConvexPartition(Vertices contour)
        {
            int n = contour.Count;

            if (n < 3)
            {
                return(new List <Vertices>());
            }

            int[] V = new int[n];

            // We want a counter-clockwise polygon in V
            if (contour.IsCounterClockWise())
            {
                for (int v = 0; v < n; v++)
                {
                    V[v] = v;
                }
            }
            else
            {
                for (int v = 0; v < n; v++)
                {
                    V[v] = (n - 1) - v;
                }
            }

            int nv = n;

            // Remove nv-2 Vertices, creating 1 triangle every time
            int count = 2 * nv; /* error detection */

            List <Vertices> result = new List <Vertices>();

            for (int v = nv - 1; nv > 2;)
            {
                // If we loop, it is probably a non-simple polygon
                if (0 >= (count--))
                {
                    // Triangulate: ERROR - probable bad polygon!
                    return(new List <Vertices>());
                }

                // Three consecutive vertices in current polygon, <u,v,w>
                int u = v;
                if (nv <= u)
                {
                    u = 0; // Previous
                }
                v = u + 1;
                if (nv <= v)
                {
                    v = 0; // New v
                }
                int w = v + 1;
                if (nv <= w)
                {
                    w = 0; // Next
                }
                _tmpA = contour[V[u]];
                _tmpB = contour[V[v]];
                _tmpC = contour[V[w]];

                if (Snip(contour, u, v, w, nv, V))
                {
                    int s, t;

                    // Output Triangle
                    Vertices triangle = new Vertices(3);
                    triangle.Add(_tmpA);
                    triangle.Add(_tmpB);
                    triangle.Add(_tmpC);
                    result.Add(triangle);

                    // Remove v from remaining polygon
                    for (s = v, t = v + 1; t < nv; s++, t++)
                    {
                        V[s] = V[t];
                    }
                    nv--;

                    // Reset error detection counter
                    count = 2 * nv;
                }
            }

            return(result);
        }
Esempio n. 13
0
        /// <summary>
        /// Check if the point P is inside the triangle defined by
        /// the points A, B, C
        /// </summary>
        /// <param name="a">The A point.</param>
        /// <param name="b">The B point.</param>
        /// <param name="c">The C point.</param>
        /// <param name="p">The point to be tested.</param>
        /// <returns>True if the point is inside the triangle</returns>
        private static bool InsideTriangle(ref FVector2 a, ref FVector2 b, ref FVector2 c, ref FVector2 p)
        {
            //A cross bp
            float abp = (c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X);

            //A cross ap
            float aap = (b.X - a.X) * (p.Y - a.Y) - (b.Y - a.Y) * (p.X - a.X);

            //b cross cp
            float bcp = (a.X - c.X) * (p.Y - c.Y) - (a.Y - c.Y) * (p.X - c.X);

            return((abp >= 0.0f) && (bcp >= 0.0f) && (aap >= 0.0f));
        }
Esempio n. 14
0
        //Andrew's monotone chain 2D convex hull algorithm.
        //Copyright 2001, softSurfer (www.softsurfer.com)

        /// <summary>
        /// Gets the convex hull.
        /// </summary>
        /// <remarks>
        /// http://www.softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm
        /// </remarks>
        /// <returns></returns>
        public static Vertices GetConvexHull(Vertices P)
        {
            P.Sort(new PointComparer());

            FVector2[] H   = new FVector2[P.Count];
            Vertices   res = new Vertices();

            int n = P.Count;

            int bot, top = -1; // indices for bottom and top of the stack
            int i;             // array scan index

            // Get the indices of points with min x-coord and min|max y-coord
            int   minmin = 0, minmax;
            float xmin = P[0].X;

            for (i = 1; i < n; i++)
            {
                if (P[i].X != xmin)
                {
                    break;
                }
            }
            minmax = i - 1;
            if (minmax == n - 1)
            {
                // degenerate case: all x-coords == xmin
                H[++top] = P[minmin];
                if (P[minmax].Y != P[minmin].Y) // a nontrivial segment
                {
                    H[++top] = P[minmax];
                }
                H[++top] = P[minmin]; // add polygon endpoint

                for (int j = 0; j < top + 1; j++)
                {
                    res.Add(H[j]);
                }

                return(res);
            }

            top = res.Count - 1;

            // Get the indices of points with max x-coord and min|max y-coord
            int   maxmin, maxmax = n - 1;
            float xmax = P[n - 1].X;

            for (i = n - 2; i >= 0; i--)
            {
                if (P[i].X != xmax)
                {
                    break;
                }
            }
            maxmin = i + 1;

            // Compute the lower hull on the stack H
            H[++top] = P[minmin]; // push minmin point onto stack
            i        = minmax;
            while (++i <= maxmin)
            {
                // the lower line joins P[minmin] with P[maxmin]
                if (MathUtils.Area(P[minmin], P[maxmin], P[i]) >= 0 && i < maxmin)
                {
                    continue;   // ignore P[i] above or on the lower line
                }
                while (top > 0) // there are at least 2 points on the stack
                {
                    // test if P[i] is left of the line at the stack top
                    if (MathUtils.Area(H[top - 1], H[top], P[i]) > 0)
                    {
                        break; // P[i] is a new hull vertex
                    }
                    else
                    {
                        top--; // pop top point off stack
                    }
                }
                H[++top] = P[i]; // push P[i] onto stack
            }

            // Next, compute the upper hull on the stack H above the bottom hull
            if (maxmax != maxmin)     // if distinct xmax points
            {
                H[++top] = P[maxmax]; // push maxmax point onto stack
            }
            bot = top;                // the bottom point of the upper hull stack
            i   = maxmin;
            while (--i >= minmax)
            {
                // the upper line joins P[maxmax] with P[minmax]
                if (MathUtils.Area(P[maxmax], P[minmax], P[i]) >= 0 && i > minmax)
                {
                    continue;     // ignore P[i] below or on the upper line
                }
                while (top > bot) // at least 2 points on the upper stack
                {
                    // test if P[i] is left of the line at the stack top
                    if (MathUtils.Area(H[top - 1], H[top], P[i]) > 0)
                    {
                        break; // P[i] is a new hull vertex
                    }
                    else
                    {
                        top--; // pop top point off stack
                    }
                }
                H[++top] = P[i]; // push P[i] onto stack
            }
            if (minmax != minmin)
            {
                H[++top] = P[minmin]; // push joining endpoint onto stack
            }
            for (int j = 0; j < top + 1; j++)
            {
                res.Add(H[j]);
            }

            return(res);
        }
Esempio n. 15
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="entrance"></param>
        /// <param name="last"></param>
        /// <returns></returns>
        private Vertices CreateSimplePolygon(FVector2 entrance, FVector2 last)
        {
            bool entranceFound = false;
            bool endOfHull     = false;

            Vertices polygon       = new Vertices(32);
            Vertices hullArea      = new Vertices(32);
            Vertices endOfHullArea = new Vertices(32);

            FVector2 current = FVector2.Zero;

            #region Entrance check

            // Get the entrance point. //todo: alle möglichkeiten testen
            if (entrance == FVector2.Zero || !InBounds(ref entrance))
            {
                entranceFound = SearchHullEntrance(out entrance);

                if (entranceFound)
                {
                    current = new FVector2(entrance.X - 1f, entrance.Y);
                }
            }
            else
            {
                if (IsSolid(ref entrance))
                {
                    if (IsNearPixel(ref entrance, ref last))
                    {
                        current       = last;
                        entranceFound = true;
                    }
                    else
                    {
                        FVector2 temp;
                        if (SearchNearPixels(false, ref entrance, out temp))
                        {
                            current       = temp;
                            entranceFound = true;
                        }
                        else
                        {
                            entranceFound = false;
                        }
                    }
                }
            }

            #endregion

            if (entranceFound)
            {
                polygon.Add(entrance);
                hullArea.Add(entrance);

                FVector2 next = entrance;

                do
                {
                    // Search in the pre vision list for an outstanding point.
                    FVector2 outstanding;
                    if (SearchForOutstandingVertex(hullArea, out outstanding))
                    {
                        if (endOfHull)
                        {
                            // We have found the next pixel, but is it on the last bit of the hull?
                            if (endOfHullArea.Contains(outstanding))
                            {
                                // Indeed.
                                polygon.Add(outstanding);
                            }

                            // That's enough, quit.
                            break;
                        }

                        // Add it and remove all vertices that don't matter anymore
                        // (all the vertices before the outstanding).
                        polygon.Add(outstanding);
                        hullArea.RemoveRange(0, hullArea.IndexOf(outstanding));
                    }

                    // Last point gets current and current gets next. Our little spider is moving forward on the hull ;).
                    last    = current;
                    current = next;

                    // Get the next point on hull.
                    if (GetNextHullPoint(ref last, ref current, out next))
                    {
                        // Add the vertex to a hull pre vision list.
                        hullArea.Add(next);
                    }
                    else
                    {
                        // Quit
                        break;
                    }

                    if (next == entrance && !endOfHull)
                    {
                        // It's the last bit of the hull, search on and exit at next found vertex.
                        endOfHull = true;
                        endOfHullArea.AddRange(hullArea);

                        // We don't want the last vertex to be the same as the first one, because it causes the triangulation code to crash.
                        if (endOfHullArea.Contains(entrance))
                        {
                            endOfHullArea.Remove(entrance);
                        }
                    }
                } while (true);
            }

            return(polygon);
        }
Esempio n. 16
0
 /// <summary>
 /// This is a high-level function to cuts fixtures inside the given world, using the start and end points.
 /// Note: We don't support cutting when the start or end is inside a shape.
 /// </summary>
 /// <param name="world">The world.</param>
 /// <param name="start">The startpoint.</param>
 /// <param name="end">The endpoint.</param>
 /// <param name="thickness">The thickness of the cut</param>
 public static void Cut(Box2D.World world, FVector2 start, FVector2 end, float thickness)
 {
     /*
      * List<Fixture> fixtures = new List<Fixture>();
      * List<FVector2> entryPoints = new List<FVector2>();
      * List<FVector2> exitPoints = new List<FVector2>();
      *
      * //We don't support cutting when the start or end is inside a shape.
      * if (world.TestPoint(start) != null || world.TestPoint(end) != null)
      *  return;
      *
      * //Get the entry points
      * world.RayCast((f, p, n, fr) =>
      *                {
      *                    fixtures.Add(f);
      *                    entryPoints.Add(p);
      *                    return 1;
      *                }, start, end);
      *
      * //Reverse the ray to get the exitpoints
      * world.RayCast((f, p, n, fr) =>
      *                {
      *                    exitPoints.Add(p);
      *                    return 1;
      *                }, end, start);
      *
      * //We only have a single point. We need at least 2
      * if (entryPoints.Count + exitPoints.Count < 2)
      *  return;
      *
      * for (int i = 0; i < fixtures.Count; i++)
      * {
      *  // can't cut circles yet !
      *  if (fixtures[i].Shape.ShapeType != ShapeType.Polygon)
      *      continue;
      *
      *  if (fixtures[i].Body.BodyType != BodyType.Static)
      *  {
      *      //Split the shape up into two shapes
      *      Vertices first;
      *      Vertices second;
      *      SplitShape(fixtures[i], entryPoints[i], exitPoints[i], thickness, out first, out second);
      *
      *      //Delete the original shape and create two new. Retain the properties of the body.
      *      if (SanityCheck(first))
      *      {
      *          Body firstFixture = BodyFactory.CreatePolygon(world, first, fixtures[i].Shape.Density,
      *                                                              fixtures[i].Body.Position);
      *          firstFixture.Rotation = fixtures[i].Body.Rotation;
      *          firstFixture.LinearVelocity = fixtures[i].Body.LinearVelocity;
      *          firstFixture.AngularVelocity = fixtures[i].Body.AngularVelocity;
      *          firstFixture.BodyType = BodyType.Dynamic;
      *      }
      *
      *      if (SanityCheck(second))
      *      {
      *          Body secondFixture = BodyFactory.CreatePolygon(world, second, fixtures[i].Shape.Density,
      *                                                               fixtures[i].Body.Position);
      *          secondFixture.Rotation = fixtures[i].Body.Rotation;
      *          secondFixture.LinearVelocity = fixtures[i].Body.LinearVelocity;
      *          secondFixture.AngularVelocity = fixtures[i].Body.AngularVelocity;
      *          secondFixture.BodyType = BodyType.Dynamic;
      *      }
      *      world.RemoveBody(fixtures[i].Body);
      *  }
      * }
      * */
 }
Esempio n. 17
0
        /// <summary>
        /// Marching squares over the given domain using the mesh defined via the dimensions
        ///    (wid,hei) to build a set of polygons such that f(x,y) less than 0, using the given number
        ///    'bin' for recursive linear inteprolation along cell boundaries.
        ///
        ///    if 'comb' is true, then the polygons will also be composited into larger possible concave
        ///    polygons.
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="cellWidth"></param>
        /// <param name="cellHeight"></param>
        /// <param name="f"></param>
        /// <param name="lerpCount"></param>
        /// <param name="combine"></param>
        /// <returns></returns>
        public static List <Vertices> DetectSquares(Box2D.AABB domain, float cellWidth, float cellHeight, sbyte[,] f,
                                                    int lerpCount, bool combine)
        {
            CxFastList <GeomPoly> ret = new CxFastList <GeomPoly>();

            List <Vertices> verticesList = new List <Vertices>();

            //NOTE: removed assignments as they were not used.
            List <GeomPoly> polyList;
            GeomPoly        gp;

            int  xn = (int)(domain.GetExtents().x * 2 / cellWidth);
            bool xp = xn == (domain.GetExtents().x * 2 / cellWidth);
            int  yn = (int)(domain.GetExtents().y * 2 / cellHeight);
            bool yp = yn == (domain.GetExtents().y * 2 / cellHeight);

            if (!xp)
            {
                xn++;
            }
            if (!yp)
            {
                yn++;
            }

            sbyte[,] fs       = new sbyte[xn + 1, yn + 1];
            GeomPolyVal[,] ps = new GeomPolyVal[xn + 1, yn + 1];

            //populate shared function lookups.
            for (int x = 0; x < xn + 1; x++)
            {
                int x0;
                if (x == xn)
                {
                    x0 = (int)domain.upperBound.x;
                }
                else
                {
                    x0 = (int)(x * cellWidth + domain.lowerBound.x);
                }
                for (int y = 0; y < yn + 1; y++)
                {
                    int y0;
                    if (y == yn)
                    {
                        y0 = (int)domain.upperBound.y;
                    }
                    else
                    {
                        y0 = (int)(y * cellHeight + domain.lowerBound.y);
                    }
                    fs[x, y] = f[x0, y0];
                }
            }

            //generate sub-polys and combine to scan lines
            for (int y = 0; y < yn; y++)
            {
                float y0 = y * cellHeight + domain.lowerBound.y;
                float y1;
                if (y == yn - 1)
                {
                    y1 = domain.upperBound.y;
                }
                else
                {
                    y1 = y0 + cellHeight;
                }
                GeomPoly pre = null;
                for (int x = 0; x < xn; x++)
                {
                    float x0 = x * cellWidth + domain.lowerBound.x;
                    float x1;
                    if (x == xn - 1)
                    {
                        x1 = domain.upperBound.x;
                    }
                    else
                    {
                        x1 = x0 + cellWidth;
                    }

                    gp = new GeomPoly();

                    int key = MarchSquare(f, fs, ref gp, x, y, x0, y0, x1, y1, lerpCount);
                    if (gp.Length != 0)
                    {
                        if (combine && pre != null && (key & 9) != 0)
                        {
                            combLeft(ref pre, ref gp);
                            gp = pre;
                        }
                        else
                        {
                            ret.Add(gp);
                        }
                        ps[x, y] = new GeomPolyVal(gp, key);
                    }
                    else
                    {
                        gp = null;
                    }
                    pre = gp;
                }
            }
            if (!combine)
            {
                polyList = ret.GetListOfElements();

                foreach (GeomPoly poly in polyList)
                {
                    verticesList.Add(new Vertices(poly.Points.GetListOfElements()));
                }

                return(verticesList);
            }

            //combine scan lines together
            for (int y = 1; y < yn; y++)
            {
                int x = 0;
                while (x < xn)
                {
                    GeomPolyVal p = ps[x, y];

                    //skip along scan line if no polygon exists at this point
                    if (p == null)
                    {
                        x++;
                        continue;
                    }

                    //skip along if current polygon cannot be combined above.
                    if ((p.Key & 12) == 0)
                    {
                        x++;
                        continue;
                    }

                    //skip along if no polygon exists above.
                    GeomPolyVal u = ps[x, y - 1];
                    if (u == null)
                    {
                        x++;
                        continue;
                    }

                    //skip along if polygon above cannot be combined with.
                    if ((u.Key & 3) == 0)
                    {
                        x++;
                        continue;
                    }

                    float ax = x * cellWidth + domain.lowerBound.x;
                    float ay = y * cellHeight + domain.lowerBound.y;

                    CxFastList <FVector2> bp = p.GeomP.Points;
                    CxFastList <FVector2> ap = u.GeomP.Points;

                    //skip if it's already been combined with above polygon
                    if (u.GeomP == p.GeomP)
                    {
                        x++;
                        continue;
                    }

                    //combine above (but disallow the hole thingies
                    CxFastListNode <FVector2> bi = bp.Begin();
                    while (Square(bi.Elem().Y - ay) > Box2D.Settings.b2_epsilon || bi.Elem().X < ax)
                    {
                        bi = bi.Next();
                    }

                    //NOTE: Unused
                    //Vector2 b0 = bi.elem();
                    FVector2 b1 = bi.Next().Elem();
                    if (Square(b1.Y - ay) > Box2D.Settings.b2_epsilon)
                    {
                        x++;
                        continue;
                    }

                    bool brk = true;
                    CxFastListNode <FVector2> ai = ap.Begin();
                    while (ai != ap.End())
                    {
                        if (VecDsq(ai.Elem(), b1) < Box2D.Settings.b2_epsilon)
                        {
                            brk = false;
                            break;
                        }
                        ai = ai.Next();
                    }
                    if (brk)
                    {
                        x++;
                        continue;
                    }

                    CxFastListNode <FVector2> bj = bi.Next().Next();
                    if (bj == bp.End())
                    {
                        bj = bp.Begin();
                    }
                    while (bj != bi)
                    {
                        ai = ap.Insert(ai, bj.Elem()); // .clone()
                        bj = bj.Next();
                        if (bj == bp.End())
                        {
                            bj = bp.Begin();
                        }
                        u.GeomP.Length++;
                    }
                    //u.p.simplify(float.Epsilon,float.Epsilon);
                    //
                    ax = x + 1;
                    while (ax < xn)
                    {
                        GeomPolyVal p2 = ps[(int)ax, y];
                        if (p2 == null || p2.GeomP != p.GeomP)
                        {
                            ax++;
                            continue;
                        }
                        p2.GeomP = u.GeomP;
                        ax++;
                    }
                    ax = x - 1;
                    while (ax >= 0)
                    {
                        GeomPolyVal p2 = ps[(int)ax, y];
                        if (p2 == null || p2.GeomP != p.GeomP)
                        {
                            ax--;
                            continue;
                        }
                        p2.GeomP = u.GeomP;
                        ax--;
                    }
                    ret.Remove(p.GeomP);
                    p.GeomP = u.GeomP;

                    x = (int)((bi.Next().Elem().X - domain.lowerBound.x) / cellWidth) + 1;
                    //x++; this was already commented out!
                }
            }

            polyList = ret.GetListOfElements();

            foreach (GeomPoly poly in polyList)
            {
                verticesList.Add(new Vertices(poly.Points.GetListOfElements()));
            }

            return(verticesList);
        }
Esempio n. 18
0
 public bool InBounds(ref FVector2 coord)
 {
     return(coord.X >= 0f && coord.X < _width && coord.Y >= 0f && coord.Y < _height);
 }
Esempio n. 19
0
        /// <summary>
        /// This method detects if two line segments (or lines) intersect,
        /// and, if so, the point of intersection. Use the <paramref name="firstIsSegment"/> and
        /// <paramref name="secondIsSegment"/> parameters to set whether the intersection point
        /// must be on the first and second line segments. Setting these
        /// both to true means you are doing a line-segment to line-segment
        /// intersection. Setting one of them to true means you are doing a
        /// line to line-segment intersection test, and so on.
        /// Note: If two line segments are coincident, then
        /// no intersection is detected (there are actually
        /// infinite intersection points).
        /// Author: Jeremy Bell
        /// </summary>
        /// <param name="point1">The first point of the first line segment.</param>
        /// <param name="point2">The second point of the first line segment.</param>
        /// <param name="point3">The first point of the second line segment.</param>
        /// <param name="point4">The second point of the second line segment.</param>
        /// <param name="point">This is set to the intersection
        /// point if an intersection is detected.</param>
        /// <param name="firstIsSegment">Set this to true to require that the
        /// intersection point be on the first line segment.</param>
        /// <param name="secondIsSegment">Set this to true to require that the
        /// intersection point be on the second line segment.</param>
        /// <returns>True if an intersection is detected, false otherwise.</returns>
        public static bool LineIntersect(ref FVector2 point1, ref FVector2 point2, ref FVector2 point3, ref FVector2 point4,
                                         bool firstIsSegment, bool secondIsSegment,
                                         out FVector2 point)
        {
            point = new FVector2();

            // these are reused later.
            // each lettered sub-calculation is used twice, except
            // for b and d, which are used 3 times
            float a = point4.Y - point3.Y;
            float b = point2.X - point1.X;
            float c = point4.X - point3.X;
            float d = point2.Y - point1.Y;

            // denominator to solution of linear system
            float denom = (a * b) - (c * d);

            // if denominator is 0, then lines are parallel
            if (!(denom >= -Box2D.Settings.b2_epsilon && denom <= Box2D.Settings.b2_epsilon))
            {
                float e            = point1.Y - point3.Y;
                float f            = point1.X - point3.X;
                float oneOverDenom = 1.0f / denom;

                // numerator of first equation
                float ua = (c * e) - (a * f);
                ua *= oneOverDenom;

                // check if intersection point of the two lines is on line segment 1
                if (!firstIsSegment || ua >= 0.0f && ua <= 1.0f)
                {
                    // numerator of second equation
                    float ub = (b * e) - (d * f);
                    ub *= oneOverDenom;

                    // check if intersection point of the two lines is on line segment 2
                    // means the line segments intersect, since we know it is on
                    // segment 1 as well.
                    if (!secondIsSegment || ub >= 0.0f && ub <= 1.0f)
                    {
                        // check if they are coincident (no collision in this case)
                        if (ua != 0f || ub != 0f)
                        {
                            //There is an intersection
                            point.X = point1.X + ua * b;
                            point.Y = point1.Y + ua * d;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Esempio n. 20
0
 /// <summary>
 /// This method detects if two line segments (or lines) intersect,
 /// and, if so, the point of intersection. Use the <paramref name="firstIsSegment"/> and
 /// <paramref name="secondIsSegment"/> parameters to set whether the intersection point
 /// must be on the first and second line segments. Setting these
 /// both to true means you are doing a line-segment to line-segment
 /// intersection. Setting one of them to true means you are doing a
 /// line to line-segment intersection test, and so on.
 /// Note: If two line segments are coincident, then
 /// no intersection is detected (there are actually
 /// infinite intersection points).
 /// Author: Jeremy Bell
 /// </summary>
 /// <param name="point1">The first point of the first line segment.</param>
 /// <param name="point2">The second point of the first line segment.</param>
 /// <param name="point3">The first point of the second line segment.</param>
 /// <param name="point4">The second point of the second line segment.</param>
 /// <param name="intersectionPoint">This is set to the intersection
 /// point if an intersection is detected.</param>
 /// <param name="firstIsSegment">Set this to true to require that the
 /// intersection point be on the first line segment.</param>
 /// <param name="secondIsSegment">Set this to true to require that the
 /// intersection point be on the second line segment.</param>
 /// <returns>True if an intersection is detected, false otherwise.</returns>
 public static bool LineIntersect(FVector2 point1, FVector2 point2, FVector2 point3, FVector2 point4,
                                  bool firstIsSegment,
                                  bool secondIsSegment, out FVector2 intersectionPoint)
 {
     return(LineIntersect(ref point1, ref point2, ref point3, ref point4, firstIsSegment, secondIsSegment,
                          out intersectionPoint));
 }
Esempio n. 21
0
 /// <summary>
 /// This method detects if two line segments intersect,
 /// and, if so, the point of intersection.
 /// Note: If two line segments are coincident, then
 /// no intersection is detected (there are actually
 /// infinite intersection points).
 /// </summary>
 /// <param name="point1">The first point of the first line segment.</param>
 /// <param name="point2">The second point of the first line segment.</param>
 /// <param name="point3">The first point of the second line segment.</param>
 /// <param name="point4">The second point of the second line segment.</param>
 /// <param name="intersectionPoint">This is set to the intersection
 /// point if an intersection is detected.</param>
 /// <returns>True if an intersection is detected, false otherwise.</returns>
 public static bool LineIntersect(FVector2 point1, FVector2 point2, FVector2 point3, FVector2 point4,
                                  out FVector2 intersectionPoint)
 {
     return(LineIntersect(ref point1, ref point2, ref point3, ref point4, true, true, out intersectionPoint));
 }
Esempio n. 22
0
 /// <summary>
 /// Get all intersections between a line segment and an AABB.
 /// </summary>
 /// <param name="point1">The first point of the line segment to test</param>
 /// <param name="point2">The second point of the line segment to test.</param>
 /// <param name="aabb">The AABB that is used for testing intersection.</param>
 /// <param name="intersectionPoints">An list of intersection points. Any intersection points found will be added to this list.</param>
 public static void LineSegmentAABBIntersect(ref FVector2 point1, ref FVector2 point2, Box2D.AABB aabb,
                                             ref List <FVector2> intersectionPoints)
 {
     // LineSegmentVerticesIntersect(ref point1, ref point2, aabb.vVertices, ref intersectionPoints);
 }
Esempio n. 23
0
        // From Eric Jordan's convex decomposition library
        /// <summary>
        ///Check if the lines a0->a1 and b0->b1 cross.
        ///If they do, intersectionPoint will be filled
        ///with the point of crossing.
        ///
        ///Grazing lines should not return true.
        ///
        /// </summary>
        /// <param name="a0"></param>
        /// <param name="a1"></param>
        /// <param name="b0"></param>
        /// <param name="b1"></param>
        /// <param name="intersectionPoint"></param>
        /// <returns></returns>
        public static bool LineIntersect2(FVector2 a0, FVector2 a1, FVector2 b0, FVector2 b1, out FVector2 intersectionPoint)
        {
            intersectionPoint = FVector2.Zero;

            if (a0 == b0 || a0 == b1 || a1 == b0 || a1 == b1)
            {
                return(false);
            }

            float x1 = a0.X;
            float y1 = a0.Y;
            float x2 = a1.X;
            float y2 = a1.Y;
            float x3 = b0.X;
            float y3 = b0.Y;
            float x4 = b1.X;
            float y4 = b1.Y;

            //AABB early exit
            if (Math.Max(x1, x2) < Math.Min(x3, x4) || Math.Max(x3, x4) < Math.Min(x1, x2))
            {
                return(false);
            }

            if (Math.Max(y1, y2) < Math.Min(y3, y4) || Math.Max(y3, y4) < Math.Min(y1, y2))
            {
                return(false);
            }

            float ua    = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));
            float ub    = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));
            float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

            if (Math.Abs(denom) < Box2D.Settings.b2_epsilon)
            {
                //Lines are too close to parallel to call
                return(false);
            }
            ua /= denom;
            ub /= denom;

            if ((0 < ua) && (ua < 1) && (0 < ub) && (ub < 1))
            {
                intersectionPoint.X = (x1 + ua * (x2 - x1));
                intersectionPoint.Y = (y1 + ua * (y2 - y1));
                return(true);
            }

            return(false);
        }
Esempio n. 24
0
 private static float VecCross(FVector2 a, FVector2 b)
 {
     return(a.X * b.Y - a.Y * b.X);
 }
Esempio n. 25
0
        /** Look-up table to relate polygon key with the vertices that should be used for
         *  the sub polygon in marching squares
         **/

        /** Perform a single celled marching square for for the given cell defined by (x0,y0) (x1,y1)
         *  using the function f for recursive interpolation, given the look-up table 'fs' of
         *  the values of 'f' at cell vertices with the result to be stored in 'poly' given the actual
         *  coordinates of 'ax' 'ay' in the marching squares mesh.
         **/

        private static int MarchSquare(sbyte[,] f, sbyte[,] fs, ref GeomPoly poly, int ax, int ay, float x0, float y0,
                                       float x1, float y1, int bin)
        {
            //key lookup
            int   key = 0;
            sbyte v0  = fs[ax, ay];

            if (v0 < 0)
            {
                key |= 8;
            }
            sbyte v1 = fs[ax + 1, ay];

            if (v1 < 0)
            {
                key |= 4;
            }
            sbyte v2 = fs[ax + 1, ay + 1];

            if (v2 < 0)
            {
                key |= 2;
            }
            sbyte v3 = fs[ax, ay + 1];

            if (v3 < 0)
            {
                key |= 1;
            }

            int val = _lookMarch[key];

            if (val != 0)
            {
                CxFastListNode <FVector2> pi = null;
                for (int i = 0; i < 8; i++)
                {
                    FVector2 p;
                    if ((val & (1 << i)) != 0)
                    {
                        if (i == 7 && (val & 1) == 0)
                        {
                            poly.Points.Add(p = new FVector2(x0, Ylerp(y0, y1, x0, v0, v3, f, bin)));
                        }
                        else
                        {
                            if (i == 0)
                            {
                                p = new FVector2(x0, y0);
                            }
                            else if (i == 2)
                            {
                                p = new FVector2(x1, y0);
                            }
                            else if (i == 4)
                            {
                                p = new FVector2(x1, y1);
                            }
                            else if (i == 6)
                            {
                                p = new FVector2(x0, y1);
                            }

                            else if (i == 1)
                            {
                                p = new FVector2(Xlerp(x0, x1, y0, v0, v1, f, bin), y0);
                            }
                            else if (i == 5)
                            {
                                p = new FVector2(Xlerp(x0, x1, y1, v3, v2, f, bin), y1);
                            }

                            else if (i == 3)
                            {
                                p = new FVector2(x1, Ylerp(y0, y1, x1, v1, v2, f, bin));
                            }
                            else
                            {
                                p = new FVector2(x0, Ylerp(y0, y1, x0, v0, v3, f, bin));
                            }

                            pi = poly.Points.Insert(pi, p);
                        }
                        poly.Length++;
                    }
                }
                //poly.simplify(float.Epsilon,float.Epsilon);
            }
            return(key);
        }
Esempio n. 26
0
        /// <summary>
        /// Function to search for an entrance point of a hole in a polygon. It searches the polygon from top to bottom between the polygon edges.
        /// </summary>
        /// <param name="polygon">The polygon to search in.</param>
        /// <param name="lastHoleEntrance">The last entrance point.</param>
        /// <returns>The next holes entrance point. Null if ther are no holes.</returns>
        private FVector2?SearchHoleEntrance(Vertices polygon, FVector2?lastHoleEntrance)
        {
            if (polygon == null)
            {
                throw new ArgumentNullException("'polygon' can't be null.");
            }

            if (polygon.Count < 3)
            {
                throw new ArgumentException("'polygon.MainPolygon.Count' can't be less then 3.");
            }


            List <float> xCoords;
            FVector2?    entrance;

            int startY;
            int endY;

            int  lastSolid = 0;
            bool foundSolid;
            bool foundTransparent;

            // Set start y coordinate.
            if (lastHoleEntrance.HasValue)
            {
                // We need the y coordinate only.
                startY = (int)lastHoleEntrance.Value.Y;
            }
            else
            {
                // Start from the top of the polygon if last entrance == null.
                startY = (int)GetTopMostCoord(polygon);
            }

            // Set the end y coordinate.
            endY = (int)GetBottomMostCoord(polygon);

            if (startY > 0 && startY < _height && endY > 0 && endY < _height)
            {
                // go from top to bottom of the polygon
                for (int y = startY; y <= endY; y++)
                {
                    // get x-coord of every polygon edge which crosses y
                    xCoords = SearchCrossingEdges(polygon, y);

                    // We need an even number of crossing edges.
                    // It's always a pair of start and end edge: nothing | polygon | hole | polygon | nothing ...
                    // If it's not then don't bother, it's probably a peak ...
                    // ...which should be filtered out by SearchCrossingEdges() anyway.
                    if (xCoords.Count > 1 && xCoords.Count % 2 == 0)
                    {
                        // Ok, this is short, but probably a little bit confusing.
                        // This part searches from left to right between the edges inside the polygon.
                        // The problem: We are using the polygon data to search in the texture data.
                        // That's simply not accurate, but necessary because of performance.
                        for (int i = 0; i < xCoords.Count; i += 2)
                        {
                            foundSolid       = false;
                            foundTransparent = false;

                            // We search between the edges inside the polygon.
                            for (int x = (int)xCoords[i]; x <= (int)xCoords[i + 1]; x++)
                            {
                                // First pass: IsSolid might return false.
                                // In that case the polygon edge doesn't lie on the texture's solid pixel, because of the hull tolearance.
                                // If the edge lies before the first solid pixel then we need to skip our transparent pixel finds.

                                // The algorithm starts to search for a relevant transparent pixel (which indicates a possible hole)
                                // after it has found a solid pixel.

                                // After we've found a solid and a transparent pixel (a hole's left edge)
                                // we search for a solid pixel again (a hole's right edge).
                                // When found the distance of that coodrinate has to be greater then the hull tolerance.

                                if (IsSolid(ref x, ref y))
                                {
                                    if (!foundTransparent)
                                    {
                                        foundSolid = true;
                                        lastSolid  = x;
                                    }

                                    if (foundSolid && foundTransparent)
                                    {
                                        entrance = new FVector2(lastSolid, y);

                                        if (DistanceToHullAcceptable(polygon, entrance.Value, true))
                                        {
                                            return(entrance);
                                        }

                                        entrance = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    if (foundSolid)
                                    {
                                        foundTransparent = true;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (xCoords.Count % 2 == 0)
                        {
                            Debug.WriteLine("SearchCrossingEdges() % 2 != 0");
                        }
                    }
                }
            }

            return(null);
        }
Esempio n. 27
0
        /** Used in polygon composition to composit polygons into scan lines
         *  Combining polya and polyb into one super-polygon stored in polya.
         **/

        private static void combLeft(ref GeomPoly polya, ref GeomPoly polyb)
        {
            CxFastList <FVector2>     ap = polya.Points;
            CxFastList <FVector2>     bp = polyb.Points;
            CxFastListNode <FVector2> ai = ap.Begin();
            CxFastListNode <FVector2> bi = bp.Begin();

            FVector2 b = bi.Elem();
            CxFastListNode <FVector2> prea = null;

            while (ai != ap.End())
            {
                FVector2 a = ai.Elem();
                if (VecDsq(a, b) < Box2D.Settings.b2_epsilon)
                {
                    //ignore shared vertex if parallel
                    if (prea != null)
                    {
                        FVector2 a0 = prea.Elem();
                        b = bi.Next().Elem();

                        FVector2 u = a - a0;
                        //vec_new(u); vec_sub(a.p.p, a0.p.p, u);
                        FVector2 v = b - a;
                        //vec_new(v); vec_sub(b.p.p, a.p.p, v);
                        float dot = VecCross(u, v);
                        if (dot * dot < Box2D.Settings.b2_epsilon)
                        {
                            ap.Erase(prea, ai);
                            polya.Length--;
                            ai = prea;
                        }
                    }

                    //insert polyb into polya
                    bool fst = true;
                    CxFastListNode <FVector2> preb = null;
                    while (!bp.Empty())
                    {
                        FVector2 bb = bp.Front();
                        bp.Pop();
                        if (!fst && !bp.Empty())
                        {
                            ai = ap.Insert(ai, bb);
                            polya.Length++;
                            preb = ai;
                        }
                        fst = false;
                    }

                    //ignore shared vertex if parallel
                    ai = ai.Next();
                    FVector2 a1 = ai.Elem();
                    ai = ai.Next();
                    if (ai == ap.End())
                    {
                        ai = ap.Begin();
                    }
                    FVector2 a2  = ai.Elem();
                    FVector2 a00 = preb.Elem();
                    FVector2 uu  = a1 - a00;
                    //vec_new(u); vec_sub(a1.p, a0.p, u);
                    FVector2 vv = a2 - a1;
                    //vec_new(v); vec_sub(a2.p, a1.p, v);
                    float dot1 = VecCross(uu, vv);
                    if (dot1 * dot1 < Box2D.Settings.b2_epsilon)
                    {
                        ap.Erase(preb, preb.Next());
                        polya.Length--;
                    }

                    return;
                }
                prea = ai;
                ai   = ai.Next();
            }
        }
Esempio n. 28
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);
        }
Esempio n. 29
0
        //Cutting a shape into two is based on the work of Daid and his prototype BoxCutter: http://www.box2d.org/forum/viewtopic.php?f=3&t=1473

        /// <summary>
        /// Split a fixture into 2 vertice collections using the given entry and exit-point.
        /// </summary>
        /// <param name="fixture">The Fixture to split</param>
        /// <param name="entryPoint">The entry point - The start point</param>
        /// <param name="exitPoint">The exit point - The end point</param>
        /// <param name="splitSize">The size of the split. Think of this as the laser-width</param>
        /// <param name="first">The first collection of vertexes</param>
        /// <param name="second">The second collection of vertexes</param>
        public static void SplitShape(Box2D.Fixture fixture, FVector2 entryPoint, FVector2 exitPoint, float splitSize,
                                      out Vertices first, out Vertices second)
        {
            /*
             * FVector2 localEntryPoint = fixture.GetBody().GetLocalPoint(ref entryPoint);
             * FVector2 localExitPoint = fixture.Body.GetLocalPoint(ref exitPoint);
             *
             * Box2D.PolygonShape shape = fixture.GetShape() as Box2D.PolygonShape;
             *
             * if (shape == null)
             * {
             *  first = new Vertices();
             *  second = new Vertices();
             *  return;
             * }
             *
             * Vertices vertices = new Vertices(shape.GetVertex());
             * Vertices[] newPolygon = new Vertices[2];
             *
             * for (int i = 0; i < newPolygon.Length; i++)
             * {
             *  newPolygon[i] = new Vertices(vertices.Count);
             * }
             *
             * int[] cutAdded = { -1, -1 };
             * int last = -1;
             * for (int i = 0; i < vertices.Count; i++)
             * {
             *  int n;
             *  //Find out if this vertex is on the old or new shape.
             *  if (FVector2.Dot(MathUtils.Cross(localExitPoint - localEntryPoint, 1), vertices[i] - localEntryPoint) > Box2D.Settings.b2_epsilon)
             *      n = 0;
             *  else
             *      n = 1;
             *
             *  if (last != n)
             *  {
             *      //If we switch from one shape to the other add the cut vertices.
             *      if (last == 0)
             *      {
             *          Debug.Assert(cutAdded[0] == -1);
             *          cutAdded[0] = newPolygon[last].Count;
             *          newPolygon[last].Add(localExitPoint);
             *          newPolygon[last].Add(localEntryPoint);
             *      }
             *      if (last == 1)
             *      {
             *          Debug.Assert(cutAdded[last] == -1);
             *          cutAdded[last] = newPolygon[last].Count;
             *          newPolygon[last].Add(localEntryPoint);
             *          newPolygon[last].Add(localExitPoint);
             *      }
             *  }
             *
             *  newPolygon[n].Add(vertices[i]);
             *  last = n;
             * }
             *
             * //Add the cut in case it has not been added yet.
             * if (cutAdded[0] == -1)
             * {
             *  cutAdded[0] = newPolygon[0].Count;
             *  newPolygon[0].Add(localExitPoint);
             *  newPolygon[0].Add(localEntryPoint);
             * }
             * if (cutAdded[1] == -1)
             * {
             *  cutAdded[1] = newPolygon[1].Count;
             *  newPolygon[1].Add(localEntryPoint);
             *  newPolygon[1].Add(localExitPoint);
             * }
             *
             * for (int n = 0; n < 2; n++)
             * {
             *  FVector2 offset;
             *  if (cutAdded[n] > 0)
             *  {
             *      offset = (newPolygon[n][cutAdded[n] - 1] - newPolygon[n][cutAdded[n]]);
             *  }
             *  else
             *  {
             *      offset = (newPolygon[n][newPolygon[n].Count - 1] - newPolygon[n][0]);
             *  }
             *  offset.Normalize();
             *
             *  newPolygon[n][cutAdded[n]] += splitSize * offset;
             *
             *  if (cutAdded[n] < newPolygon[n].Count - 2)
             *  {
             *      offset = (newPolygon[n][cutAdded[n] + 2] - newPolygon[n][cutAdded[n] + 1]);
             *  }
             *  else
             *  {
             *      offset = (newPolygon[n][0] - newPolygon[n][newPolygon[n].Count - 1]);
             *  }
             *  offset.Normalize();
             *
             *  newPolygon[n][cutAdded[n] + 1] += splitSize * offset;
             * }
             */
            first  = null; // newPolygon[0];
            second = null; // newPolygon[1];
        }
Esempio n. 30
0
        private bool SplitPolygonEdge(Vertices polygon, FVector2 coordInsideThePolygon,
                                      out int vertex1Index, out int vertex2Index)
        {
            FVector2 slope;
            int      nearestEdgeVertex1Index = 0;
            int      nearestEdgeVertex2Index = 0;
            bool     edgeFound = false;

            float shortestDistance = float.MaxValue;

            bool     edgeCoordFound = false;
            FVector2 foundEdgeCoord = FVector2.Zero;

            List <float> xCoords = SearchCrossingEdges(polygon, (int)coordInsideThePolygon.Y);

            vertex1Index = 0;
            vertex2Index = 0;

            foundEdgeCoord.Y = coordInsideThePolygon.Y;

            if (xCoords != null && xCoords.Count > 1 && xCoords.Count % 2 == 0)
            {
                float distance;
                for (int i = 0; i < xCoords.Count; i++)
                {
                    if (xCoords[i] < coordInsideThePolygon.X)
                    {
                        distance = coordInsideThePolygon.X - xCoords[i];

                        if (distance < shortestDistance)
                        {
                            shortestDistance = distance;
                            foundEdgeCoord.X = xCoords[i];

                            edgeCoordFound = true;
                        }
                    }
                }

                if (edgeCoordFound)
                {
                    shortestDistance = float.MaxValue;

                    int edgeVertex2Index = polygon.Count - 1;

                    int edgeVertex1Index;
                    for (edgeVertex1Index = 0; edgeVertex1Index < polygon.Count; edgeVertex1Index++)
                    {
                        FVector2 tempVector1 = polygon[edgeVertex1Index];
                        FVector2 tempVector2 = polygon[edgeVertex2Index];
                        distance = LineTools.DistanceBetweenPointAndLineSegment(ref foundEdgeCoord,
                                                                                ref tempVector1, ref tempVector2);
                        if (distance < shortestDistance)
                        {
                            shortestDistance = distance;

                            nearestEdgeVertex1Index = edgeVertex1Index;
                            nearestEdgeVertex2Index = edgeVertex2Index;

                            edgeFound = true;
                        }

                        edgeVertex2Index = edgeVertex1Index;
                    }

                    if (edgeFound)
                    {
                        slope = polygon[nearestEdgeVertex2Index] - polygon[nearestEdgeVertex1Index];
                        slope.Normalize();

                        FVector2 tempVector = polygon[nearestEdgeVertex1Index];
                        distance = LineTools.DistanceBetweenPointAndPoint(ref tempVector, ref foundEdgeCoord);

                        vertex1Index = nearestEdgeVertex1Index;
                        vertex2Index = nearestEdgeVertex1Index + 1;

                        polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex1Index]);
                        polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex2Index]);

                        return(true);
                    }
                }
            }

            return(false);
        }