Ejemplo n.º 1
0
 /// <summary> Constructs a Penetration Sweep object, with all its attributes set.
 /// This constructor is public only for testing purposes. The static method
 /// {@link PenetrationSweep#GetPenetrationDepth(Intersection, Intersection, Vector2f, Vector2f[], Vector2f[])}
 /// should be called to get the penetration depth. 
 /// 
 /// </summary>
 /// <param name="normal">The collision normal
 /// </param>
 /// <param name="sweepDir">The sweep direction
 /// </param>
 /// <param name="intersectionStart">The start bound of the intersection Area
 /// </param>
 /// <param name="intersectionEnd">The end bound of the intersection Area.
 /// </param>
 public PenetrationSweep(Vector2f normal, Vector2f sweepDir, Vector2f intersectionStart, Vector2f intersectionEnd)
     : base()
 {
     this.normal = normal;
     this.sweepDir = sweepDir;
     this.startDist = intersectionStart.Dot(sweepDir);
     this.endDist = intersectionEnd.Dot(sweepDir);
 }
Ejemplo n.º 2
0
        /// <summary> Get point on this polygon's hull that is closest to p.
        /// 
        /// TODO: make this thing return a negative value when it is contained in the polygon
        /// 
        /// </summary>
        /// <param name="p">The point to search the closest point for
        /// </param>
        /// <returns> the nearest point on this vertex' hull
        /// </returns>
        public override ROVector2f GetNearestPoint(ROVector2f p)
        {
            // TODO: this can be done with a kind of binary search
            float r = System.Single.MaxValue;
            float l;
            Vector2f v;
            int m = - 1;

            for (int i = 0; i < vertices.Length; i++)
            {
                v = new Vector2f(vertices[i]);
                v.Sub(p);
                l = v.x * v.x + v.y * v.y;

                if (l < r)
                {
                    r = l;
                    m = i;
                }
            }

            // the closest point could be on one of the closest point's edges
            // this happens when the angle between v[m-1]-v[m] and p-v[m] is
            // smaller than 90 degrees, same for v[m+1]-v[m]
            int length = vertices.Length;
            Vector2f pm = new Vector2f(p);
            pm.Sub(vertices[m]);
            Vector2f l1 = new Vector2f(vertices[(m - 1 + length) % length]);
            l1.Sub(vertices[m]);
            Vector2f l2 = new Vector2f(vertices[(m + 1) % length]);
            l2.Sub(vertices[m]);

            Vector2f normal;
            if (pm.Dot(l1) > 0)
            {
                normal = MathUtil.GetNormal(vertices[(m - 1 + length) % length], vertices[m]);
            }
            else if (pm.Dot(l2) > 0)
            {
                normal = MathUtil.GetNormal(vertices[m], vertices[(m + 1) % length]);
            }
            else
            {
                return vertices[m];
            }

            normal.Scale(- pm.Dot(normal));
            normal.Add(p);
            return normal;
        }
Ejemplo n.º 3
0
        /// <summary> Apply the friction impulse from each contact.
        /// 
        /// </summary>
        /// <param name="dt">The amount of time to Step the simulation by
        /// </param>
        /// <param name="invDT">The inverted time
        /// </param>
        /// <param name="damping">The percentage of energy to retain through out
        /// collision. (1 = no loss, 0 = total loss)
        /// </param>
        internal virtual void PreStep(float invDT, float dt, float damping)
        {
            float allowedPenetration = 0.01f;
            float biasFactor = 0.8f;

            for (int i = 0; i < numContacts; ++i)
            {
                Contact c = contacts[i];
                c.normal.Normalise();

                Vector2f r1 = new Vector2f(c.position);
                r1.Sub(body1.GetPosition());
                Vector2f r2 = new Vector2f(c.position);
                r2.Sub(body2.GetPosition());

                // Precompute normal mass, tangent mass, and bias.
                float rn1 = r1.Dot(c.normal);
                float rn2 = r2.Dot(c.normal);
                float kNormal = body1.InvMass + body2.InvMass;
                kNormal += body1.InvI * (r1.Dot(r1) - rn1 * rn1) + body2.InvI * (r2.Dot(r2) - rn2 * rn2);
                c.massNormal = damping / kNormal;

                Vector2f tangent = MathUtil.Cross(c.normal, 1.0f);
                float rt1 = r1.Dot(tangent);
                float rt2 = r2.Dot(tangent);
                float kTangent = body1.InvMass + body2.InvMass;
                kTangent += body1.InvI * (r1.Dot(r1) - rt1 * rt1) + body2.InvI * (r2.Dot(r2) - rt2 * rt2);
                c.massTangent = damping / kTangent;

                // Compute restitution
                // Relative velocity at contact
                Vector2f relativeVelocity = new Vector2f(body2.Velocity);
                relativeVelocity.Add(MathUtil.Cross(r2, body2.AngularVelocity));
                relativeVelocity.Sub(body1.Velocity);
                relativeVelocity.Sub(MathUtil.Cross(r1, body1.AngularVelocity));

                float combinedRestitution = (body1.Restitution * body2.Restitution);
                float relVel = c.normal.Dot(relativeVelocity);
                c.restitution = combinedRestitution * (- relVel);
                c.restitution = System.Math.Max(c.restitution, 0);

                float penVel = (- c.separation) / dt;
                if (c.restitution >= penVel)
                {
                    c.bias = 0;
                }
                else
                {
                    c.bias = (- biasFactor) * invDT * System.Math.Min(0.0f, c.separation + allowedPenetration);
                }

                // apply damping
                c.accumulatedNormalImpulse *= damping;

                // Apply normal + friction impulse
                Vector2f impulse = MathUtil.Scale(c.normal, c.accumulatedNormalImpulse);
                impulse.Add(MathUtil.Scale(tangent, c.accumulatedTangentImpulse));

                body1.AdjustVelocity(MathUtil.Scale(impulse, - body1.InvMass));
                body1.AdjustAngularVelocity((- body1.InvI) * MathUtil.Cross(r1, impulse));

                body2.AdjustVelocity(MathUtil.Scale(impulse, body2.InvMass));
                body2.AdjustAngularVelocity(body2.InvI * MathUtil.Cross(r2, impulse));

                // rest bias
                c.biasImpulse = 0;
            }
        }
Ejemplo n.º 4
0
        //    private static Vector2f r1 = new Vector2f();
        //    private static Vector2f r2 = new Vector2f();
        //    private static Vector2f relativeVelocity = new Vector2f();
        //    private static Vector2f impulse = new Vector2f();
        //    private static Vector2f Pb = new Vector2f();
        //    private static Vector2f tmp = new Vector2f();
        //    
        //    /**
        //     * Apply the impulse accumlated at the contact points maintained
        //     * by this arbiter.
        //     */
        //    void ApplyImpulse() {
        //        Body b1 = body1;
        //        Body b2 = body2;
        //        
        //        for (int i = 0; i < numContacts; ++i)
        //        {
        //            Contact c = contacts[i];
        //            
        //            r1.set(c.position);
        //            r1.Sub(b1.GetPosition());
        //            r2.set(c.position);
        //            r2.Sub(b2.GetPosition());
        //
        //            // Relative velocity at contact
        //            relativeVelocity.set(b2.getVelocity());
        //            relativeVelocity.Add(MathUtil.Cross(b2.getAngularVelocity(), r2));
        //            relativeVelocity.Sub(b1.getVelocity());
        //            relativeVelocity.Sub(MathUtil.Cross(b1.getAngularVelocity(), r1));
        //            
        //            // Compute normal impulse with bias.
        //            float vn = relativeVelocity.Dot(c.normal);
        //            
        //            // bias caculations are now handled seperately hence we only
        //            // handle the real impulse caculations here
        //            //float normalImpulse = c.massNormal * ((c.restitution - vn) + c.bias);
        //            float normalImpulse = c.massNormal * (c.restitution - vn);
        //            
        //            // Clamp the accumulated impulse
        //            float oldNormalImpulse = c.accumulatedNormalImpulse;
        //            c.accumulatedNormalImpulse = Math.max(oldNormalImpulse + normalImpulse, 0.0f);
        //            normalImpulse = c.accumulatedNormalImpulse - oldNormalImpulse;
        //            
        //            if (normalImpulse != 0) {
        //                // Apply contact impulse
        //                impulse.set(c.normal);
        //                impulse.Scale(normalImpulse);
        //                
        //                tmp.set(impulse);
        //                tmp.Scale(-b1.getInvMass());
        //                b1.AdjustVelocity(tmp);
        //                b1.AdjustAngularVelocity(-(b1.getInvI() * MathUtil.Cross(r1, impulse)));
        //    
        //                tmp.set(impulse);
        //                tmp.Scale(b2.getInvMass());
        //                b2.AdjustVelocity(tmp);
        //                b2.AdjustAngularVelocity(b2.getInvI() * MathUtil.Cross(r2, impulse));
        //            }
        //            
        //            // Compute bias impulse
        //            // NEW STUFF FOR SEPERATING BIAS
        //            relativeVelocity.set(b2.getBiasedVelocity());
        //            relativeVelocity.Add(MathUtil.Cross(b2.getBiasedAngularVelocity(), r2));
        //            relativeVelocity.Sub(b1.getBiasedVelocity());
        //            relativeVelocity.Sub(MathUtil.Cross(b1.getBiasedAngularVelocity(), r1));
        //            float vnb = relativeVelocity.Dot(c.normal);
        //
        //            float biasImpulse = c.massNormal * (-vnb + c.bias);
        //            float oldBiasImpulse = c.biasImpulse;
        //            c.biasImpulse = Math.max(oldBiasImpulse + biasImpulse, 0.0f);
        //            biasImpulse = c.biasImpulse - oldBiasImpulse;
        //
        //            if (biasImpulse != 0) {
        //                Pb.set(c.normal);
        //                Pb.Scale(biasImpulse);
        //                
        //                tmp.set(Pb);
        //                tmp.Scale(-b1.getInvMass());
        //                b1.AdjustBiasedVelocity(tmp);
        //                b1.AdjustBiasedAngularVelocity(-(b1.getInvI() * MathUtil.Cross(r1, Pb)));
        //    
        //                tmp.set(Pb);
        //                tmp.Scale(b2.getInvMass());
        //                b2.AdjustBiasedVelocity(tmp);
        //                b2.AdjustBiasedAngularVelocity((b2.getInvI() * MathUtil.Cross(r2, Pb)));
        //            }
        //            // END NEW STUFF
        //            
        //            //
        //            // Compute friction (tangent) impulse
        //            //
        //            float maxTangentImpulse = friction * c.accumulatedNormalImpulse;
        //
        //            // Relative velocity at contact
        //            relativeVelocity.set(b2.getVelocity());
        //            relativeVelocity.Add(MathUtil.Cross(b2.getAngularVelocity(), r2));
        //            relativeVelocity.Sub(b1.getVelocity());
        //            relativeVelocity.Sub(MathUtil.Cross(b1.getAngularVelocity(), r1));
        //            
        //            Vector2f tangent = MathUtil.Cross(c.normal, 1.0f);
        //            float vt = relativeVelocity.Dot(tangent);
        //            float tangentImpulse = c.massTangent * (-vt);
        //
        //            // Clamp friction
        //            float oldTangentImpulse = c.accumulatedTangentImpulse;
        //            c.accumulatedTangentImpulse = MathUtil.Clamp(oldTangentImpulse + tangentImpulse, -maxTangentImpulse, maxTangentImpulse);
        //            tangentImpulse = c.accumulatedTangentImpulse - oldTangentImpulse;
        //
        //            // Apply contact impulse
        //            if ((tangentImpulse > 0.1f) || (tangentImpulse < -0.1f)) {
        //                impulse = MathUtil.Scale(tangent, tangentImpulse);
        //    
        //                tmp.set(impulse);
        //                tmp.Scale(-b1.getInvMass());
        //                b1.AdjustVelocity(tmp);
        //                b1.AdjustAngularVelocity(-b1.getInvI() * MathUtil.Cross(r1, impulse));
        //    
        //                tmp.set(impulse);
        //                tmp.Scale(b2.getInvMass());
        //                b2.AdjustVelocity(tmp);
        //                b2.AdjustAngularVelocity(b2.getInvI() * MathUtil.Cross(r2, impulse));
        //            }
        //        }
        //    }
        /// <summary> Apply the impulse accumlated at the contact points maintained
        /// by this arbiter.
        /// </summary>
        internal virtual void ApplyImpulse()
        {
            Body b1 = body1;
            Body b2 = body2;

            for (int i = 0; i < numContacts; ++i)
            {
                Contact c = contacts[i];

                Vector2f r1 = new Vector2f(c.position);
                r1.Sub(b1.GetPosition());
                Vector2f r2 = new Vector2f(c.position);
                r2.Sub(b2.GetPosition());

                // Relative velocity at contact
                Vector2f relativeVelocity = new Vector2f(b2.Velocity);
                relativeVelocity.Add(MathUtil.Cross(b2.AngularVelocity, r2));
                relativeVelocity.Sub(b1.Velocity);
                relativeVelocity.Sub(MathUtil.Cross(b1.AngularVelocity, r1));

                // Compute normal impulse with bias.
                float vn = relativeVelocity.Dot(c.normal);

                // bias caculations are now handled seperately hence we only
                // handle the real impulse caculations here
                //float normalImpulse = c.massNormal * ((c.restitution - vn) + c.bias);
                float normalImpulse = c.massNormal * (c.restitution - vn);

                // Clamp the accumulated impulse
                float oldNormalImpulse = c.accumulatedNormalImpulse;
                c.accumulatedNormalImpulse = System.Math.Max(oldNormalImpulse + normalImpulse, 0.0f);
                normalImpulse = c.accumulatedNormalImpulse - oldNormalImpulse;

                // Apply contact impulse
                Vector2f impulse = MathUtil.Scale(c.normal, normalImpulse);

                b1.AdjustVelocity(MathUtil.Scale(impulse, - b1.InvMass));
                b1.AdjustAngularVelocity(- (b1.InvI * MathUtil.Cross(r1, impulse)));

                b2.AdjustVelocity(MathUtil.Scale(impulse, b2.InvMass));
                b2.AdjustAngularVelocity(b2.InvI * MathUtil.Cross(r2, impulse));

                // Compute bias impulse
                // NEW STUFF FOR SEPERATING BIAS
                relativeVelocity.Reconfigure(b2.BiasedVelocity);
                relativeVelocity.Add(MathUtil.Cross(b2.BiasedAngularVelocity, r2));
                relativeVelocity.Sub(b1.BiasedVelocity);
                relativeVelocity.Sub(MathUtil.Cross(b1.BiasedAngularVelocity, r1));
                float vnb = relativeVelocity.Dot(c.normal);

                float biasImpulse = c.massNormal * (- vnb + c.bias);
                float oldBiasImpulse = c.biasImpulse;
                c.biasImpulse = System.Math.Max(oldBiasImpulse + biasImpulse, 0.0f);
                biasImpulse = c.biasImpulse - oldBiasImpulse;

                Vector2f Pb = MathUtil.Scale(c.normal, biasImpulse);

                b1.AdjustBiasedVelocity(MathUtil.Scale(Pb, - b1.InvMass));
                b1.AdjustBiasedAngularVelocity(- (b1.InvI * MathUtil.Cross(r1, Pb)));

                b2.AdjustBiasedVelocity(MathUtil.Scale(Pb, b2.InvMass));
                b2.AdjustBiasedAngularVelocity((b2.InvI * MathUtil.Cross(r2, Pb)));

                // END NEW STUFF

                //
                // Compute friction (tangent) impulse
                //
                float maxTangentImpulse = friction * c.accumulatedNormalImpulse;

                // Relative velocity at contact
                relativeVelocity.Reconfigure(b2.Velocity);
                relativeVelocity.Add(MathUtil.Cross(b2.AngularVelocity, r2));
                relativeVelocity.Sub(b1.Velocity);
                relativeVelocity.Sub(MathUtil.Cross(b1.AngularVelocity, r1));

                Vector2f tangent = MathUtil.Cross(c.normal, 1.0f);
                float vt = relativeVelocity.Dot(tangent);
                float tangentImpulse = c.massTangent * (- vt);

                // Clamp friction
                float oldTangentImpulse = c.accumulatedTangentImpulse;
                c.accumulatedTangentImpulse = MathUtil.Clamp(oldTangentImpulse + tangentImpulse, - maxTangentImpulse, maxTangentImpulse);
                tangentImpulse = c.accumulatedTangentImpulse - oldTangentImpulse;

                // Apply contact impulse
                impulse = MathUtil.Scale(tangent, tangentImpulse);

                b1.AdjustVelocity(MathUtil.Scale(impulse, - b1.InvMass));
                b1.AdjustAngularVelocity((- b1.InvI) * MathUtil.Cross(r1, impulse));

                b2.AdjustVelocity(MathUtil.Scale(impulse, b2.InvMass));
                b2.AdjustAngularVelocity(b2.InvI * MathUtil.Cross(r2, impulse));
            }
        }
Ejemplo n.º 5
0
        /// <summary> Precaculate everything and apply initial impulse before the
        /// simulation Step takes place
        /// 
        /// </summary>
        /// <param name="invDT">The amount of time the simulation is being stepped by
        /// </param>
        public virtual void PreStep(float invDT)
        {
            // calculate the spring's vector (pointing from body1 to body2) and Length
            spring = new Vector2f(body2.GetPosition());
            spring.Add(r2);
            spring.Sub(body1.GetPosition());
            spring.Sub(r1);
            springLength = spring.Length();

            // the spring vector needs to be normalized for ApplyImpulse as well!
            spring.Normalise();

            // calculate the spring's forces
            // note that although theoretically invDT could never be 0
            // but here it can
            float springConst;

            if (springLength < minSpringSize || springLength > maxSpringSize)
            {
                // Pre-compute anchors, mass matrix, and bias.
                Matrix2f rot1 = new Matrix2f(body1.Rotation);
                Matrix2f rot2 = new Matrix2f(body2.Rotation);

                r1 = MathUtil.Mul(rot1, localAnchor1);
                r2 = MathUtil.Mul(rot2, localAnchor2);

                // the mass normal or 'k'
                float rn1 = r1.Dot(spring);
                float rn2 = r2.Dot(spring);
                float kNormal = body1.InvMass + body2.InvMass;
                kNormal += body1.InvI * (r1.Dot(r1) - rn1 * rn1) + body2.InvI * (r2.Dot(r2) - rn2 * rn2);
                massNormal = 1 / kNormal;

                // The spring is broken so apply force to correct it
                // note that we use biased velocities for this
                float springImpulse = invDT != 0?brokenSpringConst * (springLength - springSize) / invDT:0;

                Vector2f impulse = MathUtil.Scale(spring, springImpulse);
                body1.AdjustBiasedVelocity(MathUtil.Scale(impulse, body1.InvMass));
                body1.AdjustBiasedAngularVelocity((body1.InvI * MathUtil.Cross(r1, impulse)));

                body2.AdjustBiasedVelocity(MathUtil.Scale(impulse, - body2.InvMass));
                body2.AdjustBiasedAngularVelocity(- (body2.InvI * MathUtil.Cross(r2, impulse)));

                isBroken = true;
                return ;
            }
            else if (springLength < springSize)
            {
                springConst = compressedSpringConst;
                isBroken = false;
            }
            else
            {
                // if ( springLength >= springSize )
                springConst = stretchedSpringConst;
                isBroken = false;
            }

            float springImpulse2 = invDT != 0?springConst * (springLength - springSize) / invDT:0;

            // apply the spring's forces
            Vector2f impulse2 = MathUtil.Scale(spring, springImpulse2);
            body1.AdjustVelocity(MathUtil.Scale(impulse2, body1.InvMass));
            body1.AdjustAngularVelocity((body1.InvI * MathUtil.Cross(r1, impulse2)));

            body2.AdjustVelocity(MathUtil.Scale(impulse2, - body2.InvMass));
            body2.AdjustAngularVelocity(- (body2.InvI * MathUtil.Cross(r2, impulse2)));
        }
Ejemplo n.º 6
0
        /// <summary> Apply the impulse caused by the joint to the bodies attached.</summary>
        public virtual void ApplyImpulse()
        {
            if (isBroken)
            {
                // calculate difference in velocity
                // TODO: share this code with BasicJoint and Arbiter
                Vector2f relativeVelocity = new Vector2f(body2.Velocity);
                relativeVelocity.Add(MathUtil.Cross(body2.AngularVelocity, r2));
                relativeVelocity.Sub(body1.Velocity);
                relativeVelocity.Sub(MathUtil.Cross(body1.AngularVelocity, r1));

                // project the relative velocity onto the spring vector and apply the mass normal
                float normalImpulse = massNormal * relativeVelocity.Dot(spring);

                //			// TODO: Clamp the accumulated impulse?
                //			float oldNormalImpulse = accumulatedNormalImpulse;
                //			accumulatedNormalImpulse = Math.max(oldNormalImpulse + normalImpulse, 0.0f);
                //			normalImpulse = accumulatedNormalImpulse - oldNormalImpulse;

                // only apply the impulse if we are pushing or pulling in the right way
                // i.e. pulling if the string is overstretched and pushing if it is too compressed
                if (springLength < minSpringSize && normalImpulse < 0 || springLength > maxSpringSize && normalImpulse > 0)
                {
                    // now apply the impulses to the bodies
                    Vector2f impulse = MathUtil.Scale(spring, normalImpulse);
                    body1.AdjustVelocity(MathUtil.Scale(impulse, body1.InvMass));
                    body1.AdjustAngularVelocity((body1.InvI * MathUtil.Cross(r1, impulse)));

                    body2.AdjustVelocity(MathUtil.Scale(impulse, - body2.InvMass));
                    body2.AdjustAngularVelocity(- (body2.InvI * MathUtil.Cross(r2, impulse)));
                }
            }
        }