/// <summary> Set a contact for an intersection where the colliding line's start- or endpoint
        /// is contained in the colliding polygon.
        /// 
        /// TODO: The current implementation doesn't work properly: because lines are very
        /// thin, they can slide into a polygon sideways which gives a very deep penetration
        /// |
        /// |->
        /// |      +-----+
        /// |->    |     |
        /// |      |     |
        /// |     |
        /// +-----+
        /// 
        /// A possible solution would be to use the velocity of the line relative to the 
        /// polygon to construct a collision normal and penetration depth.
        /// Another possibility is to use the line's normals (both directions) and calculate
        /// proper intersection distances for them.
        /// If one has multiple normals/penetration depths to choose from, the one with the
        /// minimum penetration depth will probably be the best bet.
        /// 
        /// </summary>
        /// <param name="contact">The contact to set
        /// </param>
        /// <param name="intersection">The intersection where the line enters or exits the polygon
        /// </param>
        /// <param name="vertsA">The line's vertices
        /// </param>
        /// <param name="vertsB">The polygon's vertices
        /// </param>
        public virtual void SetLineEndContact(Contact contact, Intersection intersection, Vector2f[] vertsA, Vector2f[] vertsB)
        {
            Vector2f separation = new Vector2f(intersection.position);
            if (intersection.isIngoing)
                separation.Sub(vertsA[1]);
            else
                separation.Sub(vertsA[0]);

            float depthA = 0; //separation.Length();

            contact.Separation = - depthA;
            contact.Normal = MathUtil.GetNormal(vertsB[(intersection.edgeB + 1) % vertsB.Length], vertsB[intersection.edgeB]);
            contact.Position = intersection.position;
            contact.Feature = new FeaturePair(0, 0, intersection.edgeA, intersection.edgeB);
        }
Esempio n. 2
0
        /// <summary> Given two intersecting polygons, the intersection points and a collision
        /// normal, get the maximum penetration Distance along the normal.
        /// 
        /// </summary>
        /// <param name="in">The ingoing intersection
        /// </param>
        /// <param name="out">The outgoing intersection
        /// </param>
        /// <param name="normal">The collision normal
        /// </param>
        /// <param name="vertsA">The vertices of polygon A
        /// </param>
        /// <param name="vertsB">The vertices of polygon B
        /// </param>
        /// <returns> the maximum penetration depth along the given normal
        /// </returns>
        public static float GetPenetrationDepth(Intersection ingoing, Intersection outgoing, Vector2f normal, Vector2f[] vertsA, Vector2f[] vertsB)
        {
            Vector2f sweepdir = new Vector2f(outgoing.position);
            sweepdir.Sub(ingoing.position);

            PenetrationSweep ps = new PenetrationSweep(normal, sweepdir, ingoing.position, outgoing.position);

            //TODO: most penetrations are very simple, similar to:
            // \               +       |
            //  \             / \      |
            //   +-----------x---x-----+
            //              /     \
            // these should be handled separately

            ContourWalker walkerA = new Silver.Weight.Raw.Collide.PenetrationSweep.ContourWalker(ps, vertsA, ingoing.edgeA, outgoing.edgeA, false);
            ContourWalker walkerB = new Silver.Weight.Raw.Collide.PenetrationSweep.ContourWalker(ps, vertsB, (outgoing.edgeB + 1) % vertsB.Length, (ingoing.edgeB + 1) % vertsB.Length, true);

            float penetration = 0;
            float lowerBound = ingoing.position.Dot(normal);
            float upperBound = lowerBound;

            while (walkerA.HasNext() || walkerB.HasNext())
            {
                // if walker a has more and the Next vertex comes before B's
                // or if walker a has more but walker b hasn't, go and take a Step
                if (walkerA.HasNext() && (walkerA.NextDistance < walkerB.NextDistance || !walkerB.HasNext()))
                {
                    walkerA.Next();
                    if (walkerA.Distance < ps.startDist || walkerA.Distance > ps.endDist)
                        continue; // we don't care for vertices outside of the intersecting borders

                    upperBound = walkerA.GetPenetration();
                    lowerBound = walkerB.GetPenetration(walkerA.Distance);
                }
                else
                {
                    walkerB.Next();
                    if (walkerB.Distance < ps.startDist || walkerB.Distance > ps.endDist)
                        continue;

                    upperBound = walkerA.GetPenetration(walkerB.Distance);
                    lowerBound = walkerB.GetPenetration();
                }

                penetration = System.Math.Max(penetration, upperBound - lowerBound);
            }

            return penetration;
        }
        /// <summary> Given a list of intersections, calculate the collision information and
        /// set the contacts with that information.
        /// 
        /// </summary>
        /// <param name="contacts">The array of contacts to fill
        /// </param>
        /// <param name="vertsA">The vertices of polygon A
        /// </param>
        /// <param name="vertsB">The vertices of polygon B
        /// </param>
        /// <param name="intersections">The array of intersection as returned by 
        /// {@link IntersectionGatherer#getIntersections()}
        /// </param>
        /// <returns> The number of contacts that have been set in the contact array
        /// </returns>
        public virtual int PopulateContacts(Contact[] contacts, Vector2f[] vertsA, Vector2f[] vertsB, Intersection[] intersections)
        {
            if (intersections.Length == 0)
                return 0;

            int noContacts = 0;

            // is the first intersection outgoing?
            if (!intersections[0].isIngoing)
            {
                SetLineEndContact(contacts[noContacts], intersections[intersections.Length - 1], vertsA, vertsB);

                if (contacts[noContacts].Separation < - 10)
                    System.Console.Out.WriteLine("first " + contacts[noContacts].Separation);

                noContacts++;
            }

            int i = noContacts;
            while (i < intersections.Length - 1)
            {
                if (noContacts > contacts.Length - 2)
                    return noContacts;

                // check if we have an intersection pair
                if (!intersections[i].isIngoing || intersections[i + 1].isIngoing)
                {
                    SetContact(contacts[noContacts], intersections[i], vertsA, vertsB);
                    i++;
                    noContacts++;
                    continue;
                }

                SetContactPair(contacts[noContacts], contacts[noContacts + 1], intersections[i], intersections[i + 1], vertsA, vertsB);

                if (contacts[noContacts].Separation < - 10)
                    System.Console.Out.WriteLine("m " + contacts[noContacts].Separation);

                noContacts += 2;
                i += 2;
            }

            // is there still an ingoing intersection left?
            if (i < intersections.Length && intersections[intersections.Length - 1].isIngoing && noContacts < contacts.Length)
            {
                SetLineEndContact(contacts[noContacts], intersections[intersections.Length - 1], vertsA, vertsB);

                if (contacts[noContacts].Separation < - 10)
                    System.Console.Out.WriteLine(" last " + contacts[noContacts].Separation);
                noContacts++;
            }

            return noContacts;
        }