Esempio n. 1
0
        /// <summary>
        /// Discrete Box vs Box test. Very fast. Generates contact info. NOTE: ensure UpdateAxes is called for each BoxShape prior.
        /// </summary>
        /// <param name="A">BoxShape A.</param>
        /// <param name="PA">BoxShape A's position.</param>
        /// <param name="OA">BoxShape A's orientation.</param>
        /// <param name="B">BoxShape B.</param>
        /// <param name="PB">BoxShape B's position.</param>
        /// <param name="OB">BoxShape B's orientation.</param>
        /// <param name="normal">Normal of collision.</param>
        /// <param name="t">Amount of penetration.</param>
        /// <param name="CA">Contacts found on BoxShape A.</param>
        /// <param name="CB">Contacts found on BoxShape B.</param>
        /// <param name="NumContacts">Number of contacts found.</param>
        /// <returns>True if collision exists.</returns>
        public static bool BoxBoxTestContact(ref BoxShape A, ref JVector PA, ref JMatrix OA,
                                             ref BoxShape B, ref JVector PB, ref JMatrix OB,
                                             out JVector normal, out float t, out JVector[] CA, out JVector[] CB, out int NumContacts)
        {
            float overlap = 0;

            normal = A.xAxis;
            t      = 0.0f;
            // TODO in future to save a few bytes of garbage make these
            // SA1, SA2 and SB1, SB2 (no arrays)
            JVector[] SA = new JVector[2], SB = new JVector[2];
            int       NumSA = 0, NumSB = 0;

            CA          = new JVector[2]; CB = new JVector[2];
            NumContacts = 0;

            JVector T = PB - PA;

            // cache scaled local axes
            JVector Ax = A.halfSize.X * A.xAxis;
            JVector Ay = A.halfSize.Y * A.yAxis;
            JVector Bx = B.halfSize.X * B.xAxis;
            JVector By = B.halfSize.Y * B.yAxis;

            // axis to test
            JVector L  = A.xAxis;
            float   TL = Math.Abs(T * L);

            float a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L);
            float b = Math.Abs((Bx) * L) + Math.Abs((By) * L);

            if (TL > (a + b))
            {
                return(false);
            }

            // cache overlap
            // just set first overlap
            overlap = TL - (b + a);

            // axis to test
            L  = A.yAxis;
            TL = Math.Abs(T * L);

            a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L);
            b = Math.Abs((Bx) * L) + Math.Abs((By) * L);

            if (TL > (a + b))
            {
                return(false);
            }

            // cache overlap
            var o = TL - (b + a);

            if (o > overlap)
            {
                overlap = o;
                normal  = A.yAxis;
            }

            // axis to test
            L  = B.xAxis;
            TL = Math.Abs(T * L);

            a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L);
            b = Math.Abs((Bx) * L) + Math.Abs((By) * L);

            if (TL > (a + b))
            {
                return(false);
            }

            // cache overlap
            o = TL - (b + a);
            if (o > overlap)
            {
                overlap = o;
                normal  = B.xAxis;
            }

            // axis to test
            L  = B.yAxis;
            TL = Math.Abs(T * L);

            a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L);
            b = Math.Abs((Bx) * L) + Math.Abs((By) * L);

            if (TL > (a + b))
            {
                return(false);
            }

            // cache overlap
            o = TL - (b + a);
            if (o > overlap)
            {
                overlap = o;
                normal  = B.yAxis;
            }

            // make sure the polygons gets pushed away from each other.
            if (normal * T < 0.0f)
            {
                normal = -normal;
            }

            t = overlap;

            // now to find a contact point or edge!
            var mn = -normal;

            NumSA = A.FindSupportPoints(ref mn, ref PA, ref OA, out SA);
            NumSB = B.FindSupportPoints(ref normal, ref PB, ref OB, out SB);

            // now refine contact points from support points
            // edge/vertex case
            if (NumSA == 2 && NumSB == 1)
            {
                ProjectPointOnLine(ref SB[0], ref SA[0], ref SA[1], out CA[NumContacts]);
                CB[NumContacts] = SB[0];
                NumContacts++;
                return(true);
            }
            // vertex/edge case
            if (NumSA == 1 && NumSB == 2)
            {
                ProjectPointOnLine(ref SA[0], ref SB[0], ref SB[1], out CB[NumContacts]);
                CA[NumContacts] = SA[0];
                NumContacts++;
                return(true);
            }
            // edge/edge case
            if (NumSA == 2 && NumSB == 2)
            {
                // clip contacts
                JVector perp = new JVector(-normal.Y, normal.X);
                // project first 2 contacts to axis perpendicular to normal
                float min0 = SA[0] * perp;
                float max0 = min0;
                float min1 = SB[0] * perp;
                float max1 = min1;
                // project next point from A
                max0 = SA[1] * perp;

                if (max0 < min0)
                {
                    JMath.Swapf(ref min0, ref max0);
                    JVector.Swap(ref SA[0], ref SA[1]);
                }

                max1 = SB[1] * perp;

                if (max1 < min1)
                {
                    JMath.Swapf(ref min1, ref max1);
                    JVector.Swap(ref SB[0], ref SB[1]);
                }

                if (min0 > min1)
                {
                    JVector Pseg;
                    ProjectPointOnLine(ref SA[0], ref SB[0], ref SB[1], out Pseg);
                    CA[NumContacts] = SA[0];
                    CB[NumContacts] = Pseg;
                    NumContacts++;
                }
                else
                {
                    JVector Pseg;
                    ProjectPointOnLine(ref SB[0], ref SA[0], ref SA[1], out Pseg);
                    CA[NumContacts] = Pseg;
                    CB[NumContacts] = SB[0];
                    NumContacts++;
                }

                if (max0 < max1)
                {
                    JVector Pseg;
                    ProjectPointOnLine(ref SA[1], ref SB[0], ref SB[1], out Pseg);
                    CA[NumContacts] = SA[1];
                    CB[NumContacts] = Pseg;
                    NumContacts++;
                }
                else
                {
                    JVector Pseg;
                    ProjectPointOnLine(ref SB[1], ref SA[0], ref SA[1], out Pseg);
                    CA[NumContacts] = Pseg;
                    CB[NumContacts] = SB[1];
                    NumContacts++;
                }

                return(true);
            }

            // if all axes overlap collision exists
            return(true);
        }