예제 #1
0
        private static void SetPointsFromContactPointsAndVertices(Polygon polygon, Polygon otherPolygon, List<ContactPoint> contactPoints, int polygonPointToStartAt, List<Vector3> thisVertices, List<Vector3> otherVertices)
        {
            Polygon currentPolygon = polygon;

            List<Vector3> newPolygonPoints = new List<Vector3>();
            int otherIndex = 0;
            int otherIndexToStartAt = -1;
            int thisIndex = polygonPointToStartAt;
            while (true)
            {
                if (newPolygonPoints.Count > 3 * (polygon.Points.Count + otherPolygon.Points.Count))
                {
                    // just break here for now
                    break;
                }

                bool isThereAContactPoint = false;

                if (currentPolygon == polygon)
                {
                    
                    newPolygonPoints.Add(thisVertices[thisIndex]);
                    isThereAContactPoint = DoesContactPointsHaveThisIndex(thisIndex, contactPoints);
                }
                else
                {
                    newPolygonPoints.Add(otherVertices[otherIndex]);
                    isThereAContactPoint = DoesContactPointsHaveOtherIndex(otherIndex, contactPoints);
                }

                if (isThereAContactPoint)
                {
                    ContactPoint cp = new ContactPoint();
                    if (currentPolygon == polygon)
                    {
                        cp = GetContactPointAtThisIndex(thisIndex, contactPoints, thisVertices[thisIndex]);
                    }
                    else
                    {
                        cp = GetContactPointAtOtherIndex(otherIndex, contactPoints, otherVertices[otherIndex]);
                    }

                    #region If it's a segment intersection, drop the point and swap the current polygon

                    if (cp.ContactType == ContactType.SegmentIntersection)
                    {

                        if (currentPolygon == polygon)
                        {
                            currentPolygon = otherPolygon;
                            otherIndex = cp.OtherIndex + 1;

                            if (otherIndex == otherVertices.Count - 1)
                            {
                                otherIndex = 0;
                            }
                            if (otherIndex == otherIndexToStartAt)
                            {
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }

                            if (otherIndexToStartAt == -1)
                            {
                                otherIndexToStartAt = otherIndex;
                            }
                        }
                        else
                        {
                            currentPolygon = polygon;
                            thisIndex = cp.ThisIndex + 1;

                            if (thisIndex == polygon.Points.Count - 1)
                            {
                                thisIndex = 0;
                            }
                            if (thisIndex == polygonPointToStartAt)
                            {
                                // close off the polygon and stop adding points
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }
                        }

                        newPolygonPoints.Add(cp.Position);


                    }
                    #endregion
                    
                    else if(cp.ContactType == ContactType.PointOnSegment)
                    {
                        // See which next point is the furthest away, and decide based off of that.

                        int nextOtherIndex = cp.OtherIndex + 1;
                        if (cp.OtherEndpoint != -1)
                        {
                            nextOtherIndex = cp.OtherEndpoint + 1;
                        }
                        if (nextOtherIndex >= otherVertices.Count - 1)
                        {
                            nextOtherIndex -= (otherVertices.Count - 1);
                        }


                        int nextThisIndex = cp.ThisIndex + 1;
                        if (cp.ThisEndpoint != -1)
                        {
                            nextThisIndex = cp.ThisEndpoint + 1;
                        }
                        if (nextThisIndex >= thisVertices.Count - 1)
                        {
                            nextThisIndex -= (thisVertices.Count - 1);
                        }

                        Vector3 nextThisVector = thisVertices[nextThisIndex] - cp.Position;
                        Vector3 nextOtherVector = otherVertices[nextOtherIndex] - cp.Position;
                        double distanceAwayFromThis = 0;
                        double distanceAwayFromOther = 0;

                        bool doWhile = true;

                        int numberOfExtraDoWhiles = 0;

                        int thisIndexBeforeDoWhile = nextThisIndex;
                        int otherIndexBeforeDoWhile = nextOtherIndex;

                        // The doWhile section will find out which path will take us
                        // furtest away from the other Polygon.  This works most of the time
                        // but in some cases (like if the initial two paths are parallel), we'll
                        // want to special case which we use
                        bool forceUseThis = false;
                        bool forceUseOther = false;

                        while (doWhile)
                        {

                            if (nextThisVector.Length() < .0001f)
                            {
                                nextThisIndex++;
                                if (nextThisIndex == thisVertices.Count - 1)
                                {
                                    nextThisIndex = 0;
                                }
                                nextThisVector = thisVertices[nextThisIndex] - cp.Position;
                            }

                            if (nextOtherVector.Length() < .0001f)
                            {
                                nextOtherIndex++;
                                if (nextOtherIndex == otherVertices.Count - 1)
                                {
                                    nextOtherIndex = 0;
                                }
                                nextOtherVector = otherVertices[nextOtherIndex] - cp.Position;
                            }

                            float thisVectorLength = nextThisVector.Length();
                            float otherVectorLength = nextOtherVector.Length();

                            float smallestDistance = System.Math.Min(thisVectorLength, otherVectorLength);

                            nextThisVector.Normalize();
                            nextOtherVector.Normalize();

                            nextThisVector *= smallestDistance / 2.0f;
                            nextOtherVector *= smallestDistance / 2.0f;

                            nextThisVector += cp.Position;
                            nextOtherVector += cp.Position;

                            if (nextThisVector == nextOtherVector)
                            {

                                forceUseThis = thisVectorLength < otherVectorLength;
                                forceUseOther = !forceUseThis;

                                break;
                            }



                            double minimumDistance = .00001;

                            if (polygon.IsPointInside(ref nextOtherVector))
                            {
                                distanceAwayFromThis = 0;
                            }
                            else
                            {
                                distanceAwayFromThis = polygon.VectorFrom(nextOtherVector.X, nextOtherVector.Y).Length();

                                if (distanceAwayFromThis < minimumDistance)
                                {
                                    distanceAwayFromThis = 0;
                                }
                            }

                            if (otherPolygon.IsPointInside(ref nextThisVector))
                            {
                                distanceAwayFromOther = 0;
                            }
                            else
                            {
                                distanceAwayFromOther = otherPolygon.VectorFrom(nextThisVector.X, nextThisVector.Y).Length();

                                if (distanceAwayFromOther < minimumDistance)
                                {
                                    distanceAwayFromOther = 0;
                                }
                            }

                            if (distanceAwayFromOther == distanceAwayFromThis)
                            {
                                // We need a tiebreaker.  Let's move an extra index and see what happens, shall we?
                                nextThisIndex++;
                                if (nextThisIndex == thisVertices.Count - 1)
                                {
                                    nextThisIndex = 0;
                                }
                                nextThisVector = thisVertices[nextThisIndex] - cp.Position;

                                nextOtherIndex++;
                                if (nextOtherIndex == otherVertices.Count - 1)
                                {
                                    nextOtherIndex = 0;
                                }
                                nextOtherVector = otherVertices[nextOtherIndex] - cp.Position;

                                numberOfExtraDoWhiles++;
                            }
                            else
                            {
                                doWhile = false;
                            }
                        }

                        nextThisIndex = thisIndexBeforeDoWhile;
                        nextOtherIndex = otherIndexBeforeDoWhile;

                        bool useThis = distanceAwayFromThis < distanceAwayFromOther;

                        if (forceUseThis)
                            useThis = true;
                        else if (forceUseOther)
                            useThis = false;

                        if (useThis && currentPolygon == polygon)
                        {
                            // make sure there are no other contact points on the current segment on this
                            for (int i = 0; i < contactPoints.Count; i++)
                            {
                                ContactPoint otherCp = contactPoints[i];

                                if (otherCp.Position != cp.Position && otherCp.ThisIndex == cp.ThisIndex)
                                {
                                    useThis = false;
                                    break;
                                }
                            }
                        }

                        else if (!useThis && currentPolygon == otherPolygon)
                        {
                            // make sure there are no other contact points on the current segment on this
                            for (int i = 0; i < contactPoints.Count; i++)
                            {
                                ContactPoint otherCp = contactPoints[i];

                                if (otherCp.Position != cp.Position && otherCp.OtherIndex == cp.OtherIndex)
                                {
                                    useThis = true;
                                    break;
                                }
                            }
                        }

                        newPolygonPoints.Add(cp.Position);

                        if (distanceAwayFromThis == distanceAwayFromOther)
                        {
                            useThis = currentPolygon == polygon;

                        }
                        if (useThis)
                        {
                            currentPolygon = polygon;

                            thisIndex = nextThisIndex;

                            if (thisIndex == polygonPointToStartAt)
                            {
                                // close off the polygon and stop adding points
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }
                        }
                        else
                        {
                            currentPolygon = otherPolygon;

                            otherIndex = nextOtherIndex;

                            if (otherIndex == otherIndexToStartAt)
                            {
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }                            
                            
                            if (otherIndexToStartAt == -1)
                            {
                                otherIndexToStartAt = otherIndex;
                            }


                        }


                    }
                }
                else
                {
                    if (currentPolygon == polygon)
                    {

                        thisIndex++;
                        if (thisIndex == polygon.Points.Count - 1)
                        {
                            thisIndex = 0;
                        }
                        if (thisIndex == polygonPointToStartAt)
                        {
                            // close off the polygon and stop adding points
                            newPolygonPoints.Add(newPolygonPoints[0]);

                            break;
                        }
                    }
                    else
                    {
                        otherIndex++;
                        if (otherIndex == otherPolygon.Points.Count - 1)
                        {
                            otherIndex = 0;
                        }
                        if (otherIndex == otherIndexToStartAt)
                        {
                            // close off the polygon and stop adding points
                            newPolygonPoints.Add(newPolygonPoints[0]);

                            break;
                        }
                    }
                }
            }

            SetPolygonPoints(polygon, newPolygonPoints);
        }
예제 #2
0
        private static List<ContactPoint> GetContactPoints(Segment[] firstSegments, Segment[] secondSegments)
        {

            if (shouldEliminatePointOnEnd)
            {
                ShiftEndpointsToEliminatePointOnSegment(firstSegments, secondSegments);
            }


            Point intersectionPoint = new Point();
            List<ContactPoint> contactPoints = new List<ContactPoint>();

            Segment firstSegment = new Segment();
            Segment secondSegment = new Segment();
            const double allowedError = .0005;

            bool debug = false;

#if !SILVERLIGHT && !MONOGAME && !XBOX360 && !WINDOWS_PHONE
            if (debug)
            {
                FlatRedBall.Content.Polygon.PolygonSaveList psl = new FlatRedBall.Content.Polygon.PolygonSaveList();

                psl.PolygonSaves.Add(
                    FlatRedBall.Content.Polygon.PolygonSave.FromPolygon(
                        Polygon.FromSegments(firstSegments)));

                psl.PolygonSaves.Add(
                    FlatRedBall.Content.Polygon.PolygonSave.FromPolygon(
                        Polygon.FromSegments(secondSegments)));

                psl.Save(FlatRedBall.IO.FileManager.MyDocuments + "modifiedPolygons.plylstx");

            }
#endif

            #region Handle the two-parallel segment special case

            List<ContactPoint> parallelContactPoints = new List<ContactPoint>();

            for (int firstIndex = 0; firstIndex < firstSegments.Length; firstIndex++)
            {
                firstSegment = firstSegments[firstIndex];
                for (int secondIndex = 0; secondIndex < secondSegments.Length; secondIndex++)
                {
                    secondSegment = secondSegments[secondIndex];

                    Point parallelIntersectionPoint;

                    if (firstSegment.IsParallelAndTouching(secondSegment, out parallelIntersectionPoint))
                    {
                        ContactPoint cp = new ContactPoint();

                        cp.ThisIndex = firstIndex;
                        cp.OtherIndex = secondIndex;

                        // Technically this is a point on segment intersection,
                        // but we treat it like a segment intersection because we're
                        // going to eliminate duplicates
                        cp.ContactType = ContactType.SegmentIntersection;
                        cp.Position = new Vector3((float)parallelIntersectionPoint.X, (float)parallelIntersectionPoint.Y, 0);

                        parallelContactPoints.Add(cp);
                    }
                }
            }

            #endregion

            #region else, do regular intersection tests
            List<int> indexesToRemove = new List<int>();


            for (int firstSegmentIndex = 0; firstSegmentIndex < firstSegments.Length; firstSegmentIndex++)
            {
                firstSegment = firstSegments[firstSegmentIndex];

                for (int secondSegmentIndex = 0; secondSegmentIndex < secondSegments.Length; secondSegmentIndex++)
                {
                    secondSegment = secondSegments[secondSegmentIndex];

                    bool intersects = firstSegment.Intersects(secondSegment, out intersectionPoint);

                    if ( intersects ||
                        firstSegment.IsParallelAndTouching(secondSegment, out intersectionPoint))
                    {
                        ContactPoint cp = new ContactPoint();
                        cp.Position = new Vector3((float)intersectionPoint.X, (float)intersectionPoint.Y, 0);
                        cp.ThisIndex = firstSegmentIndex;
                        cp.OtherIndex = secondSegmentIndex;

                        cp.ThisEndpoint = -1;
                        cp.OtherEndpoint = -1;

                        if(intersectionPoint.EqualdWithin(firstSegment.Point1, allowedError))
                        {
                            cp.ThisEndpoint = firstSegmentIndex;
                        }
                        else if(intersectionPoint.EqualdWithin(firstSegment.Point2, allowedError))
                        {
                            cp.ThisEndpoint = firstSegmentIndex + 1;
                        }
                        else if(intersectionPoint.EqualdWithin(secondSegment.Point1, allowedError))
                        {
                            cp.OtherEndpoint = secondSegmentIndex;
                        }
                        else if(intersectionPoint.EqualdWithin(secondSegment.Point2, allowedError))
                        {
                            cp.OtherEndpoint = secondSegmentIndex + 1;
                        }

                        if (!intersects ||
                             cp.ThisEndpoint != -1 ||
                            cp.OtherEndpoint != -1
                            )
                        {
                            if (shouldEliminatePointOnEnd)
                            {
                                throw new Exception();
                            }
                            cp.ContactType = ContactType.PointOnSegment;
                        }
                        else
                        {
                            cp.ContactType = ContactType.SegmentIntersection;
                        }

                        if (!intersects)
                        {
                            indexesToRemove.Add(contactPoints.Count);
                        }

                        contactPoints.Add(cp);
                    }
                }
            }

#if false // Not sure why this is here, but it causes warnings and we don't use it
            if (false && parallelContactPoints.Count == 2)
            {
                const float minimumLength = .01f;

                bool isParallelContactPoint = false;
                for (int i = 0; i < contactPoints.Count; i++)
                {
                    float closestToPair = float.PositiveInfinity;

                    Vector3 position = contactPoints[i].Position;

                    for (int parallelIndex = 0; parallelIndex < parallelContactPoints.Count; parallelIndex++)
                    {
                        Segment segment1 = firstSegments[parallelContactPoints[parallelIndex].ThisIndex];
                        Segment segment2 = secondSegments[parallelContactPoints[parallelIndex].OtherIndex];

                        float firstDistance = segment1.DistanceTo(position.X, position.Y);
                        float secondDistance = segment2.DistanceTo(position.X, position.Y);

                        float furthestAway = System.Math.Max(firstDistance, secondDistance);

                        closestToPair = System.Math.Min(furthestAway, closestToPair);
                    }

                    if (closestToPair > minimumLength)
                    {
                        isParallelContactPoint = true;
                        break;
                    }
                }

                if (!isParallelContactPoint)
                {
                    return parallelContactPoints;
                }
            }
#endif

            int numberKilled = 0;

            List<int> intersectionIndexes = new List<int>();

            for (int i = 0; i < firstSegments.Length; i++)
            {
                intersectionIndexes.Clear();

                for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++)
                {
                    if (contactPoints[cpIndex].ThisIndex == i)
                    {
                        intersectionIndexes.Add(cpIndex);
                    }
                }

                if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1)
                {
                    contactPoints.RemoveAt(intersectionIndexes[1]);
                }
            }

            for (int i = 0; i < secondSegments.Length; i++)
            {
                intersectionIndexes.Clear();

                for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++)
                {
                    if (contactPoints[cpIndex].OtherIndex == i)
                    {
                        intersectionIndexes.Add(cpIndex);
                    }
                }

                if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1)
                {
                    contactPoints.RemoveAt(intersectionIndexes[1]);
                }
            }


            // See if any contact points are the same.  If so, kill them
            for (int firstCP = 0; firstCP < contactPoints.Count - 1; firstCP++)
            {
                for (int secondCP = 1; secondCP < contactPoints.Count; secondCP++)
                {
                    if (firstCP == secondCP)
                    {
                        continue;
                    }

                    float distanceApart = (contactPoints[firstCP].Position - contactPoints[secondCP].Position).Length();

                    if (distanceApart < .002)
                    {
                        contactPoints.RemoveAt(secondCP);
                        firstCP = -1; // start over.
                        numberKilled++;
                        break;
                    }
                }
            }

            if (contactPoints.Count == 1)
            {
                // Is this bad?  What do we do?
                //int m = 3;
            }

            if (contactPoints.Count % 2 != 0 && contactPoints.Count > 1)
            {
                // Oh, no, an odd number of contact points?  Let's kill the closest pair

                ReactToOddContactPointCount(contactPoints);
            }
            #endregion

            return contactPoints;
        }
예제 #3
0
        private static void SetPointsFromContactPointsAndVertices(Polygon polygon, Polygon otherPolygon, List <ContactPoint> contactPoints, int polygonPointToStartAt, List <Vector3> thisVertices, List <Vector3> otherVertices)
        {
            Polygon currentPolygon = polygon;

            List <Vector3> newPolygonPoints    = new List <Vector3>();
            int            otherIndex          = 0;
            int            otherIndexToStartAt = -1;
            int            thisIndex           = polygonPointToStartAt;

            while (true)
            {
                if (newPolygonPoints.Count > 3 * (polygon.Points.Count + otherPolygon.Points.Count))
                {
                    // just break here for now
                    break;
                }

                bool isThereAContactPoint = false;

                if (currentPolygon == polygon)
                {
                    newPolygonPoints.Add(thisVertices[thisIndex]);
                    isThereAContactPoint = DoesContactPointsHaveThisIndex(thisIndex, contactPoints);
                }
                else
                {
                    newPolygonPoints.Add(otherVertices[otherIndex]);
                    isThereAContactPoint = DoesContactPointsHaveOtherIndex(otherIndex, contactPoints);
                }

                if (isThereAContactPoint)
                {
                    ContactPoint cp = new ContactPoint();
                    if (currentPolygon == polygon)
                    {
                        cp = GetContactPointAtThisIndex(thisIndex, contactPoints, thisVertices[thisIndex]);
                    }
                    else
                    {
                        cp = GetContactPointAtOtherIndex(otherIndex, contactPoints, otherVertices[otherIndex]);
                    }

                    #region If it's a segment intersection, drop the point and swap the current polygon

                    if (cp.ContactType == ContactType.SegmentIntersection)
                    {
                        if (currentPolygon == polygon)
                        {
                            currentPolygon = otherPolygon;
                            otherIndex     = cp.OtherIndex + 1;

                            if (otherIndex == otherVertices.Count - 1)
                            {
                                otherIndex = 0;
                            }
                            if (otherIndex == otherIndexToStartAt)
                            {
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }

                            if (otherIndexToStartAt == -1)
                            {
                                otherIndexToStartAt = otherIndex;
                            }
                        }
                        else
                        {
                            currentPolygon = polygon;
                            thisIndex      = cp.ThisIndex + 1;

                            if (thisIndex == polygon.Points.Count - 1)
                            {
                                thisIndex = 0;
                            }
                            if (thisIndex == polygonPointToStartAt)
                            {
                                // close off the polygon and stop adding points
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }
                        }

                        newPolygonPoints.Add(cp.Position);
                    }
                    #endregion

                    else if (cp.ContactType == ContactType.PointOnSegment)
                    {
                        // See which next point is the furthest away, and decide based off of that.

                        int nextOtherIndex = cp.OtherIndex + 1;
                        if (cp.OtherEndpoint != -1)
                        {
                            nextOtherIndex = cp.OtherEndpoint + 1;
                        }
                        if (nextOtherIndex >= otherVertices.Count - 1)
                        {
                            nextOtherIndex -= (otherVertices.Count - 1);
                        }


                        int nextThisIndex = cp.ThisIndex + 1;
                        if (cp.ThisEndpoint != -1)
                        {
                            nextThisIndex = cp.ThisEndpoint + 1;
                        }
                        if (nextThisIndex >= thisVertices.Count - 1)
                        {
                            nextThisIndex -= (thisVertices.Count - 1);
                        }

                        Vector3 nextThisVector        = thisVertices[nextThisIndex] - cp.Position;
                        Vector3 nextOtherVector       = otherVertices[nextOtherIndex] - cp.Position;
                        double  distanceAwayFromThis  = 0;
                        double  distanceAwayFromOther = 0;

                        bool doWhile = true;

                        int numberOfExtraDoWhiles = 0;

                        int thisIndexBeforeDoWhile  = nextThisIndex;
                        int otherIndexBeforeDoWhile = nextOtherIndex;

                        // The doWhile section will find out which path will take us
                        // furtest away from the other Polygon.  This works most of the time
                        // but in some cases (like if the initial two paths are parallel), we'll
                        // want to special case which we use
                        bool forceUseThis  = false;
                        bool forceUseOther = false;

                        while (doWhile)
                        {
                            if (nextThisVector.Length() < .0001f)
                            {
                                nextThisIndex++;
                                if (nextThisIndex == thisVertices.Count - 1)
                                {
                                    nextThisIndex = 0;
                                }
                                nextThisVector = thisVertices[nextThisIndex] - cp.Position;
                            }

                            if (nextOtherVector.Length() < .0001f)
                            {
                                nextOtherIndex++;
                                if (nextOtherIndex == otherVertices.Count - 1)
                                {
                                    nextOtherIndex = 0;
                                }
                                nextOtherVector = otherVertices[nextOtherIndex] - cp.Position;
                            }

                            float thisVectorLength  = nextThisVector.Length();
                            float otherVectorLength = nextOtherVector.Length();

                            float smallestDistance = System.Math.Min(thisVectorLength, otherVectorLength);

                            nextThisVector.Normalize();
                            nextOtherVector.Normalize();

                            nextThisVector  *= smallestDistance / 2.0f;
                            nextOtherVector *= smallestDistance / 2.0f;

                            nextThisVector  += cp.Position;
                            nextOtherVector += cp.Position;

                            if (nextThisVector == nextOtherVector)
                            {
                                forceUseThis  = thisVectorLength < otherVectorLength;
                                forceUseOther = !forceUseThis;

                                break;
                            }



                            double minimumDistance = .00001;

                            if (polygon.IsPointInside(ref nextOtherVector))
                            {
                                distanceAwayFromThis = 0;
                            }
                            else
                            {
                                distanceAwayFromThis = polygon.VectorFrom(nextOtherVector.X, nextOtherVector.Y).Length();

                                if (distanceAwayFromThis < minimumDistance)
                                {
                                    distanceAwayFromThis = 0;
                                }
                            }

                            if (otherPolygon.IsPointInside(ref nextThisVector))
                            {
                                distanceAwayFromOther = 0;
                            }
                            else
                            {
                                distanceAwayFromOther = otherPolygon.VectorFrom(nextThisVector.X, nextThisVector.Y).Length();

                                if (distanceAwayFromOther < minimumDistance)
                                {
                                    distanceAwayFromOther = 0;
                                }
                            }

                            if (distanceAwayFromOther == distanceAwayFromThis)
                            {
                                // We need a tiebreaker.  Let's move an extra index and see what happens, shall we?
                                nextThisIndex++;
                                if (nextThisIndex == thisVertices.Count - 1)
                                {
                                    nextThisIndex = 0;
                                }
                                nextThisVector = thisVertices[nextThisIndex] - cp.Position;

                                nextOtherIndex++;
                                if (nextOtherIndex == otherVertices.Count - 1)
                                {
                                    nextOtherIndex = 0;
                                }
                                nextOtherVector = otherVertices[nextOtherIndex] - cp.Position;

                                numberOfExtraDoWhiles++;
                            }
                            else
                            {
                                doWhile = false;
                            }
                        }

                        nextThisIndex  = thisIndexBeforeDoWhile;
                        nextOtherIndex = otherIndexBeforeDoWhile;

                        bool useThis = distanceAwayFromThis < distanceAwayFromOther;

                        if (forceUseThis)
                        {
                            useThis = true;
                        }
                        else if (forceUseOther)
                        {
                            useThis = false;
                        }

                        if (useThis && currentPolygon == polygon)
                        {
                            // make sure there are no other contact points on the current segment on this
                            for (int i = 0; i < contactPoints.Count; i++)
                            {
                                ContactPoint otherCp = contactPoints[i];

                                if (otherCp.Position != cp.Position && otherCp.ThisIndex == cp.ThisIndex)
                                {
                                    useThis = false;
                                    break;
                                }
                            }
                        }

                        else if (!useThis && currentPolygon == otherPolygon)
                        {
                            // make sure there are no other contact points on the current segment on this
                            for (int i = 0; i < contactPoints.Count; i++)
                            {
                                ContactPoint otherCp = contactPoints[i];

                                if (otherCp.Position != cp.Position && otherCp.OtherIndex == cp.OtherIndex)
                                {
                                    useThis = true;
                                    break;
                                }
                            }
                        }

                        newPolygonPoints.Add(cp.Position);

                        if (distanceAwayFromThis == distanceAwayFromOther)
                        {
                            useThis = currentPolygon == polygon;
                        }
                        if (useThis)
                        {
                            currentPolygon = polygon;

                            thisIndex = nextThisIndex;

                            if (thisIndex == polygonPointToStartAt)
                            {
                                // close off the polygon and stop adding points
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }
                        }
                        else
                        {
                            currentPolygon = otherPolygon;

                            otherIndex = nextOtherIndex;

                            if (otherIndex == otherIndexToStartAt)
                            {
                                newPolygonPoints.Add(newPolygonPoints[0]);
                                break;
                            }

                            if (otherIndexToStartAt == -1)
                            {
                                otherIndexToStartAt = otherIndex;
                            }
                        }
                    }
                }
                else
                {
                    if (currentPolygon == polygon)
                    {
                        thisIndex++;
                        if (thisIndex == polygon.Points.Count - 1)
                        {
                            thisIndex = 0;
                        }
                        if (thisIndex == polygonPointToStartAt)
                        {
                            // close off the polygon and stop adding points
                            newPolygonPoints.Add(newPolygonPoints[0]);

                            break;
                        }
                    }
                    else
                    {
                        otherIndex++;
                        if (otherIndex == otherPolygon.Points.Count - 1)
                        {
                            otherIndex = 0;
                        }
                        if (otherIndex == otherIndexToStartAt)
                        {
                            // close off the polygon and stop adding points
                            newPolygonPoints.Add(newPolygonPoints[0]);

                            break;
                        }
                    }
                }
            }

            SetPolygonPoints(polygon, newPolygonPoints);
        }
예제 #4
0
        private static ContactPoint GetContactPointAtOtherIndex(int index, List<ContactPoint> contactPoints, Vector3 closestPoint)
        {
            ContactPoint closestContact = new ContactPoint();

            float closestDistance = float.PositiveInfinity;


            for (int i = 0; i < contactPoints.Count; i++)
            {
                if (contactPoints[i].OtherIndex == index)
                {

                    float distanceSquared = (contactPoints[i].Position - closestPoint).LengthSquared();
                    if (distanceSquared < closestDistance)
                    {
                        closestContact = contactPoints[i];
                        closestDistance = distanceSquared;
                    }
                }
            }
            if (float.IsPositiveInfinity(closestDistance))
            {
                throw new Exception();
            }
            else
            {
                return closestContact;
            }
        }
예제 #5
0
        private static List <ContactPoint> GetContactPoints(Segment[] firstSegments, Segment[] secondSegments)
        {
            if (shouldEliminatePointOnEnd)
            {
                ShiftEndpointsToEliminatePointOnSegment(firstSegments, secondSegments);
            }


            Point intersectionPoint           = new Point();
            List <ContactPoint> contactPoints = new List <ContactPoint>();

            Segment      firstSegment  = new Segment();
            Segment      secondSegment = new Segment();
            const double allowedError  = .0005;

            bool debug = false;

#if !SILVERLIGHT && !MONOGAME && !XBOX360 && !WINDOWS_PHONE
            if (debug)
            {
                FlatRedBall.Content.Polygon.PolygonSaveList psl = new FlatRedBall.Content.Polygon.PolygonSaveList();

                psl.PolygonSaves.Add(
                    FlatRedBall.Content.Polygon.PolygonSave.FromPolygon(
                        Polygon.FromSegments(firstSegments)));

                psl.PolygonSaves.Add(
                    FlatRedBall.Content.Polygon.PolygonSave.FromPolygon(
                        Polygon.FromSegments(secondSegments)));

                psl.Save(FlatRedBall.IO.FileManager.MyDocuments + "modifiedPolygons.plylstx");
            }
#endif

            #region Handle the two-parallel segment special case

            List <ContactPoint> parallelContactPoints = new List <ContactPoint>();

            for (int firstIndex = 0; firstIndex < firstSegments.Length; firstIndex++)
            {
                firstSegment = firstSegments[firstIndex];
                for (int secondIndex = 0; secondIndex < secondSegments.Length; secondIndex++)
                {
                    secondSegment = secondSegments[secondIndex];

                    Point parallelIntersectionPoint;

                    if (firstSegment.IsParallelAndTouching(secondSegment, out parallelIntersectionPoint))
                    {
                        ContactPoint cp = new ContactPoint();

                        cp.ThisIndex  = firstIndex;
                        cp.OtherIndex = secondIndex;

                        // Technically this is a point on segment intersection,
                        // but we treat it like a segment intersection because we're
                        // going to eliminate duplicates
                        cp.ContactType = ContactType.SegmentIntersection;
                        cp.Position    = new Vector3((float)parallelIntersectionPoint.X, (float)parallelIntersectionPoint.Y, 0);

                        parallelContactPoints.Add(cp);
                    }
                }
            }

            #endregion

            #region else, do regular intersection tests
            List <int> indexesToRemove = new List <int>();


            for (int firstSegmentIndex = 0; firstSegmentIndex < firstSegments.Length; firstSegmentIndex++)
            {
                firstSegment = firstSegments[firstSegmentIndex];

                for (int secondSegmentIndex = 0; secondSegmentIndex < secondSegments.Length; secondSegmentIndex++)
                {
                    secondSegment = secondSegments[secondSegmentIndex];

                    bool intersects = firstSegment.Intersects(secondSegment, out intersectionPoint);

                    if (intersects ||
                        firstSegment.IsParallelAndTouching(secondSegment, out intersectionPoint))
                    {
                        ContactPoint cp = new ContactPoint();
                        cp.Position   = new Vector3((float)intersectionPoint.X, (float)intersectionPoint.Y, 0);
                        cp.ThisIndex  = firstSegmentIndex;
                        cp.OtherIndex = secondSegmentIndex;

                        cp.ThisEndpoint  = -1;
                        cp.OtherEndpoint = -1;

                        if (intersectionPoint.EqualdWithin(firstSegment.Point1, allowedError))
                        {
                            cp.ThisEndpoint = firstSegmentIndex;
                        }
                        else if (intersectionPoint.EqualdWithin(firstSegment.Point2, allowedError))
                        {
                            cp.ThisEndpoint = firstSegmentIndex + 1;
                        }
                        else if (intersectionPoint.EqualdWithin(secondSegment.Point1, allowedError))
                        {
                            cp.OtherEndpoint = secondSegmentIndex;
                        }
                        else if (intersectionPoint.EqualdWithin(secondSegment.Point2, allowedError))
                        {
                            cp.OtherEndpoint = secondSegmentIndex + 1;
                        }

                        if (!intersects ||
                            cp.ThisEndpoint != -1 ||
                            cp.OtherEndpoint != -1
                            )
                        {
                            if (shouldEliminatePointOnEnd)
                            {
                                throw new Exception();
                            }
                            cp.ContactType = ContactType.PointOnSegment;
                        }
                        else
                        {
                            cp.ContactType = ContactType.SegmentIntersection;
                        }

                        if (!intersects)
                        {
                            indexesToRemove.Add(contactPoints.Count);
                        }

                        contactPoints.Add(cp);
                    }
                }
            }

#if false // Not sure why this is here, but it causes warnings and we don't use it
            if (false && parallelContactPoints.Count == 2)
            {
                const float minimumLength = .01f;

                bool isParallelContactPoint = false;
                for (int i = 0; i < contactPoints.Count; i++)
                {
                    float closestToPair = float.PositiveInfinity;

                    Vector3 position = contactPoints[i].Position;

                    for (int parallelIndex = 0; parallelIndex < parallelContactPoints.Count; parallelIndex++)
                    {
                        Segment segment1 = firstSegments[parallelContactPoints[parallelIndex].ThisIndex];
                        Segment segment2 = secondSegments[parallelContactPoints[parallelIndex].OtherIndex];

                        float firstDistance  = segment1.DistanceTo(position.X, position.Y);
                        float secondDistance = segment2.DistanceTo(position.X, position.Y);

                        float furthestAway = System.Math.Max(firstDistance, secondDistance);

                        closestToPair = System.Math.Min(furthestAway, closestToPair);
                    }

                    if (closestToPair > minimumLength)
                    {
                        isParallelContactPoint = true;
                        break;
                    }
                }

                if (!isParallelContactPoint)
                {
                    return(parallelContactPoints);
                }
            }
#endif

            int numberKilled = 0;

            List <int> intersectionIndexes = new List <int>();

            for (int i = 0; i < firstSegments.Length; i++)
            {
                intersectionIndexes.Clear();

                for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++)
                {
                    if (contactPoints[cpIndex].ThisIndex == i)
                    {
                        intersectionIndexes.Add(cpIndex);
                    }
                }

                if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1)
                {
                    contactPoints.RemoveAt(intersectionIndexes[1]);
                }
            }

            for (int i = 0; i < secondSegments.Length; i++)
            {
                intersectionIndexes.Clear();

                for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++)
                {
                    if (contactPoints[cpIndex].OtherIndex == i)
                    {
                        intersectionIndexes.Add(cpIndex);
                    }
                }

                if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1)
                {
                    contactPoints.RemoveAt(intersectionIndexes[1]);
                }
            }


            // See if any contact points are the same.  If so, kill them
            for (int firstCP = 0; firstCP < contactPoints.Count - 1; firstCP++)
            {
                for (int secondCP = 1; secondCP < contactPoints.Count; secondCP++)
                {
                    if (firstCP == secondCP)
                    {
                        continue;
                    }

                    float distanceApart = (contactPoints[firstCP].Position - contactPoints[secondCP].Position).Length();

                    if (distanceApart < .002)
                    {
                        contactPoints.RemoveAt(secondCP);
                        firstCP = -1; // start over.
                        numberKilled++;
                        break;
                    }
                }
            }

            if (contactPoints.Count == 1)
            {
                // Is this bad?  What do we do?
                //int m = 3;
            }

            if (contactPoints.Count % 2 != 0 && contactPoints.Count > 1)
            {
                // Oh, no, an odd number of contact points?  Let's kill the closest pair

                ReactToOddContactPointCount(contactPoints);
            }
            #endregion

            return(contactPoints);
        }