public ContactList(ContactList contactList) : base(contactList)
 {
 }
Exemple #2
0
        /// <summary>
        /// Returns the contact list from two possibly intersecting Geom's.
        /// This is the stationary version of this function. It doesn't
        /// account for linear or angular motion.
        /// </summary>
        /// <param name="geomA">The first Geom.</param>
        /// <param name="geomB">The second Geom.</param>
        /// <param name="contactList">Set of Contacts between the two Geoms.
        /// NOTE- this will be empty if no contacts are present.</param>
        public void Collide(Geom geomA, Geom geomB, ContactList contactList)
        {
            PolygonCollisionResult result = PolygonCollision(geomA.WorldVertices, geomB.WorldVertices);
            float   distance         = result.MinimumTranslationVector.Length();
            int     contactsDetected = 0;
            Vector2 normal           = Vector2.Normalize(-result.MinimumTranslationVector);
            int     contactsHandled  = 0;

            if (result.Intersect && distance > 0.001f)
            {
                for (int i = 0; i < geomA.WorldVertices.Count; i++)
                {
                    if (contactsDetected <= PhysicsSimulator.MaxContactsToDetect)
                    {
                        if (InsidePolygon(geomB.WorldVertices, geomA.WorldVertices[i]))
                        {
                            Contact c = new Contact(geomA.WorldVertices[i], normal, -distance, new ContactId(geomA.id, i, geomB.id));
                            contactList.Add(c);
                            contactsDetected++;
                            contactsHandled++;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                contactsDetected = 0;

                for (int i = 0; i < geomB.WorldVertices.Count; i++)
                {
                    if (contactsDetected <= PhysicsSimulator.MaxContactsToDetect)
                    {
                        if (InsidePolygon(geomA.WorldVertices, geomB.WorldVertices[i]))
                        {
                            Contact c = new Contact(geomB.WorldVertices[i], normal, -distance, new ContactId(geomB.id, i, geomA.id));
                            contactList.Add(c);
                            contactsDetected++;
                            contactsHandled++;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                // No vertices of either polygon are inside the other, despite their intersection.
                // (Think of an X made of two rectangles of four vertices each.)
                // So select the vertex that is furthest past the edge forming the
                // separating axis as the contact point.
                //   - Andrew Russell
                if (contactsHandled == 0)
                {
                    int  edgeIndex        = result.bestEdgeIndex;
                    Geom separatingEdgeOn = geomA;
                    Geom otherPolygon     = geomB;
                    if (result.bestEdgeIndex >= geomA.WorldVertices.Count)
                    {
                        edgeIndex       -= geomA.WorldVertices.Count;
                        separatingEdgeOn = geomB;
                        otherPolygon     = geomA;
                    }

                    Vector2 edge = separatingEdgeOn.WorldVertices.GetEdge(edgeIndex);
                    Vector2 axis = new Vector2(-edge.Y, edge.X);
                    axis.Normalize();

                    int   mostPenetrationIndex = 0;
                    float mostPenetration      = Vector2.Dot(axis, otherPolygon.WorldVertices[0]);
                    for (int i = 1; i < otherPolygon.WorldVertices.Count; i++)
                    {
                        float penetration = Vector2.Dot(axis, otherPolygon.WorldVertices[i]);
                        if (penetration < mostPenetration)
                        {
                            mostPenetration      = penetration;
                            mostPenetrationIndex = i;
                        }
                    }

                    Contact c = new Contact(otherPolygon.WorldVertices[mostPenetrationIndex], normal, -distance,
                                            new ContactId(otherPolygon.id, mostPenetrationIndex, separatingEdgeOn.id));
                    contactList.Add(c);
                }
            }
        }
        /// <summary>
        /// Finds the contactpoints between the two geometries.
        /// </summary>
        /// <param name="geomA">The first geom.</param>
        /// <param name="geomB">The second geom.</param>
        /// <param name="contactList">The contact list.</param>
        public void Collide(Geom geomA, Geom geomB, ContactList contactList)
        {
            int vertexIndex = -1;

            //Lookup distancegrid A data from list
            DistanceGridData geomAGridData = _distanceGrids[geomA.id];

            //Iterate the second geometry vertices
            for (int i = 0; i < geomB.worldVertices.Count; i++)
            {
                if (contactList.Count == PhysicsSimulator.MaxContactsToDetect)
                {
                    break;
                }

                vertexIndex += 1;
                _vertRef     = geomB.WorldVertices[i];
                geomA.TransformToLocalCoordinates(ref _vertRef, out _localVertex);

                //The geometry intersects when distance <= 0
                //Continue in the list if the current vector does not intersect
                if (!geomAGridData.Intersect(ref _localVertex, out _feature))
                {
                    continue;
                }

                //If the geometries collide, create a new contact and add it to the contact list.
                if (_feature.Distance < 0f)
                {
                    geomA.TransformNormalToWorld(ref _feature.Normal, out _feature.Normal);

                    Contact contact = new Contact(geomB.WorldVertices[i], _feature.Normal, _feature.Distance, new ContactId(geomB.id, vertexIndex, geomA.id));
                    contactList.Add(contact);
                }
            }

            //Lookup distancegrid B data from list
            DistanceGridData geomBGridData = _distanceGrids[geomB.id];

            //Iterate the first geometry vertices
            for (int i = 0; i < geomA.WorldVertices.Count; i++)
            {
                if (contactList.Count == PhysicsSimulator.MaxContactsToDetect)
                {
                    break;
                }

                vertexIndex += 1;
                _vertRef     = geomA.WorldVertices[i];
                geomB.TransformToLocalCoordinates(ref _vertRef, out _localVertex);

                if (!geomBGridData.Intersect(ref _localVertex, out _feature))
                {
                    continue;
                }

                if (_feature.Distance < 0f)
                {
                    geomB.TransformNormalToWorld(ref _feature.Normal, out _feature.Normal);
                    _feature.Normal = -_feature.Normal;

                    Contact contact = new Contact(geomA.WorldVertices[i], _feature.Normal, _feature.Distance, new ContactId(geomA.id, vertexIndex, geomB.id));
                    contactList.Add(contact);
                }
            }
        }