Esempio n. 1
0
    /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.

    // Pulley:
    // length1 = norm(p1 - s1)
    // length2 = norm(p2 - s2)
    // C0 = (length1 + ratio * length2)_initial
    // C = C0 - (length1 + ratio * length2)
    // u1 = (p1 - s1) / norm(p1 - s1)
    // u2 = (p2 - s2) / norm(p2 - s2)
    // Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
    // J = -[u1 cross(r1, u1) ratio * u2  ratio * cross(r2, u2)]
    // K = J * invM * JT
    //   = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)

    public void Initialize(b2Body bA, b2Body bB, b2Vec2 groundA, b2Vec2 groundB, b2Vec2 anchorA, b2Vec2 anchorB, float r)
    {
        bodyA = bA;
        bodyB = bB;


        groundAnchorA = groundA;


        groundAnchorB = groundB;


        localAnchorA = bodyA.GetLocalPoint(anchorA);


        localAnchorB = bodyB.GetLocalPoint(anchorB);
        b2Vec2 dA = anchorA - groundA;

        lengthA = dA.Length();
        b2Vec2 dB = anchorB - groundB;

        lengthB = dB.Length();
        ratio   = r;
        Debug.Assert(ratio > float.Epsilon);
    }
Esempio n. 2
0
        public override void SolveVelocityConstraints(b2SolverData data)
        {
            b2Vec2 vB = data.velocities[m_indexB].v;
            float  wB = data.velocities[m_indexB].w;

            // Cdot = v + cross(w, r)
            b2Vec2 Cdot    = vB + b2Math.b2Cross(wB, m_rB);
            b2Vec2 impulse = b2Math.b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse));

            b2Vec2 oldImpulse = m_impulse;

            m_impulse += impulse;
            float maxImpulse = data.step.dt * m_maxForce;

            if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
            {
                m_impulse *= maxImpulse / m_impulse.Length();
            }
            impulse = m_impulse - oldImpulse;

            vB += m_invMassB * impulse;
            wB += m_invIB * b2Math.b2Cross(m_rB, impulse);

            data.velocities[m_indexB].v = vB;
            data.velocities[m_indexB].w = wB;
        }
Esempio n. 3
0
        public virtual float GetLengthB()
        {
            b2Vec2 p = m_bodyB.GetWorldPoint(m_localAnchorB);
            b2Vec2 s = m_groundAnchorB;
            b2Vec2 d = p - s;

            return(d.Length());
        }
Esempio n. 4
0
    /// Get the current length of the segment attached to bodyB.


    public float GetCurrentLengthB()
    {
        b2Vec2 p = m_bodyB.GetWorldPoint(m_localAnchorB);


        b2Vec2 s = new b2Vec2(m_groundAnchorB);
        b2Vec2 d = p - s;

        return(d.Length());
    }
Esempio n. 5
0
    /// Initialize the bodies, anchors, and length using the world
    /// anchors.

    // 1-D constrained system
    // m (v2 - v1) = lambda
    // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
    // x2 = x1 + h * v2

    // 1-D mass-damper-spring system
    // m (v2 - v1) + h * d * v2 + h * k *

    // C = norm(p2 - p1) - L
    // u = (p2 - p1) / norm(p2 - p1)
    // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
    // J = [-u -cross(r1, u) u cross(r2, u)]
    // K = J * invM * JT
    //   = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2

    public void Initialize(b2Body b1, b2Body b2, b2Vec2 anchor1, b2Vec2 anchor2)
    {
        bodyA        = b1;
        bodyB        = b2;
        localAnchorA = bodyA.GetLocalPoint(anchor1);
        localAnchorB = bodyB.GetLocalPoint(anchor2);
        b2Vec2 d = anchor2 - anchor1;

        length = d.Length();
    }
Esempio n. 6
0
        /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
        public void Initialize(b2Body bA, b2Body bB,
                               b2Vec2 groundA, b2Vec2 groundB,
                               b2Vec2 anchorA, b2Vec2 anchorB,
                               float r)
        {
            BodyA         = bA;
            BodyB         = bB;
            groundAnchorA = groundA;
            groundAnchorB = groundB;
            localAnchorA  = BodyA.GetLocalPoint(anchorA);
            localAnchorB  = BodyB.GetLocalPoint(anchorB);
            b2Vec2 dA = anchorA - groundA;

            lengthA = dA.Length();
            b2Vec2 dB = anchorB - groundB;

            lengthB = dB.Length();
            ratio   = r;
            System.Diagnostics.Debug.Assert(ratio > b2Settings.b2_epsilon);
        }
Esempio n. 7
0
        public override void InitVelocityConstraints(b2SolverData data)
        {
            m_indexA       = m_bodyA.IslandIndex;
            m_indexB       = m_bodyB.IslandIndex;
            m_localCenterA = m_bodyA.Sweep.localCenter;
            m_localCenterB = m_bodyB.Sweep.localCenter;
            m_invMassA     = m_bodyA.InvertedMass;
            m_invMassB     = m_bodyB.InvertedMass;
            m_invIA        = m_bodyA.InvertedI;
            m_invIB        = m_bodyB.InvertedI;

            b2Vec2 cA = data.positions[m_indexA].c;
            float  aA = data.positions[m_indexA].a;
            b2Vec2 vA = data.velocities[m_indexA].v;
            float  wA = data.velocities[m_indexA].w;

            b2Vec2 cB = data.positions[m_indexB].c;
            float  aB = data.positions[m_indexB].a;
            b2Vec2 vB = data.velocities[m_indexB].v;
            float  wB = data.velocities[m_indexB].w;

            b2Rot qA = new b2Rot(aA);
            b2Rot qB = new b2Rot(aB);

            m_rA = b2Math.b2Mul(qA, m_localAnchorA - m_localCenterA);
            m_rB = b2Math.b2Mul(qB, m_localAnchorB - m_localCenterB);
            m_u  = cB + m_rB - cA - m_rA;

            m_length = m_u.Length();

            float C = m_length - m_maxLength;

            if (C > 0.0f)
            {
                m_state = b2LimitState.e_atUpperLimit;
            }
            else
            {
                m_state = b2LimitState.e_inactiveLimit;
            }

            if (m_length > b2Settings.b2_linearSlop)
            {
                m_u *= 1.0f / m_length;
            }
            else
            {
                m_u.SetZero();
                m_mass    = 0.0f;
                m_impulse = 0.0f;
                return;
            }

            // Compute effective mass.
            float crA     = b2Math.b2Cross(m_rA, m_u);
            float crB     = b2Math.b2Cross(m_rB, m_u);
            float invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB;

            m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;

            if (data.step.warmStarting)
            {
                // Scale the impulse to support a variable time step.
                m_impulse *= data.step.dtRatio;

                b2Vec2 P = m_impulse * m_u;
                vA -= m_invMassA * P;
                wA -= m_invIA * b2Math.b2Cross(m_rA, P);
                vB += m_invMassB * P;
                wB += m_invIB * b2Math.b2Cross(m_rB, P);
            }
            else
            {
                m_impulse = 0.0f;
            }

            data.velocities[m_indexA].v = vA;
            data.velocities[m_indexA].w = wA;
            data.velocities[m_indexB].v = vB;
            data.velocities[m_indexB].w = wB;
        }
Esempio n. 8
0
        public override bool SolvePositionConstraints(b2SolverData data)
        {
            b2Vec2 cA = data.positions[m_indexA].c;
            float  aA = data.positions[m_indexA].a;
            b2Vec2 cB = data.positions[m_indexB].c;
            float  aB = data.positions[m_indexB].a;

            b2Rot qA = new b2Rot(aA);
            b2Rot qB = new b2Rot(aB);

            float mA = m_invMassA, mB = m_invMassB;
            float iA = m_invIA, iB = m_invIB;

            b2Vec2 rA = b2Math.b2Mul(qA, m_localAnchorA - m_localCenterA);
            b2Vec2 rB = b2Math.b2Mul(qB, m_localAnchorB - m_localCenterB);

            float positionError, angularError;

            b2Vec3 ex = new b2Vec3();
            b2Vec3 ey = new b2Vec3();
            b2Vec3 ez = new b2Vec3();

            ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
            ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
            ez.x = -rA.y * iA - rB.y * iB;
            ex.y = ey.x;
            ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
            ez.y = rA.x * iA + rB.x * iB;
            ex.z = ez.x;
            ey.z = ez.y;
            ez.z = iA + iB;
            b2Mat33 K = new b2Mat33(ex, ey, ez);

            if (m_frequencyHz > 0.0f)
            {
                b2Vec2 C1 = cB + rB - cA - rA;

                positionError = C1.Length();
                angularError  = 0.0f;

                b2Vec2 P = -K.Solve22(C1);

                cA -= mA * P;
                aA -= iA * b2Math.b2Cross(rA, P);

                cB += mB * P;
                aB += iB * b2Math.b2Cross(rB, P);
            }
            else
            {
                b2Vec2 C1 = cB + rB - cA - rA;
                float  C2 = aB - aA - m_referenceAngle;

                positionError = C1.Length();
                angularError  = b2Math.b2Abs(C2);

                b2Vec3 C = new b2Vec3(C1.x, C1.y, C2);

                b2Vec3 impulse = -K.Solve33(C);
                b2Vec2 P       = new b2Vec2(impulse.x, impulse.y);

                cA -= mA * P;
                aA -= iA * (b2Math.b2Cross(rA, P) + impulse.z);

                cB += mB * P;
                aB += iB * (b2Math.b2Cross(rB, P) + impulse.z);
            }

            data.positions[m_indexA].c = cA;
            data.positions[m_indexA].a = aA;
            data.positions[m_indexB].c = cB;
            data.positions[m_indexB].a = aB;

            return(positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop);
        }
Esempio n. 9
0
        public override void InitVelocityConstraints(b2SolverData data)
        {
            m_indexA       = m_bodyA.IslandIndex;
            m_indexB       = m_bodyB.IslandIndex;
            m_localCenterA = m_bodyA.Sweep.localCenter;
            m_localCenterB = m_bodyB.Sweep.localCenter;
            m_invMassA     = m_bodyA.InvertedMass;
            m_invMassB     = m_bodyB.InvertedMass;
            m_invIA        = m_bodyA.InvertedI;
            m_invIB        = m_bodyB.InvertedI;

            b2Vec2 cA = data.positions[m_indexA].c;
            float  aA = data.positions[m_indexA].a;
            b2Vec2 vA = data.velocities[m_indexA].v;
            float  wA = data.velocities[m_indexA].w;

            b2Vec2 cB = data.positions[m_indexB].c;
            float  aB = data.positions[m_indexB].a;
            b2Vec2 vB = data.velocities[m_indexB].v;
            float  wB = data.velocities[m_indexB].w;

            b2Rot qA = new b2Rot(aA);
            b2Rot qB = new b2Rot(aB);

            m_rA = b2Math.b2Mul(qA, m_localAnchorA - m_localCenterA);
            m_rB = b2Math.b2Mul(qB, m_localAnchorB - m_localCenterB);

            // Get the pulley axes.
            m_uA = cA + m_rA - m_groundAnchorA;
            m_uB = cB + m_rB - m_groundAnchorB;

            float lengthA = m_uA.Length();
            float lengthB = m_uB.Length();

            if (lengthA > 10.0f * b2Settings.b2_linearSlop)
            {
                m_uA *= 1.0f / lengthA;
            }
            else
            {
                m_uA.SetZero();
            }

            if (lengthB > 10.0f * b2Settings.b2_linearSlop)
            {
                m_uB *= 1.0f / lengthB;
            }
            else
            {
                m_uB.SetZero();
            }

            // Compute effective mass.
            float ruA = b2Math.b2Cross(m_rA, m_uA);
            float ruB = b2Math.b2Cross(m_rB, m_uB);

            float mA = m_invMassA + m_invIA * ruA * ruA;
            float mB = m_invMassB + m_invIB * ruB * ruB;

            m_mass = mA + m_ratio * m_ratio * mB;

            if (m_mass > 0.0f)
            {
                m_mass = 1.0f / m_mass;
            }

            if (data.step.warmStarting)
            {
                // Scale impulses to support variable time steps.
                m_impulse *= data.step.dtRatio;

                // Warm starting.
                b2Vec2 PA = -(m_impulse) * m_uA;
                b2Vec2 PB = (-m_ratio * m_impulse) * m_uB;

                vA += m_invMassA * PA;
                wA += m_invIA * b2Math.b2Cross(m_rA, PA);
                vB += m_invMassB * PB;
                wB += m_invIB * b2Math.b2Cross(m_rB, PB);
            }
            else
            {
                m_impulse = 0.0f;
            }

            data.velocities[m_indexA].v = vA;
            data.velocities[m_indexA].w = wA;
            data.velocities[m_indexB].v = vB;
            data.velocities[m_indexB].w = wB;
        }
Esempio n. 10
0
        public override bool SolvePositionConstraints(b2SolverData data)
        {
            b2Vec2 cA = data.positions[m_indexA].c;
            float  aA = data.positions[m_indexA].a;
            b2Vec2 cB = data.positions[m_indexB].c;
            float  aB = data.positions[m_indexB].a;

            b2Rot qA = new b2Rot(aA);
            b2Rot qB = new b2Rot(aB);

            b2Vec2 rA = b2Math.b2Mul(qA, m_localAnchorA - m_localCenterA);
            b2Vec2 rB = b2Math.b2Mul(qB, m_localAnchorB - m_localCenterB);

            // Get the pulley axes.
            b2Vec2 uA = cA + rA - m_groundAnchorA;
            b2Vec2 uB = cB + rB - m_groundAnchorB;

            float lengthA = uA.Length();
            float lengthB = uB.Length();

            if (lengthA > 10.0f * b2Settings.b2_linearSlop)
            {
                uA *= 1.0f / lengthA;
            }
            else
            {
                uA.SetZero();
            }

            if (lengthB > 10.0f * b2Settings.b2_linearSlop)
            {
                uB *= 1.0f / lengthB;
            }
            else
            {
                uB.SetZero();
            }

            // Compute effective mass.
            float ruA = b2Math.b2Cross(rA, uA);
            float ruB = b2Math.b2Cross(rB, uB);

            float mA = m_invMassA + m_invIA * ruA * ruA;
            float mB = m_invMassB + m_invIB * ruB * ruB;

            float mass = mA + m_ratio * m_ratio * mB;

            if (mass > 0.0f)
            {
                mass = 1.0f / mass;
            }

            float C           = m_constant - lengthA - m_ratio * lengthB;
            float linearError = b2Math.b2Abs(C);

            float impulse = -mass * C;

            b2Vec2 PA = -impulse * uA;
            b2Vec2 PB = -m_ratio * impulse * uB;

            cA += m_invMassA * PA;
            aA += m_invIA * b2Math.b2Cross(rA, PA);
            cB += m_invMassB * PB;
            aB += m_invIB * b2Math.b2Cross(rB, PB);

            data.positions[m_indexA].c = cA;
            data.positions[m_indexA].a = aA;
            data.positions[m_indexB].c = cB;
            data.positions[m_indexB].a = aB;

            return(linearError < b2Settings.b2_linearSlop);
        }
Esempio n. 11
0
    public static float Distance(b2Vec2 a, b2Vec2 b)
    {
        b2Vec2 c = a - b;

        return(c.Length());
    }
Esempio n. 12
0
    internal override bool SolvePositionConstraints(b2SolverData data)
    {
        b2Vec2 cA = data.positions[m_indexA].c;
        float  aA = data.positions[m_indexA].a;
        b2Vec2 cB = data.positions[m_indexB].c;
        float  aB = data.positions[m_indexB].a;

        b2Rot qA = new b2Rot(aA);
        b2Rot qB = new b2Rot(aB);

        float angularError  = 0.0f;
        float positionError = 0.0f;

        bool fixedRotation = (m_invIA + m_invIB == 0.0f);

        // Solve angular limit constraint.
        if (m_enableLimit && m_limitState != b2LimitState.e_inactiveLimit && fixedRotation == false)
        {
            float angle        = aB - aA - m_referenceAngle;
            float limitImpulse = 0.0f;

            if (m_limitState == b2LimitState.e_equalLimits)
            {
                // Prevent large angular corrections
                float C = Utils.b2Clamp(angle - m_lowerAngle, -Settings.b2_maxAngularCorrection, Settings.b2_maxAngularCorrection);
                limitImpulse = -m_motorMass * C;
                angularError = Utils.b2Abs(C);
            }
            else if (m_limitState == b2LimitState.e_atLowerLimit)
            {
                float C = angle - m_lowerAngle;
                angularError = -C;

                // Prevent large angular corrections and allow some slop.
                C            = Utils.b2Clamp(C + Settings.b2_angularSlop, -Settings.b2_maxAngularCorrection, 0.0f);
                limitImpulse = -m_motorMass * C;
            }
            else if (m_limitState == b2LimitState.e_atUpperLimit)
            {
                float C = angle - m_upperAngle;
                angularError = C;

                // Prevent large angular corrections and allow some slop.
                C            = Utils.b2Clamp(C - Settings.b2_angularSlop, 0.0f, Settings.b2_maxAngularCorrection);
                limitImpulse = -m_motorMass * C;
            }

            aA -= m_invIA * limitImpulse;
            aB += m_invIB * limitImpulse;
        }

        {
            // Solve point-to-point constraint.
            qA.Set(aA);
            qB.Set(aB);
            b2Vec2 rA = Utils.b2Mul(qA, m_localAnchorA - m_localCenterA);
            b2Vec2 rB = Utils.b2Mul(qB, m_localAnchorB - m_localCenterB);

            b2Vec2 C = cB + rB - cA - rA;
            positionError = C.Length();

            float mA = m_invMassA;
            float mB = m_invMassB;
            float iA = m_invIA;
            float iB = m_invIB;

            b2Mat22 K = new b2Mat22();
            K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
            K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
            K.ey.x = K.ex.y;
            K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;

            b2Vec2 impulse = -K.Solve(C);

            cA -= mA * impulse;
            aA -= iA * Utils.b2Cross(rA, impulse);

            cB += mB * impulse;
            aB += iB * Utils.b2Cross(rB, impulse);
        }

        data.positions[m_indexA].c = cA;
        data.positions[m_indexA].a = aA;
        data.positions[m_indexB].c = cB;
        data.positions[m_indexB].a = aB;

        return(positionError <= Settings.b2_linearSlop && angularError <= Settings.b2_angularSlop);
    }
Esempio n. 13
0
    public void SolveTOI(b2TimeStep subStep, int toiIndexA, int toiIndexB)
    {
        Debug.Assert(toiIndexA < m_bodyCount);
        Debug.Assert(toiIndexB < m_bodyCount);

        // Initialize the body state.
        for (int i = 0; i < m_bodyCount; ++i)
        {
            b2Body b = m_bodies[i];


            m_positions[i].c = b.m_sweep.c;
            m_positions[i].a = b.m_sweep.a;


            m_velocities[i].v = b.m_linearVelocity;
            m_velocities[i].w = b.m_angularVelocity;
        }

        b2ContactSolverDef contactSolverDef = new b2ContactSolverDef();

        contactSolverDef.contacts = m_contacts;
        contactSolverDef.count    = m_contactCount;

        contactSolverDef.step       = subStep;
        contactSolverDef.positions  = m_positions;
        contactSolverDef.velocities = m_velocities;
        b2ContactSolver contactSolver = new b2ContactSolver(contactSolverDef);

        // Solve position constraints.
        for (int i = 0; i < subStep.positionIterations; ++i)
        {
            bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB);
            if (contactsOkay)
            {
                break;
            }
        }

#if false
        //	// Is the new position really safe?
        //	for (int32 i = 0; i < m_contactCount; ++i)
        //	{
        //		b2Contact* c = m_contacts[i];
        //		b2Fixture* fA = c->GetFixtureA();
        //		b2Fixture* fB = c->GetFixtureB();
        //
        //		b2Body* bA = fA->GetBody();
        //		b2Body* bB = fB->GetBody();
        //
        //		int32 indexA = c->GetChildIndexA();
        //		int32 indexB = c->GetChildIndexB();
        //
        //		b2DistanceInput input;
        //		input.proxyA.Set(fA->GetShape(), indexA);
        //		input.proxyB.Set(fB->GetShape(), indexB);
        //		input.transformA = bA->GetTransform();
        //		input.transformB = bB->GetTransform();
        //		input.useRadii = false;
        //
        //		b2DistanceOutput output;
        //		b2SimplexCache cache;
        //		cache.count = 0;
        //		b2Distance(&output, &cache, &input);
        //
        //		if (output.distance == 0 || cache.count == 3)
        //		{
        //			cache.count += 0;
        //		}
        //	}
#endif

        // Leap of faith to new safe state.


        m_bodies[toiIndexA].m_sweep.c0 = m_positions[toiIndexA].c;
        m_bodies[toiIndexA].m_sweep.a0 = m_positions[toiIndexA].a;


        m_bodies[toiIndexB].m_sweep.c0 = m_positions[toiIndexB].c;
        m_bodies[toiIndexB].m_sweep.a0 = m_positions[toiIndexB].a;

        // No warm starting is needed for TOI events because warm
        // starting impulses were applied in the discrete solver.
        contactSolver.InitializeVelocityConstraints();

        // Solve velocity constraints.
        for (int i = 0; i < subStep.velocityIterations; ++i)
        {
            contactSolver.SolveVelocityConstraints();
        }

        // Don't store the TOI contact forces for warm starting
        // because they can be quite large.

        float h = subStep.dt;

        // Integrate positions
        for (int i = 0; i < m_bodyCount; ++i)
        {
            b2Vec2 c = m_positions[i].c;
            float  a = m_positions[i].a;
            b2Vec2 v = m_velocities[i].v;
            float  w = m_velocities[i].w;

            // Check for large velocities
            b2Vec2 translation = h * v;
            if (Utils.b2Dot(translation, translation) > (Settings.b2_maxTranslationSquared))
            {
                float ratio = Settings.b2_maxTranslation / translation.Length();
                v *= ratio;
            }

            float rotation = h * w;
            if (rotation * rotation > Settings.b2_maxRotationSquared)
            {
                float ratio = (0.5f * Settings.b2_pi) / Utils.b2Abs(rotation);
                w *= ratio;
            }

            // Integrate
            c += h * v;
            a += h * w;



            m_positions[i].c = c;
            m_positions[i].a = a;


            m_velocities[i].v = v;
            m_velocities[i].w = w;

            // Sync bodies
            b2Body body = m_bodies[i];


            body.m_sweep.c         = c;
            body.m_sweep.a         = a;
            body.m_linearVelocity  = v;
            body.m_angularVelocity = w;
            body.SynchronizeTransform();
        }

        Report(contactSolver.m_velocityConstraints);
    }
Esempio n. 14
0
    public void Solve(b2Profile profile, b2TimeStep step, b2Vec2 gravity, bool allowSleep)
    {
        b2Timer timer = new b2Timer();

        float h = step.dt;

        // Integrate velocities and apply damping. Initialize the body state.
        for (int i = 0; i < m_bodyCount; ++i)
        {
            b2Body b = m_bodies[i];

            b2Vec2 c = new b2Vec2(b.m_sweep.c);
            float  a = b.m_sweep.a;

            b2Vec2 v = new b2Vec2(b.m_linearVelocity);
            float  w = b.m_angularVelocity;

            // Store positions for continuous collision.
            b.m_sweep.c0 = b.m_sweep.c;
            b.m_sweep.a0 = b.m_sweep.a;

            if (b.m_type == BodyType.b2_dynamicBody)
            {
                // Integrate velocities.
                v += h * (b.m_gravityScale * gravity + b.m_invMass * b.m_force);
                w += h * b.m_invI * b.m_torque;

                // Apply damping.
                // ODE: dv/dt + c * v = 0
                // Solution: v(t) = v0 * exp(-c * t)
                // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
                // v2 = exp(-c * dt) * v1
                // Pade approximation:
                // v2 = v1 * 1 / (1 + c * dt)
                v *= 1.0f / (1.0f + h * b.m_linearDamping);
                w *= 1.0f / (1.0f + h * b.m_angularDamping);
            }

            m_positions[i].c  = c;
            m_positions[i].a  = a;
            m_velocities[i].v = v;
            m_velocities[i].w = w;
        }

        timer.Reset();

        // Solver data
        b2SolverData solverData = new b2SolverData();

        solverData.step       = step;
        solverData.positions  = m_positions;
        solverData.velocities = m_velocities;

        // Initialize velocity constraints.
        b2ContactSolverDef contactSolverDef = new b2ContactSolverDef();


        contactSolverDef.step       = step;
        contactSolverDef.contacts   = m_contacts;
        contactSolverDef.count      = m_contactCount;
        contactSolverDef.positions  = m_positions;
        contactSolverDef.velocities = m_velocities;

        b2ContactSolver contactSolver = new b2ContactSolver(contactSolverDef);

        contactSolver.InitializeVelocityConstraints();

        if (step.warmStarting)
        {
            contactSolver.WarmStart();
        }

        for (int i = 0; i < m_jointCount; ++i)
        {
            m_joints[i].InitVelocityConstraints(solverData);
        }

        profile.solveInit = timer.GetMilliseconds();

        // Solve velocity constraints
        timer.Reset();
        for (int i = 0; i < step.velocityIterations; ++i)
        {
            for (int j = 0; j < m_jointCount; ++j)
            {
                m_joints[j].SolveVelocityConstraints(solverData);
            }

            contactSolver.SolveVelocityConstraints();
        }

        // Store impulses for warm starting
        contactSolver.StoreImpulses();
        profile.solveVelocity = timer.GetMilliseconds();

        // Integrate positions
        for (int i = 0; i < m_bodyCount; ++i)
        {
            b2Vec2 c = m_positions[i].c;
            float  a = m_positions[i].a;
            b2Vec2 v = m_velocities[i].v;
            float  w = m_velocities[i].w;

            // Check for large velocities
            b2Vec2 translation = h * v;
            if (Utils.b2Dot(translation, translation) > (Settings.b2_maxTranslation * Settings.b2_maxTranslation))
            {
                float ratio = Settings.b2_maxTranslation / translation.Length();
                v *= ratio;
            }

            float rotation = h * w;
            if (rotation * rotation > Settings.b2_maxRotationSquared)
            {
                float ratio = (0.5f * Settings.b2_pi) / Utils.b2Abs(rotation);
                w *= ratio;
            }

            // Integrate
            c += h * v;
            a += h * w;

            m_positions[i].c  = c;
            m_positions[i].a  = a;
            m_velocities[i].v = v;
            m_velocities[i].w = w;
        }

        // Solve position constraints
        timer.Reset();
        bool positionSolved = false;

        for (int i = 0; i < step.positionIterations; ++i)
        {
            bool contactsOkay = contactSolver.SolvePositionConstraints();

            bool jointsOkay = true;
            for (int j = 0; j < m_jointCount; ++j)
            {
                bool jointOkay = m_joints[j].SolvePositionConstraints(solverData);
                jointsOkay = jointsOkay && jointOkay;
            }

            if (contactsOkay && jointsOkay)
            {
                // Exit early if the position errors are small.
                positionSolved = true;
                break;
            }
        }

        // Copy state buffers back to the bodies
        for (int i = 0; i < m_bodyCount; ++i)
        {
            b2Body body = m_bodies[i];
            body.m_sweep.c         = m_positions[i].c;
            body.m_sweep.a         = m_positions[i].a;
            body.m_linearVelocity  = m_velocities[i].v;
            body.m_angularVelocity = m_velocities[i].w;
            body.SynchronizeTransform();
        }

        profile.solvePosition = timer.GetMilliseconds();

        Report(contactSolver.m_velocityConstraints);

        if (allowSleep)
        {
            float minSleepTime = float.MaxValue;

            const float linTolSqr = Settings.b2_linearSleepTolerance * Settings.b2_linearSleepTolerance;
            float       angTolSqr = Settings.b2_angularSlop * Settings.b2_angularSlop;

            for (int i = 0; i < m_bodyCount; ++i)
            {
                b2Body b = m_bodies[i];
                if (b.GetType() == BodyType.b2_staticBody)
                {
                    continue;
                }

                if ((b.m_flags & b2Body.BodyFlags.e_autoSleepFlag) == 0 || b.m_angularVelocity * b.m_angularVelocity > angTolSqr || Utils.b2Dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr)
                {
                    b.m_sleepTime = 0.0f;
                    minSleepTime  = 0.0f;
                }
                else
                {
                    b.m_sleepTime += h;
                    minSleepTime   = Utils.b2Min(minSleepTime, b.m_sleepTime);
                }
            }

            if (minSleepTime >= Settings.b2_timeToSleep && positionSolved)
            {
                for (int i = 0; i < m_bodyCount; ++i)
                {
                    b2Body b = m_bodies[i];
                    b.SetAwake(false);
                }
            }
        }
    }
Esempio n. 15
0
        public override void InitVelocityConstraints(b2SolverData data)
        {
            m_indexA       = m_bodyA.IslandIndex;
            m_indexB       = m_bodyB.IslandIndex;
            m_localCenterA = m_bodyA.Sweep.localCenter;
            m_localCenterB = m_bodyB.Sweep.localCenter;
            m_invMassA     = m_bodyA.InvertedMass;
            m_invMassB     = m_bodyB.InvertedMass;
            m_invIA        = m_bodyA.InvertedI;
            m_invIB        = m_bodyB.InvertedI;

            b2Vec2 cA = data.positions[m_indexA].c;
            float  aA = data.positions[m_indexA].a;
            b2Vec2 vA = data.velocities[m_indexA].v;
            float  wA = data.velocities[m_indexA].w;

            b2Vec2 cB = data.positions[m_indexB].c;
            float  aB = data.positions[m_indexB].a;
            b2Vec2 vB = data.velocities[m_indexB].v;
            float  wB = data.velocities[m_indexB].w;

            b2Rot qA = new b2Rot(aA);
            b2Rot qB = new b2Rot(aB);

            m_rA = b2Math.b2Mul(qA, m_localAnchorA - m_localCenterA);
            m_rB = b2Math.b2Mul(qB, m_localAnchorB - m_localCenterB);
            m_u  = cB + m_rB - cA - m_rA;

            // Handle singularity.
            float length = m_u.Length();

            if (length > b2Settings.b2_linearSlop)
            {
                m_u *= 1.0f / length;
            }
            else
            {
                m_u.Set(0.0f, 0.0f);
            }

            float crAu    = b2Math.b2Cross(m_rA, m_u);
            float crBu    = b2Math.b2Cross(m_rB, m_u);
            float invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;

            // Compute the effective mass matrix.
            m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;

            if (m_frequencyHz > 0.0f)
            {
                float C = length - m_length;

                // Frequency
                float omega = 2.0f * (float)Math.PI * m_frequencyHz;

                // Damping coefficient
                float d = 2.0f * m_mass * m_dampingRatio * omega;

                // Spring stiffness
                float k = m_mass * omega * omega;

                // magic formulas
                float h = data.step.dt;
                m_gamma = h * (d + h * k);
                m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
                m_bias  = C * h * k * m_gamma;

                invMass += m_gamma;
                m_mass   = invMass != 0.0f ? 1.0f / invMass : 0.0f;
            }
            else
            {
                m_gamma = 0.0f;
                m_bias  = 0.0f;
            }

            if (data.step.warmStarting)
            {
                // Scale the impulse to support a variable time step.
                m_impulse *= data.step.dtRatio;

                b2Vec2 P = m_impulse * m_u;
                vA -= m_invMassA * P;
                wA -= m_invIA * b2Math.b2Cross(m_rA, P);
                vB += m_invMassB * P;
                wB += m_invIB * b2Math.b2Cross(m_rB, P);
            }
            else
            {
                m_impulse = 0.0f;
            }

            data.velocities[m_indexA].v = vA;
            data.velocities[m_indexA].w = wA;
            data.velocities[m_indexB].v = vB;
            data.velocities[m_indexB].w = wB;
        }
Esempio n. 16
0
        public void Solve(ref b2Profile profile, b2TimeStep step, b2Vec2 gravity, bool allowSleep)
        {
            b2Timer timer = new b2Timer();

            float h = step.dt;

            // Integrate velocities and apply damping. Initialize the body state.
            for (int i = 0; i < m_bodyCount; ++i)
            {
                b2Body b = m_bodies[i];

                b2Vec2 c = b.Sweep.c;
                float  a = b.Sweep.a;
                b2Vec2 v = b.LinearVelocity;
                float  w = b.AngularVelocity;

                // Store positions for continuous collision.
                b.Sweep.c0 = b.Sweep.c;
                b.Sweep.a0 = b.Sweep.a;

                if (b.BodyType == b2BodyType.b2_dynamicBody)
                {
                    // Integrate velocities.
                    v += h * (b.GravityScale * gravity + b.InvertedMass * b.Force);
                    w += h * b.InvertedI * b.Torque;

                    // Apply damping.
                    // ODE: dv/dt + c * v = 0
                    // Solution: v(t) = v0 * exp(-c * t)
                    // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
                    // v2 = exp(-c * dt) * v1
                    // Taylor expansion:
                    // v2 = (1.0f - c * dt) * v1
                    v *= b2Math.b2Clamp(1.0f - h * b.LinearDamping, 0.0f, 1.0f);
                    w *= b2Math.b2Clamp(1.0f - h * b.AngularDamping, 0.0f, 1.0f);
                }

                m_positions[i].c  = c;
                m_positions[i].a  = a;
                m_velocities[i].v = v;
                m_velocities[i].w = w;
            }

            timer.Reset();

            // Solver data
            b2SolverData solverData = new b2SolverData();

            solverData.step       = step;
            solverData.positions  = m_positions;
            solverData.velocities = m_velocities;

            // Initialize velocity constraints.
            b2ContactSolverDef contactSolverDef;

            contactSolverDef.step       = step;
            contactSolverDef.contacts   = m_contacts;
            contactSolverDef.count      = m_contactCount;
            contactSolverDef.positions  = m_positions;
            contactSolverDef.velocities = m_velocities;

            b2ContactSolver contactSolver = new b2ContactSolver(contactSolverDef);

            contactSolver.InitializeVelocityConstraints();

            if (step.warmStarting)
            {
                contactSolver.WarmStart();
            }

            for (int i = 0; i < m_jointCount; ++i)
            {
                m_joints[i].InitVelocityConstraints(solverData);
            }

            profile.solveInit = timer.GetMilliseconds();

            // Solve velocity constraints
            timer.Reset();
            for (int i = 0; i < step.velocityIterations; ++i)
            {
                for (int j = 0; j < m_jointCount; ++j)
                {
                    m_joints[j].SolveVelocityConstraints(solverData);
                }

                contactSolver.SolveVelocityConstraints();
            }

            // Store impulses for warm starting
            contactSolver.StoreImpulses();
            profile.solveVelocity = timer.GetMilliseconds();

            // Integrate positions
            for (int i = 0; i < m_bodyCount; ++i)
            {
                b2Vec2 c = m_positions[i].c;
                float  a = m_positions[i].a;
                b2Vec2 v = m_velocities[i].v;
                float  w = m_velocities[i].w;

                // Check for large velocities
                b2Vec2 translation = h * v;
                if (b2Math.b2Dot(translation, translation) > b2Settings.b2_maxTranslationSquared)
                {
                    float ratio = b2Settings.b2_maxTranslation / translation.Length();
                    v *= ratio;
                }

                float rotation = h * w;
                if (rotation * rotation > b2Settings.b2_maxRotationSquared)
                {
                    float ratio = b2Settings.b2_maxRotation / Math.Abs(rotation);
                    w *= ratio;
                }

                // Integrate
                c += h * v;
                a += h * w;

                m_positions[i].c  = c;
                m_positions[i].a  = a;
                m_velocities[i].v = v;
                m_velocities[i].w = w;
            }

            // Solve position constraints
            timer.Reset();
            bool positionSolved = false;

            for (int i = 0; i < step.positionIterations; ++i)
            {
                bool contactsOkay = contactSolver.SolvePositionConstraints();

                bool jointsOkay = true;
                for (int i2 = 0; i2 < m_jointCount; ++i2)
                {
                    bool jointOkay = m_joints[i2].SolvePositionConstraints(solverData);
                    jointsOkay = jointsOkay && jointOkay;
                }

                if (contactsOkay && jointsOkay)
                {
                    // Exit early if the position errors are small.
                    positionSolved = true;
                    break;
                }
            }

            // Copy state buffers back to the bodies
            for (int i = 0; i < m_bodyCount; ++i)
            {
                b2Body body = m_bodies[i];
                body.Sweep.c         = m_positions[i].c;
                body.Sweep.a         = m_positions[i].a;
                body.LinearVelocity  = m_velocities[i].v;
                body.AngularVelocity = m_velocities[i].w;
                body.SynchronizeTransform();
            }

            profile.solvePosition = timer.GetMilliseconds();

            Report(contactSolver.m_velocityConstraints);

            if (allowSleep)
            {
                float minSleepTime = b2Settings.b2_maxFloat;

                float linTolSqr = b2Settings.b2_linearSleepTolerance * b2Settings.b2_linearSleepTolerance;
                float angTolSqr = b2Settings.b2_angularSleepTolerance * b2Settings.b2_angularSleepTolerance;

                for (int i = 0; i < m_bodyCount; ++i)
                {
                    b2Body b = m_bodies[i];
                    if (b.BodyType == b2BodyType.b2_staticBody)
                    {
                        continue;
                    }

                    if (!(b.BodyFlags.HasFlag(b2BodyFlags.e_autoSleepFlag)) ||
                        b.AngularVelocity * b.AngularVelocity > angTolSqr ||
                        b2Math.b2Dot(b.LinearVelocity, b.LinearVelocity) > linTolSqr)
                    {
                        b.SleepTime  = 0.0f;
                        minSleepTime = 0.0f;
                    }
                    else
                    {
                        b.SleepTime += h;
                        minSleepTime = Math.Min(minSleepTime, b.SleepTime);
                    }
                }

                if (minSleepTime >= b2Settings.b2_timeToSleep && positionSolved)
                {
                    for (int i = 0; i < m_bodyCount; ++i)
                    {
                        b2Body b = m_bodies[i];
                        b.SetAwake(false);
                    }
                }
            }
        }