internal unsafe void Initialize(SimplexCache *cache,
                                        Shape shapeA, XForm transformA,
                                        Shape shapeB, XForm transformB)
        {
            ShapeA = shapeA;
            ShapeB = shapeB;
            int count = cache->Count;

            Box2DXDebug.Assert(0 < count && count < 3);

            if (count == 1)
            {
                FaceType = Type.Points;
                Vec2 localPointA = ShapeA.GetVertex(cache->IndexA[0]);
                Vec2 localPointB = ShapeB.GetVertex(cache->IndexB[0]);
                Vec2 pointA      = Common.Math.Mul(transformA, localPointA);
                Vec2 pointB      = Common.Math.Mul(transformB, localPointB);
                Axis = pointB - pointA;
                Axis.Normalize();
            }
            else if (cache->IndexB[0] == cache->IndexB[1])
            {
                // Two points on A and one on B
                FaceType = Type.FaceA;
                Vec2 localPointA1 = ShapeA.GetVertex(cache->IndexA[0]);
                Vec2 localPointA2 = ShapeA.GetVertex(cache->IndexA[1]);
                Vec2 localPointB  = ShapeB.GetVertex(cache->IndexB[0]);
                LocalPoint = 0.5f * (localPointA1 + localPointA2);
                Axis       = Vec2.Cross(localPointA2 - localPointA1, 1.0f);
                Axis.Normalize();

                Vec2 normal = Common.Math.Mul(transformA.R, Axis);
                Vec2 pointA = Common.Math.Mul(transformA, LocalPoint);
                Vec2 pointB = Common.Math.Mul(transformB, localPointB);

                float s = Vec2.Dot(pointB - pointA, normal);
                if (s < 0.0f)
                {
                    Axis = -Axis;
                }
            }
            else
            {
                // Two points on B and one or two points on A.
                // We ignore the second point on A.
                FaceType = Type.FaceB;
                Vec2 localPointA  = shapeA.GetVertex(cache->IndexA[0]);
                Vec2 localPointB1 = shapeB.GetVertex(cache->IndexB[0]);
                Vec2 localPointB2 = shapeB.GetVertex(cache->IndexB[1]);
                LocalPoint = 0.5f * (localPointB1 + localPointB2);
                Axis       = Vec2.Cross(localPointB2 - localPointB1, 1.0f);
                Axis.Normalize();

                Vec2 normal = Common.Math.Mul(transformB.R, Axis);
                Vec2 pointB = Common.Math.Mul(transformB, LocalPoint);
                Vec2 pointA = Common.Math.Mul(transformA, localPointA);

                float s = Vec2.Dot(pointA - pointB, normal);
                if (s < 0.0f)
                {
                    Axis = -Axis;
                }
            }
        }
Example #2
0
        internal override void InitVelocityConstraints(TimeStep step)
        {
            Body b1 = _body1;
            Body b2 = _body2;

            Vector2 r1 = b1.GetTransform().TransformDirection(_localAnchor1 - b1.GetLocalCenter());
            Vector2 r2 = b2.GetTransform().TransformDirection(_localAnchor2 - b2.GetLocalCenter());

            Vector2 p1 = b1._sweep.C + r1;
            Vector2 p2 = b2._sweep.C + r2;

            Vector2 s1 = _ground.GetTransform().position + _groundAnchor1;
            Vector2 s2 = _ground.GetTransform().position + _groundAnchor2;

            // Get the pulley axes.
            _u1 = p1 - s1;
            _u2 = p2 - s2;

            float length1 = _u1.Length;
            float length2 = _u2.Length;

            if (length1 > Settings.LinearSlop)
            {
                _u1 *= 1.0f / length1;
            }
            else
            {
                _u1 = Vector2.Zero;
            }

            if (length2 > Settings.LinearSlop)
            {
                _u2 *= 1.0f / length2;
            }
            else
            {
                _u2 = Vector2.Zero;
            }

            float C = _constant - length1 - _ratio * length2;

            if (C > 0.0f)
            {
                _state   = LimitState.InactiveLimit;
                _impulse = 0.0f;
            }
            else
            {
                _state = LimitState.AtUpperLimit;
            }

            if (length1 < _maxLength1)
            {
                _limitState1   = LimitState.InactiveLimit;
                _limitImpulse1 = 0.0f;
            }
            else
            {
                _limitState1 = LimitState.AtUpperLimit;
            }

            if (length2 < _maxLength2)
            {
                _limitState2   = LimitState.InactiveLimit;
                _limitImpulse2 = 0.0f;
            }
            else
            {
                _limitState2 = LimitState.AtUpperLimit;
            }

            // Compute effective mass.
            float cr1u1 = r1.Cross(_u1);
            float cr2u2 = r2.Cross(_u2);

            _limitMass1 = b1._invMass + b1._invI * cr1u1 * cr1u1;
            _limitMass2 = b2._invMass + b2._invI * cr2u2 * cr2u2;
            _pulleyMass = _limitMass1 + _ratio * _ratio * _limitMass2;
            Box2DXDebug.Assert(_limitMass1 > Settings.FLT_EPSILON);
            Box2DXDebug.Assert(_limitMass2 > Settings.FLT_EPSILON);
            Box2DXDebug.Assert(_pulleyMass > Settings.FLT_EPSILON);
            _limitMass1 = 1.0f / _limitMass1;
            _limitMass2 = 1.0f / _limitMass2;
            _pulleyMass = 1.0f / _pulleyMass;

            if (step.WarmStarting)
            {
                // Scale impulses to support variable time steps.
                _impulse       *= step.DtRatio;
                _limitImpulse1 *= step.DtRatio;
                _limitImpulse2 *= step.DtRatio;

                // Warm starting.
                Vector2 P1 = -(_impulse + _limitImpulse1) * _u1;
                Vector2 P2 = (-_ratio * _impulse - _limitImpulse2) * _u2;
                b1._linearVelocity  += b1._invMass * P1;
                b1._angularVelocity += b1._invI * r1.Cross(P1);
                b2._linearVelocity  += b2._invMass * P2;
                b2._angularVelocity += b2._invI * r2.Cross(P2);
            }
            else
            {
                _impulse       = 0.0f;
                _limitImpulse1 = 0.0f;
                _limitImpulse2 = 0.0f;
            }
        }
Example #3
0
        // Create and destroy proxies. These call Flush first.
        public ushort CreateProxy(AABB aabb, object userData)
        {
            Box2DXDebug.Assert(_proxyCount < Settings.MaxProxies);
            Box2DXDebug.Assert(_freeProxy != PairManager.NullProxy);

            ushort proxyId = _freeProxy;
            Proxy  proxy   = _proxyPool[proxyId];

            _freeProxy = proxy.Next;

            proxy.OverlapCount = 0;
            proxy.UserData     = userData;

            int boundCount = 2 * _proxyCount;

            ushort[] lowerValues = new ushort[2], upperValues = new ushort[2];
            ComputeBounds(out lowerValues, out upperValues, aabb);

            for (int axis = 0; axis < 2; ++axis)
            {
                Bound[] bounds = _bounds[axis];
                int     lowerIndex, upperIndex;
                Query(out lowerIndex, out upperIndex, lowerValues[axis], upperValues[axis], bounds, boundCount, axis);

#warning "Check this"
                //memmove(bounds + upperIndex + 2, bounds + upperIndex, (boundCount - upperIndex) * sizeof(b2Bound));
                Bound[] tmp = new Bound[boundCount - upperIndex];
                for (int i = 0; i < (boundCount - upperIndex); i++)
                {
                    tmp[i] = bounds[upperIndex + i].Clone();
                }
                for (int i = 0; i < (boundCount - upperIndex); i++)
                {
                    bounds[upperIndex + 2 + i] = tmp[i];
                }

                //memmove(bounds + lowerIndex + 1, bounds + lowerIndex, (upperIndex - lowerIndex) * sizeof(b2Bound));
                tmp = new Bound[upperIndex - lowerIndex];
                for (int i = 0; i < (upperIndex - lowerIndex); i++)
                {
                    tmp[i] = bounds[lowerIndex + i].Clone();
                }
                for (int i = 0; i < (upperIndex - lowerIndex); i++)
                {
                    bounds[lowerIndex + 1 + i] = tmp[i];
                }

                // The upper index has increased because of the lower bound insertion.
                ++upperIndex;

                // Copy in the new bounds.
                bounds[lowerIndex].Value   = lowerValues[axis];
                bounds[lowerIndex].ProxyId = proxyId;
                bounds[upperIndex].Value   = upperValues[axis];
                bounds[upperIndex].ProxyId = proxyId;

                bounds[lowerIndex].StabbingCount = lowerIndex == 0 ? (ushort)0 : bounds[lowerIndex - 1].StabbingCount;
                bounds[upperIndex].StabbingCount = bounds[upperIndex - 1].StabbingCount;

                // Adjust the stabbing count between the new bounds.
                for (int index = lowerIndex; index < upperIndex; ++index)
                {
                    ++bounds[index].StabbingCount;
                }

                // Adjust the all the affected bound indices.
                for (int index = lowerIndex; index < boundCount + 2; ++index)
                {
                    Proxy proxy_ = _proxyPool[bounds[index].ProxyId];
                    if (bounds[index].IsLower)
                    {
                        proxy_.LowerBounds[axis] = (ushort)index;
                    }
                    else
                    {
                        proxy_.UpperBounds[axis] = (ushort)index;
                    }
                }
            }

            ++_proxyCount;

            Box2DXDebug.Assert(_queryResultCount < Settings.MaxProxies);

            // Create pairs if the AABB is in range.
            for (int i = 0; i < _queryResultCount; ++i)
            {
                Box2DXDebug.Assert(_queryResults[i] < Settings.MaxProxies);
                Box2DXDebug.Assert(_proxyPool[_queryResults[i]].IsValid);

                _pairManager.AddBufferedPair(proxyId, _queryResults[i]);
            }

            _pairManager.Commit();

            if (IsValidate)
            {
                Validate();
            }

            // Prepare for next query.
            _queryResultCount = 0;
            IncrementTimeStamp();

            return(proxyId);
        }
Example #4
0
        internal void ContactSolverSetup(Manifold manifold, WorldManifold worldManifold, ContactConstraint cc)
        {
            // this is kind of yucky but we do know these were setup before entry to this method
            var bodyA = cc.BodyA;
            var bodyB = cc.BodyB;

            Vector2 vA = bodyA._linearVelocity;
            Vector2 vB = bodyB._linearVelocity;
            float   wA = bodyA._angularVelocity;
            float   wB = bodyB._angularVelocity;

            ContactConstraintPoint[] ccPointsPtr = cc.Points;
            for (int j = 0; j < cc.PointCount; ++j)
            {
                ManifoldPoint          cp  = manifold.Points[j];
                ContactConstraintPoint ccp = ccPointsPtr[j];

                ccp.NormalImpulse  = cp.NormalImpulse;
                ccp.TangentImpulse = cp.TangentImpulse;

                ccp.LocalPoint = cp.LocalPoint;

                ccp.RA = worldManifold.Points[j] - bodyA._sweep.C;
                ccp.RB = worldManifold.Points[j] - bodyB._sweep.C;

                float rnA = ccp.RA.Cross(cc.Normal);
                float rnB = ccp.RB.Cross(cc.Normal);
                rnA *= rnA;
                rnB *= rnB;

                float kNormal = bodyA._invMass + bodyB._invMass + bodyA._invI * rnA + bodyB._invI * rnB;

                Box2DXDebug.Assert(kNormal > Common.Settings.FLT_EPSILON);
                ccp.NormalMass = 1.0f / kNormal;

                float kEqualized = bodyA._mass * bodyA._invMass + bodyB._mass * bodyB._invMass;
                kEqualized += bodyA._mass * bodyA._invI * rnA + bodyB._mass * bodyB._invI * rnB;

                Box2DXDebug.Assert(kEqualized > Common.Settings.FLT_EPSILON);
                ccp.EqualizedMass = 1.0f / kEqualized;

                Vector2 tangent = cc.Normal.CrossScalarPostMultiply(1.0f);

                float rtA = ccp.RA.Cross(tangent);
                float rtB = ccp.RB.Cross(tangent);
                rtA *= rtA;
                rtB *= rtB;

                float kTangent = bodyA._invMass + bodyB._invMass + bodyA._invI * rtA + bodyB._invI * rtB;

                Box2DXDebug.Assert(kTangent > Common.Settings.FLT_EPSILON);
                ccp.TangentMass = 1.0f / kTangent;

                // Setup a velocity bias for restitution.
                ccp.VelocityBias = 0.0f;
                float vRel = Vector2.Dot(cc.Normal, vB + ccp.RB.CrossScalarPreMultiply(wB) - vA - ccp.RA.CrossScalarPreMultiply(wA));
                if (vRel < -Common.Settings.VelocityThreshold)
                {
                    ccp.VelocityBias = -cc.Restitution * vRel;
                }
            }

            // If we have two points, then prepare the block solver.
            if (cc.PointCount == 2)
            {
                ContactConstraintPoint ccp1 = ccPointsPtr[0];
                ContactConstraintPoint ccp2 = ccPointsPtr[1];

                float invMassA = bodyA._invMass;
                float invIA    = bodyA._invI;
                float invMassB = bodyB._invMass;
                float invIB    = bodyB._invI;

                float rn1A = ccp1.RA.Cross(cc.Normal);
                float rn1B = ccp1.RB.Cross(cc.Normal);
                float rn2A = ccp2.RA.Cross(cc.Normal);
                float rn2B = ccp2.RB.Cross(cc.Normal);

                float k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B;
                float k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B;
                float k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B;

                // Ensure a reasonable condition number.
                const float k_maxConditionNumber = 100.0f;
                if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
                {
                    // K is safe to invert.
                    cc.K.Col1     = new Vector2(k11, k12);
                    cc.K.Col2     = new Vector2(k12, k22);
                    cc.NormalMass = cc.K.GetInverse();
                }
                else
                {
                    // The constraints are redundant, just use one.
                    // TODO_ERIN use deepest?
                    cc.PointCount = 1;
                }
            }
        }
Example #5
0
        public void SolveVelocityConstraints()
        {
            for (int i = 0; i < _constraintCount; ++i)
            {
                ContactConstraint c = _constraints[i];
                Body  bodyA         = c.BodyA;
                Body  bodyB         = c.BodyB;
                float wA            = bodyA._angularVelocity;
                float wB            = bodyB._angularVelocity;
                Vec2  vA            = bodyA._linearVelocity;
                Vec2  vB            = bodyB._linearVelocity;
                float invMassA      = bodyA._invMass;
                float invIA         = bodyA._invI;
                float invMassB      = bodyB._invMass;
                float invIB         = bodyB._invI;
                Vec2  normal        = c.Normal;
                Vec2  tangent       = Vec2.Cross(normal, 1.0f);
                float friction      = c.Friction;

                Box2DNetDebug.Assert(c.PointCount == 1 || c.PointCount == 2);

                unsafe
                {
                    fixed(ContactConstraintPoint *pointsPtr = c.Points)
                    {
                        // Solve tangent constraints
                        for (int j = 0; j < c.PointCount; ++j)
                        {
                            ContactConstraintPoint *ccp = &pointsPtr[j];

                            // Relative velocity at contact
                            Vec2 dv = vB + Vec2.Cross(wB, ccp->RB) - vA - Vec2.Cross(wA, ccp->RA);

                            // Compute tangent force
                            float vt     = Vec2.Dot(dv, tangent);
                            float lambda = ccp->TangentMass * (-vt);

                            // b2Clamp the accumulated force
                            float maxFriction = friction * ccp->NormalImpulse;
                            float newImpulse  = Common.Math.Clamp(ccp->TangentImpulse + lambda, -maxFriction, maxFriction);
                            lambda = newImpulse - ccp->TangentImpulse;

                            // Apply contact impulse
                            Vec2 P = lambda * tangent;

                            vA -= invMassA * P;
                            wA -= invIA * Vec2.Cross(ccp->RA, P);

                            vB += invMassB * P;
                            wB += invIB * Vec2.Cross(ccp->RB, P);

                            ccp->TangentImpulse = newImpulse;
                        }

                        // Solve normal constraints
                        if (c.PointCount == 1)
                        {
                            ContactConstraintPoint ccp = c.Points[0];

                            // Relative velocity at contact
                            Vec2 dv = vB + Vec2.Cross(wB, ccp.RB) - vA - Vec2.Cross(wA, ccp.RA);

                            // Compute normal impulse
                            float vn     = Vec2.Dot(dv, normal);
                            float lambda = -ccp.NormalMass * (vn - ccp.VelocityBias);

                            // Clamp the accumulated impulse
                            float newImpulse = Common.Math.Max(ccp.NormalImpulse + lambda, 0.0f);
                            lambda = newImpulse - ccp.NormalImpulse;

                            // Apply contact impulse
                            Vec2 P = lambda * normal;
                            vA -= invMassA * P;
                            wA -= invIA * Vec2.Cross(ccp.RA, P);

                            vB += invMassB * P;
                            wB += invIB * Vec2.Cross(ccp.RB, P);
                            ccp.NormalImpulse = newImpulse;
                        }
                        else
                        {
                            // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
                            // Build the mini LCP for this contact patch
                            //
                            // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
                            //
                            // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
                            // b = vn_0 - velocityBias
                            //
                            // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
                            // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
                            // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid
                            // solution that satisfies the problem is chosen.
                            //
                            // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
                            // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
                            //
                            // Substitute:
                            //
                            // x = x' - a
                            //
                            // Plug into above equation:
                            //
                            // vn = A * x + b
                            //    = A * (x' - a) + b
                            //    = A * x' + b - A * a
                            //    = A * x' + b'
                            // b' = b - A * a;

                            ContactConstraintPoint *cp1 = &pointsPtr[0];
                            ContactConstraintPoint *cp2 = &pointsPtr[1];

                            Vec2 a = new Vec2(cp1->NormalImpulse, cp2->NormalImpulse);
                            Box2DNetDebug.Assert(a.X >= 0.0f && a.Y >= 0.0f);

                            // Relative velocity at contact
                            Vec2 dv1 = vB + Vec2.Cross(wB, cp1->RB) - vA - Vec2.Cross(wA, cp1->RA);
                            Vec2 dv2 = vB + Vec2.Cross(wB, cp2->RB) - vA - Vec2.Cross(wA, cp2->RA);

                            // Compute normal velocity
                            float vn1 = Vec2.Dot(dv1, normal);
                            float vn2 = Vec2.Dot(dv2, normal);

                            Vec2 b;
                            b.X = vn1 - cp1->VelocityBias;
                            b.Y = vn2 - cp2->VelocityBias;
                            b  -= Common.Math.Mul(c.K, a);

                            const float k_errorTol = 1e-3f;
                            //B2_NOT_USED(k_errorTol);

                            for (; ;)
                            {
                                //
                                // Case 1: vn = 0
                                //
                                // 0 = A * x' + b'
                                //
                                // Solve for x':
                                //
                                // x' = - inv(A) * b'
                                //
                                Vec2 x = -Common.Math.Mul(c.NormalMass, b);

                                if (x.X >= 0.0f && x.Y >= 0.0f)
                                {
                                    // Resubstitute for the incremental impulse
                                    Vec2 d = x - a;

                                    // Apply incremental impulse
                                    Vec2 P1 = d.X * normal;
                                    Vec2 P2 = d.Y * normal;
                                    vA -= invMassA * (P1 + P2);
                                    wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));

                                    vB += invMassB * (P1 + P2);
                                    wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));

                                    // Accumulate
                                    cp1->NormalImpulse = x.X;
                                    cp2->NormalImpulse = x.Y;

#if DEBUG_SOLVER
                                    // Postconditions
                                    dv1 = vB + Vec2.Cross(wB, cp1->RB) - vA - Vec2.Cross(wA, cp1->RA);
                                    dv2 = vB + Vec2.Cross(wB, cp2->RB) - vA - Vec2.Cross(wA, cp2->RA);

                                    // Compute normal velocity
                                    vn1 = Vec2.Dot(dv1, normal);
                                    vn2 = Vec2.Dot(dv2, normal);

                                    Box2DXDebug.Assert(Common.Math.Abs(vn1 - cp1.VelocityBias) < k_errorTol);
                                    Box2DXDebug.Assert(Common.Math.Abs(vn2 - cp2.VelocityBias) < k_errorTol);
#endif
                                    break;
                                }

                                //
                                // Case 2: vn1 = 0 and x2 = 0
                                //
                                //   0 = a11 * x1' + a12 * 0 + b1'
                                // vn2 = a21 * x1' + a22 * 0 + b2'
                                //
                                x.X = -cp1->NormalMass * b.X;
                                x.Y = 0.0f;
                                vn1 = 0.0f;
                                vn2 = c.K.Col1.Y * x.X + b.Y;

                                if (x.X >= 0.0f && vn2 >= 0.0f)
                                {
                                    // Resubstitute for the incremental impulse
                                    Vec2 d = x - a;

                                    // Apply incremental impulse
                                    Vec2 P1 = d.X * normal;
                                    Vec2 P2 = d.Y * normal;
                                    vA -= invMassA * (P1 + P2);
                                    wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));

                                    vB += invMassB * (P1 + P2);
                                    wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));

                                    // Accumulate
                                    cp1->NormalImpulse = x.X;
                                    cp2->NormalImpulse = x.Y;

#if DEBUG_SOLVER
                                    // Postconditions
                                    dv1 = vB + Vec2.Cross(wB, cp1->RB) - vA - Vec2.Cross(wA, cp1->RA);

                                    // Compute normal velocity
                                    vn1 = Vec2.Dot(dv1, normal);

                                    Box2DXDebug.Assert(Common.Math.Abs(vn1 - cp1.VelocityBias) < k_errorTol);
#endif
                                    break;
                                }


                                //
                                // Case 3: w2 = 0 and x1 = 0
                                //
                                // vn1 = a11 * 0 + a12 * x2' + b1'
                                //   0 = a21 * 0 + a22 * x2' + b2'
                                //
                                x.X = 0.0f;
                                x.Y = -cp2->NormalMass * b.Y;
                                vn1 = c.K.Col2.X * x.Y + b.X;
                                vn2 = 0.0f;

                                if (x.Y >= 0.0f && vn1 >= 0.0f)
                                {
                                    // Resubstitute for the incremental impulse
                                    Vec2 d = x - a;

                                    // Apply incremental impulse
                                    Vec2 P1 = d.X * normal;
                                    Vec2 P2 = d.Y * normal;
                                    vA -= invMassA * (P1 + P2);
                                    wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));

                                    vB += invMassB * (P1 + P2);
                                    wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));

                                    // Accumulate
                                    cp1->NormalImpulse = x.X;
                                    cp2->NormalImpulse = x.Y;

#if DEBUG_SOLVER
                                    // Postconditions
                                    dv2 = vB + Vec2.Cross(wB, cp2->RB) - vA - Vec2.Cross(wA, cp2->RA);

                                    // Compute normal velocity
                                    vn2 = Vec2.Dot(dv2, normal);

                                    Box2DXDebug.Assert(Common.Math.Abs(vn2 - cp2.VelocityBias) < k_errorTol);
#endif
                                    break;
                                }

                                //
                                // Case 4: x1 = 0 and x2 = 0
                                //
                                // vn1 = b1
                                // vn2 = b2;
                                x.X = 0.0f;
                                x.Y = 0.0f;
                                vn1 = b.X;
                                vn2 = b.Y;

                                if (vn1 >= 0.0f && vn2 >= 0.0f)
                                {
                                    // Resubstitute for the incremental impulse
                                    Vec2 d = x - a;

                                    // Apply incremental impulse
                                    Vec2 P1 = d.X * normal;
                                    Vec2 P2 = d.Y * normal;
                                    vA -= invMassA * (P1 + P2);
                                    wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));

                                    vB += invMassB * (P1 + P2);
                                    wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));

                                    // Accumulate
                                    cp1->NormalImpulse = x.X;
                                    cp2->NormalImpulse = x.Y;

                                    break;
                                }

                                // No solution, give up. This is hit sometimes, but it doesn't seem to matter.
                                break;
                            }
                        }

                        bodyA._linearVelocity  = vA;
                        bodyA._angularVelocity = wA;
                        bodyB._linearVelocity  = vB;
                        bodyB._angularVelocity = wB;
                    }
                }
            }
        }
Example #6
0
        internal PolygonShape(ShapeDef def) : base(def)
        {
            Box2DXDebug.Assert(def.Type == ShapeType.PolygonShape);
            this._type = ShapeType.PolygonShape;
            PolygonDef polygonDef = (PolygonDef)def;

            this._vertexCount = polygonDef.VertexCount;
            Box2DXDebug.Assert(3 <= this._vertexCount && this._vertexCount <= Settings.MaxPolygonVertices);
            for (int i = 0; i < this._vertexCount; i++)
            {
                this._vertices[i] = polygonDef.Vertices[i];
            }
            for (int i = 0; i < this._vertexCount; i++)
            {
                int  num  = i;
                int  num2 = (i + 1 < this._vertexCount) ? (i + 1) : 0;
                Vec2 a    = this._vertices[num2] - this._vertices[num];
                Box2DXDebug.Assert(a.LengthSquared() > Settings.FLT_EPSILON * Settings.FLT_EPSILON);
                this._normals[i] = Vec2.Cross(a, 1f);
                this._normals[i].Normalize();
            }
            for (int i = 0; i < this._vertexCount; i++)
            {
                for (int j = 0; j < this._vertexCount; j++)
                {
                    if (j != i && j != (i + 1) % this._vertexCount)
                    {
                        float num3 = Vec2.Dot(this._normals[i], this._vertices[j] - this._vertices[i]);
                        Box2DXDebug.Assert(num3 < -Settings.LinearSlop);
                    }
                }
            }
            for (int i = 1; i < this._vertexCount; i++)
            {
                float num4 = Vec2.Cross(this._normals[i - 1], this._normals[i]);
                num4 = Box2DX.Common.Math.Clamp(num4, -1f, 1f);
                float num5 = (float)System.Math.Asin((double)num4);
                Box2DXDebug.Assert(num5 > Settings.AngularSlop);
            }
            this._centroid = PolygonShape.ComputeCentroid(polygonDef.Vertices, polygonDef.VertexCount);
            PolygonShape.ComputeOBB(out this._obb, this._vertices, this._vertexCount);
            for (int i = 0; i < this._vertexCount; i++)
            {
                int  num  = (i - 1 >= 0) ? (i - 1) : (this._vertexCount - 1);
                int  num2 = i;
                Vec2 a2   = this._normals[num];
                Vec2 a3   = this._normals[num2];
                Vec2 b    = this._vertices[i] - this._centroid;
                Vec2 b2   = default(Vec2);
                b2.X = Vec2.Dot(a2, b) - Settings.ToiSlop;
                b2.Y = Vec2.Dot(a3, b) - Settings.ToiSlop;
                Box2DXDebug.Assert(b2.X >= 0f);
                Box2DXDebug.Assert(b2.Y >= 0f);
                Mat22 mat = default(Mat22);
                mat.Col1.X            = a2.X;
                mat.Col2.X            = a2.Y;
                mat.Col1.Y            = a3.X;
                mat.Col2.Y            = a3.Y;
                this._coreVertices[i] = mat.Solve(b2) + this._centroid;
            }
        }
Example #7
0
        public ContactSolver(TimeStep step, Contact[] contacts, int contactCount)
        {
            this._step            = step;
            this._constraintCount = 0;
            for (int i = 0; i < contactCount; i++)
            {
                Box2DXDebug.Assert(contacts[i].IsSolid());
                this._constraintCount += contacts[i].GetManifoldCount();
            }
            this._constraints = new ContactConstraint[this._constraintCount];
            for (int i = 0; i < this._constraintCount; i++)
            {
                this._constraints[i] = new ContactConstraint();
            }
            int num = 0;

            for (int i = 0; i < contactCount; i++)
            {
                Contact    contact          = contacts[i];
                Shape      shape            = contact._shape1;
                Shape      shape2           = contact._shape2;
                Body       body             = shape.GetBody();
                Body       body2            = shape2.GetBody();
                int        manifoldCount    = contact.GetManifoldCount();
                Manifold[] manifolds        = contact.GetManifolds();
                float      friction         = Settings.MixFriction(shape.Friction, shape2.Friction);
                float      restitution      = Settings.MixRestitution(shape.Restitution, shape2.Restitution);
                Vec2       linearVelocity   = body._linearVelocity;
                Vec2       linearVelocity2  = body2._linearVelocity;
                float      angularVelocity  = body._angularVelocity;
                float      angularVelocity2 = body2._angularVelocity;
                for (int j = 0; j < manifoldCount; j++)
                {
                    Manifold manifold = manifolds[j];
                    Box2DXDebug.Assert(manifold.PointCount > 0);
                    Vec2 normal = manifold.Normal;
                    Box2DXDebug.Assert(num < this._constraintCount);
                    ContactConstraint contactConstraint = this._constraints[num];
                    contactConstraint.Body1       = body;
                    contactConstraint.Body2       = body2;
                    contactConstraint.Manifold    = manifold;
                    contactConstraint.Normal      = normal;
                    contactConstraint.PointCount  = manifold.PointCount;
                    contactConstraint.Friction    = friction;
                    contactConstraint.Restitution = restitution;
                    for (int k = 0; k < contactConstraint.PointCount; k++)
                    {
                        ManifoldPoint          manifoldPoint          = manifold.Points[k];
                        ContactConstraintPoint contactConstraintPoint = contactConstraint.Points[k];
                        contactConstraintPoint.NormalImpulse  = manifoldPoint.NormalImpulse;
                        contactConstraintPoint.TangentImpulse = manifoldPoint.TangentImpulse;
                        contactConstraintPoint.Separation     = manifoldPoint.Separation;
                        contactConstraintPoint.LocalAnchor1   = manifoldPoint.LocalPoint1;
                        contactConstraintPoint.LocalAnchor2   = manifoldPoint.LocalPoint2;
                        contactConstraintPoint.R1             = Box2DX.Common.Math.Mul(body.GetXForm().R, manifoldPoint.LocalPoint1 - body.GetLocalCenter());
                        contactConstraintPoint.R2             = Box2DX.Common.Math.Mul(body2.GetXForm().R, manifoldPoint.LocalPoint2 - body2.GetLocalCenter());
                        float num2 = Vec2.Cross(contactConstraintPoint.R1, normal);
                        float num3 = Vec2.Cross(contactConstraintPoint.R2, normal);
                        num2 *= num2;
                        num3 *= num3;
                        float num4 = body._invMass + body2._invMass + body._invI * num2 + body2._invI * num3;
                        Box2DXDebug.Assert(num4 > Settings.FLT_EPSILON);
                        contactConstraintPoint.NormalMass = 1f / num4;
                        float num5 = body._mass * body._invMass + body2._mass * body2._invMass;
                        num5 += body._mass * body._invI * num2 + body2._mass * body2._invI * num3;
                        Box2DXDebug.Assert(num5 > Settings.FLT_EPSILON);
                        contactConstraintPoint.EqualizedMass = 1f / num5;
                        Vec2  b    = Vec2.Cross(normal, 1f);
                        float num6 = Vec2.Cross(contactConstraintPoint.R1, b);
                        float num7 = Vec2.Cross(contactConstraintPoint.R2, b);
                        num6 *= num6;
                        num7 *= num7;
                        float num8 = body._invMass + body2._invMass + body._invI * num6 + body2._invI * num7;
                        Box2DXDebug.Assert(num8 > Settings.FLT_EPSILON);
                        contactConstraintPoint.TangentMass  = 1f / num8;
                        contactConstraintPoint.VelocityBias = 0f;
                        if (contactConstraintPoint.Separation > 0f)
                        {
                            contactConstraintPoint.VelocityBias = -step.Inv_Dt * contactConstraintPoint.Separation;
                        }
                        else
                        {
                            float num9 = Vec2.Dot(contactConstraint.Normal, linearVelocity2 + Vec2.Cross(angularVelocity2, contactConstraintPoint.R2) - linearVelocity - Vec2.Cross(angularVelocity, contactConstraintPoint.R1));
                            if (num9 < -Settings.VelocityThreshold)
                            {
                                contactConstraintPoint.VelocityBias = -contactConstraint.Restitution * num9;
                            }
                        }
                    }
                    if (contactConstraint.PointCount == 2)
                    {
                        ContactConstraintPoint contactConstraintPoint2 = contactConstraint.Points[0];
                        ContactConstraintPoint contactConstraintPoint3 = contactConstraint.Points[1];
                        float invMass  = body._invMass;
                        float invI     = body._invI;
                        float invMass2 = body2._invMass;
                        float invI2    = body2._invI;
                        float num10    = Vec2.Cross(contactConstraintPoint2.R1, normal);
                        float num11    = Vec2.Cross(contactConstraintPoint2.R2, normal);
                        float num12    = Vec2.Cross(contactConstraintPoint3.R1, normal);
                        float num13    = Vec2.Cross(contactConstraintPoint3.R2, normal);
                        float num14    = invMass + invMass2 + invI * num10 * num10 + invI2 * num11 * num11;
                        float num15    = invMass + invMass2 + invI * num12 * num12 + invI2 * num13 * num13;
                        float num16    = invMass + invMass2 + invI * num10 * num12 + invI2 * num11 * num13;
                        if (num14 * num14 < 100f * (num14 * num15 - num16 * num16))
                        {
                            contactConstraint.K.Col1.Set(num14, num16);
                            contactConstraint.K.Col2.Set(num16, num15);
                            contactConstraint.NormalMass = contactConstraint.K.Invert();
                        }
                        else
                        {
                            contactConstraint.PointCount = 1;
                        }
                    }
                    num++;
                }
            }
            Box2DXDebug.Assert(num == this._constraintCount);
        }
Example #8
0
        internal Body(BodyDef bd, World world)
        {
            Box2DXDebug.Assert(world._lock == false);

            _flags = 0;

            if (bd.IsBullet)
            {
                _flags |= BodyFlags.Bullet;
            }
            if (bd.FixedRotation)
            {
                _flags |= BodyFlags.FixedRotation;
            }
            if (bd.AllowSleep)
            {
                _flags |= BodyFlags.AllowSleep;
            }
            if (bd.IsSleeping)
            {
                _flags |= BodyFlags.Sleep;
            }

            _world = world;

            _xf.Position = bd.Position;
            _xf.R.Set(bd.Angle);

            _sweep.LocalCenter = bd.MassData.Center;
            _sweep.T0          = 1.0f;
            _sweep.A0          = _sweep.A = bd.Angle;
            _sweep.C0          = _sweep.C = Common.Math.Mul(_xf, _sweep.LocalCenter);

            //_jointList = null;
            //_contactList = null;
            //_controllerList = null;
            //_prev = null;
            //_next = null;

            _linearVelocity  = bd.LinearVelocity;
            _angularVelocity = bd.AngularVelocity;

            _linearDamping  = bd.LinearDamping;
            _angularDamping = bd.AngularDamping;

            //_force.Set(0.0f, 0.0f);
            //_torque = 0.0f;

            //_linearVelocity.SetZero();
            //_angularVelocity = 0.0f;

            //_sleepTime = 0.0f;

            //_invMass = 0.0f;
            //_I = 0.0f;
            //_invI = 0.0f;

            _mass = bd.MassData.Mass;

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

            _I = bd.MassData.I;

            if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
            {
                _invI = 1.0f / _I;
            }

            if (_invMass == 0.0f && _invI == 0.0f)
            {
                _type = BodyType.Static;
            }
            else
            {
                _type = BodyType.Dynamic;
            }

            _userData = bd.UserData;

            //_fixtureList = null;
            //_fixtureCount = 0;
        }
        public void Create(BroadPhase broadPhase, Body body, Transform xf, FixtureDef def)
        {
            UserData    = def.UserData;
            Friction    = def.Friction;
            Restitution = def.Restitution;
            Density     = def.Density;

            _body = body;
            _next = null;

            Filter = def.Filter;

            _isSensor = def.IsSensor;

            _type = def.Type;

            // Allocate and initialize the child shape.
            switch (_type)
            {
            case ShapeType.CircleShape:
            {
                CircleShape circle    = new CircleShape();
                CircleDef   circleDef = (CircleDef)def;
                circle._position = circleDef.LocalPosition;
                circle._radius   = circleDef.Radius;
                _shape           = circle;
            }
            break;

            case ShapeType.PolygonShape:
            {
                PolygonShape polygon    = new PolygonShape();
                PolygonDef   polygonDef = (PolygonDef)def;
                polygon.Set(polygonDef.Vertices, polygonDef.VertexCount);
                _shape = polygon;
            }
            break;

            case ShapeType.EdgeShape:
            {
                EdgeShape edge    = new EdgeShape();
                EdgeDef   edgeDef = (EdgeDef)def;
                edge.Set(edgeDef.Vertex1, edgeDef.Vertex2);
                _shape = edge;
            }
            break;

            default:
                Box2DXDebug.Assert(false);
                break;
            }

            // Create proxy in the broad-phase.
            AABB aabb;

            _shape.ComputeAABB(out aabb, xf);

            bool inRange = broadPhase.InRange(aabb);

            // You are creating a shape outside the world box.
            Box2DXDebug.Assert(inRange);

            if (inRange)
            {
                _proxyId = broadPhase.CreateProxy(aabb, this);
            }
            else
            {
                _proxyId = PairManager.NullProxy;
            }
        }
Example #10
0
        int QuerySegment(Segment segment, object[] userData, int maxCount, SortKeyFunc sortKey)
        {
            float maxLambda = 1;

            float dx = (segment.P2.X - segment.P1.X) * _quantizationFactor.X;
            float dy = (segment.P2.Y - segment.P1.Y) * _quantizationFactor.Y;

            int sx = dx < -Settings.FLT_EPSILON ? -1 : (dx > Settings.FLT_EPSILON ? 1 : 0);
            int sy = dy < -Settings.FLT_EPSILON ? -1 : (dy > Settings.FLT_EPSILON ? 1 : 0);

            Box2DXDebug.Assert(sx != 0 || sy != 0);

            float p1x = (segment.P1.X - _worldAABB.LowerBound.X) * _quantizationFactor.X;
            float p1y = (segment.P1.Y - _worldAABB.LowerBound.Y) * _quantizationFactor.Y;

#if ALLOWUNSAFE
            ushort *startValues  = stackalloc ushort[2];
            ushort *startValues2 = stackalloc ushort[2];
#else
            ushort[] startValues  = new ushort[2];
            ushort[] startValues2 = new ushort[2];
#endif

            int xIndex;
            int yIndex;

            ushort proxyId;
            Proxy  proxy;

            // TODO_ERIN implement fast float to ushort conversion.
            startValues[0]  = (ushort)((ushort)(p1x) & (BROADPHASE_MAX - 1));
            startValues2[0] = (ushort)((ushort)(p1x) | 1);

            startValues[1]  = (ushort)((ushort)(p1y) & (BROADPHASE_MAX - 1));
            startValues2[1] = (ushort)((ushort)(p1y) | 1);

            //First deal with all the proxies that contain segment.p1
            int lowerIndex;
            int upperIndex;
            Query(out lowerIndex, out upperIndex, startValues[0], startValues2[0], _bounds[0], 2 * _proxyCount, 0);
            if (sx >= 0)
            {
                xIndex = upperIndex - 1;
            }
            else
            {
                xIndex = lowerIndex;
            }
            Query(out lowerIndex, out upperIndex, startValues[1], startValues2[1], _bounds[1], 2 * _proxyCount, 1);
            if (sy >= 0)
            {
                yIndex = upperIndex - 1;
            }
            else
            {
                yIndex = lowerIndex;
            }

            //If we are using sortKey, then sort what we have so far, filtering negative keys
            if (sortKey != null)
            {
                //Fill keys
                for (int j = 0; j < _queryResultCount; j++)
                {
                    _querySortKeys[j] = sortKey(_proxyPool[_queryResults[j]].UserData);
                }
                //Bubble sort keys
                //Sorting negative values to the top, so we can easily remove them
                int i = 0;
                while (i < _queryResultCount - 1)
                {
                    float a = _querySortKeys[i];
                    float b = _querySortKeys[i + 1];
                    if ((a < 0) ? (b >= 0) : (a > b && b >= 0))
                    {
                        _querySortKeys[i + 1] = a;
                        _querySortKeys[i]     = b;
                        ushort tempValue = _queryResults[i + 1];
                        _queryResults[i + 1] = _queryResults[i];
                        _queryResults[i]     = tempValue;
                        i--;
                        if (i == -1)
                        {
                            i = 1;
                        }
                    }
                    else
                    {
                        i++;
                    }
                }
                //Skim off negative values
                while (_queryResultCount > 0 && _querySortKeys[_queryResultCount - 1] < 0)
                {
                    _queryResultCount--;
                }
            }

            //Now work through the rest of the segment
            for (; ;)
            {
                float xProgress = 0;
                float yProgress = 0;
                if (xIndex < 0 || xIndex >= _proxyCount * 2)
                {
                    break;
                }
                if (yIndex < 0 || yIndex >= _proxyCount * 2)
                {
                    break;
                }
                if (sx != 0)
                {
                    //Move on to the next bound
                    if (sx > 0)
                    {
                        xIndex++;
                        if (xIndex == _proxyCount * 2)
                        {
                            break;
                        }
                    }
                    else
                    {
                        xIndex--;
                        if (xIndex < 0)
                        {
                            break;
                        }
                    }
                    xProgress = (_bounds[0][xIndex].Value - p1x) / dx;
                }
                if (sy != 0)
                {
                    //Move on to the next bound
                    if (sy > 0)
                    {
                        yIndex++;
                        if (yIndex == _proxyCount * 2)
                        {
                            break;
                        }
                    }
                    else
                    {
                        yIndex--;
                        if (yIndex < 0)
                        {
                            break;
                        }
                    }
                    yProgress = (_bounds[1][yIndex].Value - p1y) / dy;
                }
                for (; ;)
                {
                    if (sy == 0 || (sx != 0 && xProgress < yProgress))
                    {
                        if (xProgress > maxLambda)
                        {
                            break;
                        }

                        //Check that we are entering a proxy, not leaving
                        if (sx > 0 ? _bounds[0][xIndex].IsLower : _bounds[0][xIndex].IsUpper)
                        {
                            //Check the other axis of the proxy
                            proxyId = _bounds[0][xIndex].ProxyId;
                            proxy   = _proxyPool[proxyId];
                            if (sy >= 0)
                            {
                                if (proxy.LowerBounds[1] <= yIndex - 1 && proxy.UpperBounds[1] >= yIndex)
                                {
                                    //Add the proxy
                                    if (sortKey != null)
                                    {
                                        AddProxyResult(proxyId, proxy, maxCount, sortKey);
                                    }
                                    else
                                    {
                                        _queryResults[_queryResultCount] = proxyId;
                                        ++_queryResultCount;
                                    }
                                }
                            }
                            else
                            {
                                if (proxy.LowerBounds[1] <= yIndex && proxy.UpperBounds[1] >= yIndex + 1)
                                {
                                    //Add the proxy
                                    if (sortKey != null)
                                    {
                                        AddProxyResult(proxyId, proxy, maxCount, sortKey);
                                    }
                                    else
                                    {
                                        _queryResults[_queryResultCount] = proxyId;
                                        ++_queryResultCount;
                                    }
                                }
                            }
                        }

                        //Early out
                        if (sortKey != null && _queryResultCount == maxCount && _queryResultCount > 0 && xProgress > _querySortKeys[_queryResultCount - 1])
                        {
                            break;
                        }

                        //Move on to the next bound
                        if (sx > 0)
                        {
                            xIndex++;
                            if (xIndex == _proxyCount * 2)
                            {
                                break;
                            }
                        }
                        else
                        {
                            xIndex--;
                            if (xIndex < 0)
                            {
                                break;
                            }
                        }
                        xProgress = (_bounds[0][xIndex].Value - p1x) / dx;
                    }
                    else
                    {
                        if (yProgress > maxLambda)
                        {
                            break;
                        }

                        //Check that we are entering a proxy, not leaving
                        if (sy > 0 ? _bounds[1][yIndex].IsLower : _bounds[1][yIndex].IsUpper)
                        {
                            //Check the other axis of the proxy
                            proxyId = _bounds[1][yIndex].ProxyId;
                            proxy   = _proxyPool[proxyId];
                            if (sx >= 0)
                            {
                                if (proxy.LowerBounds[0] <= xIndex - 1 && proxy.UpperBounds[0] >= xIndex)
                                {
                                    //Add the proxy
                                    if (sortKey != null)
                                    {
                                        AddProxyResult(proxyId, proxy, maxCount, sortKey);
                                    }
                                    else
                                    {
                                        _queryResults[_queryResultCount] = proxyId;
                                        ++_queryResultCount;
                                    }
                                }
                            }
                            else
                            {
                                if (proxy.LowerBounds[0] <= xIndex && proxy.UpperBounds[0] >= xIndex + 1)
                                {
                                    //Add the proxy
                                    if (sortKey != null)
                                    {
                                        AddProxyResult(proxyId, proxy, maxCount, sortKey);
                                    }
                                    else
                                    {
                                        _queryResults[_queryResultCount] = proxyId;
                                        ++_queryResultCount;
                                    }
                                }
                            }
                        }

                        //Early out
                        if (sortKey != null && _queryResultCount == maxCount && _queryResultCount > 0 && yProgress > _querySortKeys[_queryResultCount - 1])
                        {
                            break;
                        }

                        //Move on to the next bound
                        if (sy > 0)
                        {
                            yIndex++;
                            if (yIndex == _proxyCount * 2)
                            {
                                break;
                            }
                        }
                        else
                        {
                            yIndex--;
                            if (yIndex < 0)
                            {
                                break;
                            }
                        }
                        yProgress = (_bounds[1][yIndex].Value - p1y) / dy;
                    }
                }

                break;
            }

            int count = 0;
            for (int i = 0; i < _queryResultCount && count < maxCount; ++i, ++count)
            {
                Box2DXDebug.Assert(_queryResults[i] < Settings.MaxProxies);
                Proxy proxy_ = _proxyPool[_queryResults[i]];
                Box2DXDebug.Assert(proxy_.IsValid);
                userData[i] = proxy_.UserData;
            }

            // Prepare for next query.
            _queryResultCount = 0;
            IncrementTimeStamp();

            return(count);
        }
Example #11
0
 public void Dispose()
 {
     Box2DXDebug.Assert(_world._lock == false);
     // shapes and joints are destroyed in World.Destroy
 }
Example #12
0
        // Call MoveProxy as many times as you like, then when you are done
        // call Commit to finalized the proxy pairs (for your time step).
        public void MoveProxy(int proxyId, AABB aabb)
        {
            if (proxyId == PairManager.NullProxy || Settings.MaxProxies <= proxyId)
            {
                Box2DXDebug.Assert(false);
                return;
            }

            if (aabb.IsValid == false)
            {
                Box2DXDebug.Assert(false);
                return;
            }

            int boundCount = 2 * _proxyCount;

            Proxy proxy = _proxyPool[proxyId];

            // Get new bound values
            BoundValues newValues = new BoundValues();;

            ComputeBounds(out newValues.LowerValues, out newValues.UpperValues, aabb);

            // Get old bound values
            BoundValues oldValues = new BoundValues();

            for (int axis = 0; axis < 2; ++axis)
            {
                oldValues.LowerValues[axis] = _bounds[axis][proxy.LowerBounds[axis]].Value;
                oldValues.UpperValues[axis] = _bounds[axis][proxy.UpperBounds[axis]].Value;
            }

            for (int axis = 0; axis < 2; ++axis)
            {
                Bound[] bounds = _bounds[axis];

                int lowerIndex = proxy.LowerBounds[axis];
                int upperIndex = proxy.UpperBounds[axis];

                ushort lowerValue = newValues.LowerValues[axis];
                ushort upperValue = newValues.UpperValues[axis];

                int deltaLower = lowerValue - bounds[lowerIndex].Value;
                int deltaUpper = upperValue - bounds[upperIndex].Value;

                bounds[lowerIndex].Value = lowerValue;
                bounds[upperIndex].Value = upperValue;

                //
                // Expanding adds overlaps
                //

                // Should we move the lower bound down?
                if (deltaLower < 0)
                {
                    int index = lowerIndex;
                    while (index > 0 && lowerValue < bounds[index - 1].Value)
                    {
                        Bound bound     = bounds[index];
                        Bound prevBound = bounds[index - 1];

                        int   prevProxyId = prevBound.ProxyId;
                        Proxy prevProxy   = _proxyPool[prevBound.ProxyId];

                        ++prevBound.StabbingCount;

                        if (prevBound.IsUpper == true)
                        {
                            if (TestOverlap(newValues, prevProxy))
                            {
                                _pairManager.AddBufferedPair(proxyId, prevProxyId);
                            }

                            ++prevProxy.UpperBounds[axis];
                            ++bound.StabbingCount;
                        }
                        else
                        {
                            ++prevProxy.LowerBounds[axis];
                            --bound.StabbingCount;
                        }

                        --proxy.LowerBounds[axis];
                        Common.Math.Swap <Bound>(ref bounds[index], ref bounds[index - 1]);
                        --index;
                    }
                }

                // Should we move the upper bound up?
                if (deltaUpper > 0)
                {
                    int index = upperIndex;
                    while (index < boundCount - 1 && bounds[index + 1].Value <= upperValue)
                    {
                        Bound bound       = bounds[index];
                        Bound nextBound   = bounds[index + 1];
                        int   nextProxyId = nextBound.ProxyId;
                        Proxy nextProxy   = _proxyPool[nextProxyId];

                        ++nextBound.StabbingCount;

                        if (nextBound.IsLower == true)
                        {
                            if (TestOverlap(newValues, nextProxy))
                            {
                                _pairManager.AddBufferedPair(proxyId, nextProxyId);
                            }

                            --nextProxy.LowerBounds[axis];
                            ++bound.StabbingCount;
                        }
                        else
                        {
                            --nextProxy.UpperBounds[axis];
                            --bound.StabbingCount;
                        }

                        ++proxy.UpperBounds[axis];
                        Common.Math.Swap <Bound>(ref bounds[index], ref bounds[index + 1]);
                        ++index;
                    }
                }

                //
                // Shrinking removes overlaps
                //

                // Should we move the lower bound up?
                if (deltaLower > 0)
                {
                    int index = lowerIndex;
                    while (index < boundCount - 1 && bounds[index + 1].Value <= lowerValue)
                    {
                        Bound bound     = bounds[index];
                        Bound nextBound = bounds[index + 1];

                        int   nextProxyId = nextBound.ProxyId;
                        Proxy nextProxy   = _proxyPool[nextProxyId];

                        --nextBound.StabbingCount;

                        if (nextBound.IsUpper)
                        {
                            if (TestOverlap(oldValues, nextProxy))
                            {
                                _pairManager.RemoveBufferedPair(proxyId, nextProxyId);
                            }

                            --nextProxy.UpperBounds[axis];
                            --bound.StabbingCount;
                        }
                        else
                        {
                            --nextProxy.LowerBounds[axis];
                            ++bound.StabbingCount;
                        }

                        ++proxy.LowerBounds[axis];
                        Common.Math.Swap <Bound>(ref bounds[index], ref bounds[index + 1]);
                        ++index;
                    }
                }

                // Should we move the upper bound down?
                if (deltaUpper < 0)
                {
                    int index = upperIndex;
                    while (index > 0 && upperValue < bounds[index - 1].Value)
                    {
                        Bound bound     = bounds[index];
                        Bound prevBound = bounds[index - 1];

                        int   prevProxyId = prevBound.ProxyId;
                        Proxy prevProxy   = _proxyPool[prevProxyId];

                        --prevBound.StabbingCount;

                        if (prevBound.IsLower == true)
                        {
                            if (TestOverlap(oldValues, prevProxy))
                            {
                                _pairManager.RemoveBufferedPair(proxyId, prevProxyId);
                            }

                            ++prevProxy.LowerBounds[axis];
                            --bound.StabbingCount;
                        }
                        else
                        {
                            ++prevProxy.UpperBounds[axis];
                            ++bound.StabbingCount;
                        }

                        --proxy.UpperBounds[axis];
                        Common.Math.Swap <Bound>(ref bounds[index], ref bounds[index - 1]);
                        --index;
                    }
                }
            }

            if (IsValidate)
            {
                Validate();
            }
        }
Example #13
0
        public override void RayCast(out RayCastOutput output, ref RayCastInput input, Transform xf)
        {
            output = new RayCastOutput();

            float lower = 0.0f, upper = input.MaxFraction;

            // Put the ray into the polygon's frame of reference.
            Vec2 p1    = Math.MulT(xf.R, input.P1 - xf.Position);
            Vec2 p2    = Math.MulT(xf.R, input.P2 - xf.Position);
            Vec2 d     = p2 - p1;
            int  index = -1;

            output.Hit = false;

            for (int i = 0; i < VertexCount; ++i)
            {
                // p = p1 + a * d
                // dot(normal, p - v) = 0
                // dot(normal, p1 - v) + a * dot(normal, d) = 0
                float numerator   = Vec2.Dot(Normals[i], Vertices[i] - p1);
                float denominator = Vec2.Dot(Normals[i], d);

                if (denominator == 0.0f)
                {
                    if (numerator < 0.0f)
                    {
                        return;
                    }
                }
                else
                {
                    // Note: we want this predicate without division:
                    // lower < numerator / denominator, where denominator < 0
                    // Since denominator < 0, we have to flip the inequality:
                    // lower < numerator / denominator <==> denominator * lower > numerator.
                    if (denominator < 0.0f && numerator < lower * denominator)
                    {
                        // Increase lower.
                        // The segment enters this half-space.
                        lower = numerator / denominator;
                        index = i;
                    }
                    else if (denominator > 0.0f && numerator < upper * denominator)
                    {
                        // Decrease upper.
                        // The segment exits this half-space.
                        upper = numerator / denominator;
                    }
                }

                if (upper < lower)
                {
                    return;
                }
            }

            Box2DXDebug.Assert(0.0f <= lower && lower <= input.MaxFraction);

            if (index >= 0)
            {
                output.Hit      = true;
                output.Fraction = lower;
                output.Normal   = Math.Mul(xf.R, Normals[index]);
                return;
            }
        }
        public static void CollidePolygonAndCircle(ref Manifold manifold,
                                                   PolygonShape polygon, XForm xf1, CircleShape circle, XForm xf2)
        {
            manifold.PointCount = 0;

            // Compute circle position in the frame of the polygon.
            Vec2 c      = Common.Math.Mul(xf2, circle.GetLocalPosition());
            Vec2 cLocal = Common.Math.MulT(xf1, c);

            // Find the min separating edge.
            int   normalIndex = 0;
            float separation  = -Settings.FLT_MAX;
            float radius      = circle.GetRadius();
            int   vertexCount = polygon.VertexCount;

            Vec2[] vertices = polygon.GetVertices();
            Vec2[] normals  = polygon.Normals;

            for (int i = 0; i < vertexCount; ++i)
            {
                float s = Vec2.Dot(normals[i], cLocal - vertices[i]);
                if (s > radius)
                {
                    // Early out.
                    return;
                }

                if (s > separation)
                {
                    separation  = s;
                    normalIndex = i;
                }
            }

            // If the center is inside the polygon ...
            if (separation < Common.Settings.FLT_EPSILON)
            {
                manifold.PointCount = 1;
                manifold.Normal     = Common.Math.Mul(xf1.R, normals[normalIndex]);
                manifold.Points[0].ID.Features.IncidentEdge   = (byte)normalIndex;
                manifold.Points[0].ID.Features.IncidentVertex = Collision.NullFeature;
                manifold.Points[0].ID.Features.ReferenceEdge  = 0;
                manifold.Points[0].ID.Features.Flip           = 0;
                Vec2 position = c - radius * manifold.Normal;
                manifold.Points[0].LocalPoint1 = Common.Math.MulT(xf1, position);
                manifold.Points[0].LocalPoint2 = Common.Math.MulT(xf2, position);
                manifold.Points[0].Separation  = separation - radius;
                return;
            }

            // Project the circle center onto the edge segment.
            int  vertIndex1 = normalIndex;
            int  vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
            Vec2 e          = vertices[vertIndex2] - vertices[vertIndex1];

            float length = e.Normalize();

            Box2DXDebug.Assert(length > Settings.FLT_EPSILON);

            // Project the center onto the edge.
            float u = Vec2.Dot(cLocal - vertices[vertIndex1], e);
            Vec2  p;

            if (u <= 0.0f)
            {
                p = vertices[vertIndex1];
                manifold.Points[0].ID.Features.IncidentEdge   = Collision.NullFeature;
                manifold.Points[0].ID.Features.IncidentVertex = (byte)vertIndex1;
            }
            else if (u >= length)
            {
                p = vertices[vertIndex2];
                manifold.Points[0].ID.Features.IncidentEdge   = Collision.NullFeature;
                manifold.Points[0].ID.Features.IncidentVertex = (byte)vertIndex2;
            }
            else
            {
                p = vertices[vertIndex1] + u * e;
                manifold.Points[0].ID.Features.IncidentEdge   = (byte)normalIndex;
                manifold.Points[0].ID.Features.IncidentVertex = Collision.NullFeature;
            }

            Vec2  d    = cLocal - p;
            float dist = d.Normalize();

            if (dist > radius)
            {
                return;
            }

            manifold.PointCount = 1;
            manifold.Normal     = Common.Math.Mul(xf1.R, d);
            Vec2 position_ = c - radius * manifold.Normal;

            manifold.Points[0].LocalPoint1 = Common.Math.MulT(xf1, position_);
            manifold.Points[0].LocalPoint2 = Common.Math.MulT(xf2, position_);
            manifold.Points[0].Separation  = dist - radius;
            manifold.Points[0].ID.Features.ReferenceEdge = 0;
            manifold.Points[0].ID.Features.Flip          = 0;
        }
Example #15
0
 public override Vector2 GetVertex(int index)
 {
     Box2DXDebug.Assert(0 <= index && index < _vertexCount);
     return(_vertices[index]);
 }
Example #16
0
        internal override void InitVelocityConstraints(TimeStep step)
        {
            Body b1 = _body1;
            Body b2 = _body2;

            Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
            Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());

            Vec2 p1 = b1._sweep.C + r1;
            Vec2 p2 = b2._sweep.C + r2;

            Vec2 s1 = _ground.GetXForm().Position + _groundAnchor1;
            Vec2 s2 = _ground.GetXForm().Position + _groundAnchor2;

            // Get the pulley axes.
            _u1 = p1 - s1;
            _u2 = p2 - s2;

            float length1 = _u1.Length();
            float length2 = _u2.Length();

            if (length1 > Settings.LinearSlop)
            {
                _u1 *= 1.0f / length1;
            }
            else
            {
                _u1.SetZero();
            }

            if (length2 > Settings.LinearSlop)
            {
                _u2 *= 1.0f / length2;
            }
            else
            {
                _u2.SetZero();
            }

            float C = _constant - length1 - _ratio * length2;

            if (C > 0.0f)
            {
                _state = LimitState.InactiveLimit;
                _force = 0.0f;
            }
            else
            {
                _state           = LimitState.AtUpperLimit;
                _positionImpulse = 0.0f;
            }

            if (length1 < _maxLength1)
            {
                _limitState1 = LimitState.InactiveLimit;
                _limitForce1 = 0.0f;
            }
            else
            {
                _limitState1           = LimitState.AtUpperLimit;
                _limitPositionImpulse1 = 0.0f;
            }

            if (length2 < _maxLength2)
            {
                _limitState2 = LimitState.InactiveLimit;
                _limitForce2 = 0.0f;
            }
            else
            {
                _limitState2           = LimitState.AtUpperLimit;
                _limitPositionImpulse2 = 0.0f;
            }

            // Compute effective mass.
            float cr1u1 = Vec2.Cross(r1, _u1);
            float cr2u2 = Vec2.Cross(r2, _u2);

            _limitMass1 = b1._invMass + b1._invI * cr1u1 * cr1u1;
            _limitMass2 = b2._invMass + b2._invI * cr2u2 * cr2u2;
            _pulleyMass = _limitMass1 + _ratio * _ratio * _limitMass2;
            Box2DXDebug.Assert(_limitMass1 > Settings.FLT_EPSILON);
            Box2DXDebug.Assert(_limitMass2 > Settings.FLT_EPSILON);
            Box2DXDebug.Assert(_pulleyMass > Settings.FLT_EPSILON);
            _limitMass1 = 1.0f / _limitMass1;
            _limitMass2 = 1.0f / _limitMass2;
            _pulleyMass = 1.0f / _pulleyMass;

            if (step.WarmStarting)
            {
                // Warm starting.
                Vec2 P1 = Settings.FORCE_SCALE(step.Dt) * (-_force - _limitForce1) * _u1;
                Vec2 P2 = Settings.FORCE_SCALE(step.Dt) * (-_ratio * _force - _limitForce2) * _u2;
                b1._linearVelocity  += b1._invMass * P1;
                b1._angularVelocity += b1._invI * Vec2.Cross(r1, P1);
                b2._linearVelocity  += b2._invMass * P2;
                b2._angularVelocity += b2._invI * Vec2.Cross(r2, P2);
            }
            else
            {
                _force       = 0.0f;
                _limitForce1 = 0.0f;
                _limitForce2 = 0.0f;
            }
        }
Example #17
0
        internal override bool SolvePositionConstraints(float baumgarte)
        {
            Body  body  = this._body1;
            Body  body2 = this._body2;
            float num   = 0f;

            if (this._enableLimit && this._limitState != LimitState.InactiveLimit)
            {
                float num2 = body2._sweep.A - body._sweep.A - this._referenceAngle;
                float num3 = 0f;
                if (this._limitState == LimitState.EqualLimits)
                {
                    float num4 = Box2DX.Common.Math.Clamp(num2, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);
                    num3 = -this._motorMass * num4;
                    num  = Box2DX.Common.Math.Abs(num4);
                }
                else
                {
                    if (this._limitState == LimitState.AtLowerLimit)
                    {
                        float num4 = num2 - this._lowerAngle;
                        num  = -num4;
                        num4 = Box2DX.Common.Math.Clamp(num4 + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0f);
                        num3 = -this._motorMass * num4;
                    }
                    else
                    {
                        if (this._limitState == LimitState.AtUpperLimit)
                        {
                            float num4 = num2 - this._upperAngle;
                            num  = num4;
                            num4 = Box2DX.Common.Math.Clamp(num4 - Settings.AngularSlop, 0f, Settings.MaxAngularCorrection);
                            num3 = -this._motorMass * num4;
                        }
                    }
                }
                Body expr_139_cp_0 = body;
                expr_139_cp_0._sweep.A = expr_139_cp_0._sweep.A - body._invI * num3;
                Body expr_154_cp_0 = body2;
                expr_154_cp_0._sweep.A = expr_154_cp_0._sweep.A + body2._invI * num3;
                body.SynchronizeTransform();
                body2.SynchronizeTransform();
            }
            Vec2  vec      = Box2DX.Common.Math.Mul(body.GetXForm().R, this._localAnchor1 - body.GetLocalCenter());
            Vec2  vec2     = Box2DX.Common.Math.Mul(body2.GetXForm().R, this._localAnchor2 - body2.GetLocalCenter());
            Vec2  vec3     = body2._sweep.C + vec2 - body._sweep.C - vec;
            float num5     = vec3.Length();
            float invMass  = body._invMass;
            float invMass2 = body2._invMass;
            float invI     = body._invI;
            float invI2    = body2._invI;
            float num6     = 10f * Settings.LinearSlop;

            if (vec3.LengthSquared() > num6 * num6)
            {
                Vec2 vec4 = vec3;
                vec4.Normalize();
                float num7 = invMass + invMass2;
                Box2DXDebug.Assert(num7 > Settings.FLT_EPSILON);
                float a             = 1f / num7;
                Vec2  v             = a * -vec3;
                float num8          = 0.5f;
                Body  expr_283_cp_0 = body;
                expr_283_cp_0._sweep.C = expr_283_cp_0._sweep.C - num8 * invMass * v;
                Body expr_2A5_cp_0 = body2;
                expr_2A5_cp_0._sweep.C = expr_2A5_cp_0._sweep.C + num8 * invMass2 * v;
                vec3 = body2._sweep.C + vec2 - body._sweep.C - vec;
            }
            Mat22 a2 = default(Mat22);

            a2.Col1.X = invMass + invMass2;
            a2.Col2.X = 0f;
            a2.Col1.Y = 0f;
            a2.Col2.Y = invMass + invMass2;
            Mat22 b = default(Mat22);

            b.Col1.X = invI * vec.Y * vec.Y;
            b.Col2.X = -invI * vec.X * vec.Y;
            b.Col1.Y = -invI * vec.X * vec.Y;
            b.Col2.Y = invI * vec.X * vec.X;
            Mat22 b2 = default(Mat22);

            b2.Col1.X = invI2 * vec2.Y * vec2.Y;
            b2.Col2.X = -invI2 * vec2.X * vec2.Y;
            b2.Col1.Y = -invI2 * vec2.X * vec2.Y;
            b2.Col2.Y = invI2 * vec2.X * vec2.X;
            Vec2 vec5          = (a2 + b + b2).Solve(-vec3);
            Body expr_465_cp_0 = body;

            expr_465_cp_0._sweep.C = expr_465_cp_0._sweep.C - body._invMass * vec5;
            Body expr_488_cp_0 = body;

            expr_488_cp_0._sweep.A = expr_488_cp_0._sweep.A - body._invI * Vec2.Cross(vec, vec5);
            Body expr_4AA_cp_0 = body2;

            expr_4AA_cp_0._sweep.C = expr_4AA_cp_0._sweep.C + body2._invMass * vec5;
            Body expr_4CD_cp_0 = body2;

            expr_4CD_cp_0._sweep.A = expr_4CD_cp_0._sweep.A + body2._invI * Vec2.Cross(vec2, vec5);
            body.SynchronizeTransform();
            body2.SynchronizeTransform();
            return(num5 <= Settings.LinearSlop && num <= Settings.AngularSlop);
        }
Example #18
0
        internal override void InitVelocityConstraints(TimeStep step)
        {
            Body b1 = _body1;
            Body b2 = _body2;

            _localCenter1 = b1.GetLocalCenter();
            _localCenter2 = b2.GetLocalCenter();

            XForm xf1 = b1.GetXForm();
            XForm xf2 = b2.GetXForm();

            // Compute the effective masses.
            Vec2 r1 = Box2DX.Common.Math.Mul(xf1.R, _localAnchor1 - _localCenter1);
            Vec2 r2 = Box2DX.Common.Math.Mul(xf2.R, _localAnchor2 - _localCenter2);
            Vec2 d  = b2._sweep.C + r2 - b1._sweep.C - r1;

            _invMass1 = b1._invMass;
            _invI1    = b1._invI;
            _invMass2 = b2._invMass;
            _invI2    = b2._invI;

            // Compute motor Jacobian and effective mass.
            {
                _axis = Box2DX.Common.Math.Mul(xf1.R, _localXAxis1);
                _a1   = Vec2.Cross(d + r1, _axis);
                _a2   = Vec2.Cross(r2, _axis);

                _motorMass = _invMass1 + _invMass2 + _invI1 * _a1 * _a1 + _invI2 * _a2 * _a2;
                Box2DXDebug.Assert(_motorMass > Settings.FLT_EPSILON);
                _motorMass = 1.0f / _motorMass;
            }

            // Prismatic constraint.
            {
                _perp = Box2DX.Common.Math.Mul(xf1.R, _localYAxis1);

                _s1 = Vec2.Cross(d + r1, _perp);
                _s2 = Vec2.Cross(r2, _perp);

                float m1 = _invMass1, m2 = _invMass2;
                float i1 = _invI1, i2 = _invI2;

                float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
                float k12 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
                float k22 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;

                _K.Col1.Set(k11, k12);
                _K.Col2.Set(k12, k22);
            }

            // Compute motor and limit terms.
            if (_enableLimit)
            {
                float jointTranslation = Vec2.Dot(_axis, d);
                if (Box2DX.Common.Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
                {
                    _limitState = LimitState.EqualLimits;
                }
                else if (jointTranslation <= _lowerTranslation)
                {
                    if (_limitState != LimitState.AtLowerLimit)
                    {
                        _limitState = LimitState.AtLowerLimit;
                        _impulse.Y  = 0.0f;
                    }
                }
                else if (jointTranslation >= _upperTranslation)
                {
                    if (_limitState != LimitState.AtUpperLimit)
                    {
                        _limitState = LimitState.AtUpperLimit;
                        _impulse.Y  = 0.0f;
                    }
                }
                else
                {
                    _limitState = LimitState.InactiveLimit;
                    _impulse.Y  = 0.0f;
                }
            }
            else
            {
                _limitState = LimitState.InactiveLimit;
            }

            if (_enableMotor == false)
            {
                _motorImpulse = 0.0f;
            }

            if (step.WarmStarting)
            {
                // Account for variable time step.
                _impulse      *= step.DtRatio;
                _motorImpulse *= step.DtRatio;

                Vec2  P  = _impulse.X * _perp + (_motorImpulse + _impulse.Y) * _axis;
                float L1 = _impulse.X * _s1 + (_motorImpulse + _impulse.Y) * _a1;
                float L2 = _impulse.X * _s2 + (_motorImpulse + _impulse.Y) * _a2;

                b1._linearVelocity  -= _invMass1 * P;
                b1._angularVelocity -= _invI1 * L1;

                b2._linearVelocity  += _invMass2 * P;
                b2._angularVelocity += _invI2 * L2;
            }
            else
            {
                _impulse.SetZero();
                _motorImpulse = 0.0f;
            }
        }
Example #19
0
 public virtual void Dispose()
 {
     Box2DXDebug.Assert(_proxyId == PairManager.NullProxy);
 }
Example #20
0
        internal override void InitVelocityConstraints(TimeStep step)
        {
            Body b1 = _bodyA;
            Body b2 = _bodyB;

            if (_enableMotor || _enableLimit)
            {
                // You cannot create a rotation limit between bodies that
                // both have fixed rotation.
                Box2DXDebug.Assert(b1._invI > 0.0f || b2._invI > 0.0f);
            }

            // Compute the effective mass matrix.
            Vec2 r1 = Box2DXMath.Mul(b1.GetTransform().R, _localAnchor1 - b1.GetLocalCenter());
            Vec2 r2 = Box2DXMath.Mul(b2.GetTransform().R, _localAnchor2 - b2.GetLocalCenter());

            // J = [-I -r1_skew I r2_skew]
            //     [ 0       -1 0       1]
            // r_skew = [-ry; rx]

            // Matlab
            // K = [ m1+r1y^2*i1+m2+r2y^2*i2,  -r1y*i1*r1x-r2y*i2*r2x,          -r1y*i1-r2y*i2]
            //     [  -r1y*i1*r1x-r2y*i2*r2x, m1+r1x^2*i1+m2+r2x^2*i2,           r1x*i1+r2x*i2]
            //     [          -r1y*i1-r2y*i2,           r1x*i1+r2x*i2,                   i1+i2]

            float m1 = b1._invMass, m2 = b2._invMass;
            float i1 = b1._invI, i2 = b2._invI;

            _mass.Col1.X = m1 + m2 + r1.Y * r1.Y * i1 + r2.Y * r2.Y * i2;
            _mass.Col2.X = -r1.Y * r1.X * i1 - r2.Y * r2.X * i2;
            _mass.Col3.X = -r1.Y * i1 - r2.Y * i2;
            _mass.Col1.Y = _mass.Col2.X;
            _mass.Col2.Y = m1 + m2 + r1.X * r1.X * i1 + r2.X * r2.X * i2;
            _mass.Col3.Y = r1.X * i1 + r2.X * i2;
            _mass.Col1.Z = _mass.Col3.X;
            _mass.Col2.Z = _mass.Col3.Y;
            _mass.Col3.Z = i1 + i2;

            _motorMass = 1.0f / (i1 + i2);

            if (_enableMotor == false)
            {
                _motorImpulse = 0.0f;
            }

            if (_enableLimit)
            {
                float jointAngle = b2._sweep.A - b1._sweep.A - _referenceAngle;
                if (Box2DXMath.Abs(_upperAngle - _lowerAngle) < 2.0f * Settings.AngularSlop)
                {
                    _limitState = LimitState.EqualLimits;
                }
                else if (jointAngle <= _lowerAngle)
                {
                    if (_limitState != LimitState.AtLowerLimit)
                    {
                        _impulse.Z = 0.0f;
                    }
                    _limitState = LimitState.AtLowerLimit;
                }
                else if (jointAngle >= _upperAngle)
                {
                    if (_limitState != LimitState.AtUpperLimit)
                    {
                        _impulse.Z = 0.0f;
                    }
                    _limitState = LimitState.AtUpperLimit;
                }
                else
                {
                    _limitState = LimitState.InactiveLimit;
                    _impulse.Z  = 0.0f;
                }
            }
            else
            {
                _limitState = LimitState.InactiveLimit;
            }

            if (step.WarmStarting)
            {
                // Scale impulses to support a variable time step.
                _impulse      *= step.DtRatio;
                _motorImpulse *= step.DtRatio;

                Vec2 P = new Vec2(_impulse.X, _impulse.Y);

                b1._linearVelocity  -= m1 * P;
                b1._angularVelocity -= i1 * (Vec2.Cross(r1, P) + _motorImpulse + _impulse.Z);

                b2._linearVelocity  += m2 * P;
                b2._angularVelocity += i2 * (Vec2.Cross(r2, P) + _motorImpulse + _impulse.Z);
            }
            else
            {
                _impulse.SetZero();
                _motorImpulse = 0.0f;
            }
        }
Example #21
0
 public void SolveVelocityConstraints()
 {
     for (int i = 0; i < this._constraintCount; i++)
     {
         ContactConstraint contactConstraint = this._constraints[i];
         Body  body     = contactConstraint.Body1;
         Body  body2    = contactConstraint.Body2;
         float num      = body._angularVelocity;
         float num2     = body2._angularVelocity;
         Vec2  vec      = body._linearVelocity;
         Vec2  vec2     = body2._linearVelocity;
         float invMass  = body._invMass;
         float invI     = body._invI;
         float invMass2 = body2._invMass;
         float invI2    = body2._invI;
         Vec2  normal   = contactConstraint.Normal;
         Vec2  vec3     = Vec2.Cross(normal, 1f);
         float friction = contactConstraint.Friction;
         Box2DXDebug.Assert(contactConstraint.PointCount == 1 || contactConstraint.PointCount == 2);
         if (contactConstraint.PointCount == 1)
         {
             ContactConstraintPoint contactConstraintPoint = contactConstraint.Points[0];
             Vec2  a    = vec2 + Vec2.Cross(num2, contactConstraintPoint.R2) - vec - Vec2.Cross(num, contactConstraintPoint.R1);
             float num3 = Vec2.Dot(a, normal);
             float num4 = -contactConstraintPoint.NormalMass * (num3 - contactConstraintPoint.VelocityBias);
             float num5 = Box2DX.Common.Math.Max(contactConstraintPoint.NormalImpulse + num4, 0f);
             num4 = num5 - contactConstraintPoint.NormalImpulse;
             Vec2 vec4 = num4 * normal;
             vec  -= invMass * vec4;
             num  -= invI * Vec2.Cross(contactConstraintPoint.R1, vec4);
             vec2 += invMass2 * vec4;
             num2 += invI2 * Vec2.Cross(contactConstraintPoint.R2, vec4);
             contactConstraintPoint.NormalImpulse = num5;
         }
         else
         {
             ContactConstraintPoint contactConstraintPoint2 = contactConstraint.Points[0];
             ContactConstraintPoint contactConstraintPoint3 = contactConstraint.Points[1];
             Vec2 vec5 = new Vec2(contactConstraintPoint2.NormalImpulse, contactConstraintPoint3.NormalImpulse);
             Box2DXDebug.Assert(vec5.X >= 0f && vec5.Y >= 0f);
             Vec2  a2   = vec2 + Vec2.Cross(num2, contactConstraintPoint2.R2) - vec - Vec2.Cross(num, contactConstraintPoint2.R1);
             Vec2  a3   = vec2 + Vec2.Cross(num2, contactConstraintPoint3.R2) - vec - Vec2.Cross(num, contactConstraintPoint3.R1);
             float num6 = Vec2.Dot(a2, normal);
             float num7 = Vec2.Dot(a3, normal);
             Vec2  vec6;
             vec6.X = num6 - contactConstraintPoint2.VelocityBias;
             vec6.Y = num7 - contactConstraintPoint3.VelocityBias;
             vec6  -= Box2DX.Common.Math.Mul(contactConstraint.K, vec5);
             Vec2 v = -Box2DX.Common.Math.Mul(contactConstraint.NormalMass, vec6);
             if (v.X >= 0f && v.Y >= 0f)
             {
                 Vec2 vec7 = v - vec5;
                 Vec2 vec8 = vec7.X * normal;
                 Vec2 vec9 = vec7.Y * normal;
                 vec  -= invMass * (vec8 + vec9);
                 num  -= invI * (Vec2.Cross(contactConstraintPoint2.R1, vec8) + Vec2.Cross(contactConstraintPoint3.R1, vec9));
                 vec2 += invMass2 * (vec8 + vec9);
                 num2 += invI2 * (Vec2.Cross(contactConstraintPoint2.R2, vec8) + Vec2.Cross(contactConstraintPoint3.R2, vec9));
                 contactConstraintPoint2.NormalImpulse = v.X;
                 contactConstraintPoint3.NormalImpulse = v.Y;
             }
             else
             {
                 v.X  = -contactConstraintPoint2.NormalMass * vec6.X;
                 v.Y  = 0f;
                 num7 = contactConstraint.K.Col1.Y * v.X + vec6.Y;
                 if (v.X >= 0f && num7 >= 0f)
                 {
                     Vec2 vec7 = v - vec5;
                     Vec2 vec8 = vec7.X * normal;
                     Vec2 vec9 = vec7.Y * normal;
                     vec  -= invMass * (vec8 + vec9);
                     num  -= invI * (Vec2.Cross(contactConstraintPoint2.R1, vec8) + Vec2.Cross(contactConstraintPoint3.R1, vec9));
                     vec2 += invMass2 * (vec8 + vec9);
                     num2 += invI2 * (Vec2.Cross(contactConstraintPoint2.R2, vec8) + Vec2.Cross(contactConstraintPoint3.R2, vec9));
                     contactConstraintPoint2.NormalImpulse = v.X;
                     contactConstraintPoint3.NormalImpulse = v.Y;
                 }
                 else
                 {
                     v.X  = 0f;
                     v.Y  = -contactConstraintPoint3.NormalMass * vec6.Y;
                     num6 = contactConstraint.K.Col2.X * v.Y + vec6.X;
                     if (v.Y >= 0f && num6 >= 0f)
                     {
                         Vec2 vec7 = v - vec5;
                         Vec2 vec8 = vec7.X * normal;
                         Vec2 vec9 = vec7.Y * normal;
                         vec  -= invMass * (vec8 + vec9);
                         num  -= invI * (Vec2.Cross(contactConstraintPoint2.R1, vec8) + Vec2.Cross(contactConstraintPoint3.R1, vec9));
                         vec2 += invMass2 * (vec8 + vec9);
                         num2 += invI2 * (Vec2.Cross(contactConstraintPoint2.R2, vec8) + Vec2.Cross(contactConstraintPoint3.R2, vec9));
                         contactConstraintPoint2.NormalImpulse = v.X;
                         contactConstraintPoint3.NormalImpulse = v.Y;
                     }
                     else
                     {
                         v.X  = 0f;
                         v.Y  = 0f;
                         num6 = vec6.X;
                         num7 = vec6.Y;
                         if (num6 >= 0f && num7 >= 0f)
                         {
                             Vec2 vec7 = v - vec5;
                             Vec2 vec8 = vec7.X * normal;
                             Vec2 vec9 = vec7.Y * normal;
                             vec  -= invMass * (vec8 + vec9);
                             num  -= invI * (Vec2.Cross(contactConstraintPoint2.R1, vec8) + Vec2.Cross(contactConstraintPoint3.R1, vec9));
                             vec2 += invMass2 * (vec8 + vec9);
                             num2 += invI2 * (Vec2.Cross(contactConstraintPoint2.R2, vec8) + Vec2.Cross(contactConstraintPoint3.R2, vec9));
                             contactConstraintPoint2.NormalImpulse = v.X;
                             contactConstraintPoint3.NormalImpulse = v.Y;
                         }
                     }
                 }
             }
         }
         for (int j = 0; j < contactConstraint.PointCount; j++)
         {
             ContactConstraintPoint contactConstraintPoint = contactConstraint.Points[j];
             Vec2  a    = vec2 + Vec2.Cross(num2, contactConstraintPoint.R2) - vec - Vec2.Cross(num, contactConstraintPoint.R1);
             float num8 = Vec2.Dot(a, vec3);
             float num4 = contactConstraintPoint.TangentMass * -num8;
             float num9 = friction * contactConstraintPoint.NormalImpulse;
             float num5 = Box2DX.Common.Math.Clamp(contactConstraintPoint.TangentImpulse + num4, -num9, num9);
             num4 = num5 - contactConstraintPoint.TangentImpulse;
             Vec2 vec4 = num4 * vec3;
             vec  -= invMass * vec4;
             num  -= invI * Vec2.Cross(contactConstraintPoint.R1, vec4);
             vec2 += invMass2 * vec4;
             num2 += invI2 * Vec2.Cross(contactConstraintPoint.R2, vec4);
             contactConstraintPoint.TangentImpulse = num5;
         }
         body._linearVelocity   = vec;
         body._angularVelocity  = num;
         body2._linearVelocity  = vec2;
         body2._angularVelocity = num2;
     }
 }
Example #22
0
        internal override bool SolvePositionConstraints(float baumgarte)
        {
            // TODO_ERIN block solve with limit.

            Body b1 = _bodyA;
            Body b2 = _bodyB;

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

            // Solve angular limit constraint.
            if (_enableLimit && _limitState != LimitState.InactiveLimit)
            {
                float angle        = b2._sweep.A - b1._sweep.A - _referenceAngle;
                float limitImpulse = 0.0f;

                if (_limitState == LimitState.EqualLimits)
                {
                    // Prevent large angular corrections
                    float C = Box2DXMath.Clamp(angle - _lowerAngle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);
                    limitImpulse = -_motorMass * C;
                    angularError = Box2DXMath.Abs(C);
                }
                else if (_limitState == LimitState.AtLowerLimit)
                {
                    float C = angle - _lowerAngle;
                    angularError = -C;

                    // Prevent large angular corrections and allow some slop.
                    C            = Box2DXMath.Clamp(C + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f);
                    limitImpulse = -_motorMass * C;
                }
                else if (_limitState == LimitState.AtUpperLimit)
                {
                    float C = angle - _upperAngle;
                    angularError = C;

                    // Prevent large angular corrections and allow some slop.
                    C            = Box2DXMath.Clamp(C - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection);
                    limitImpulse = -_motorMass * C;
                }

                b1._sweep.A -= b1._invI * limitImpulse;
                b2._sweep.A += b2._invI * limitImpulse;

                b1.SynchronizeTransform();
                b2.SynchronizeTransform();
            }

            // Solve point-to-point constraint.
            {
                Vec2 r1 = Box2DXMath.Mul(b1.GetTransform().R, _localAnchor1 - b1.GetLocalCenter());
                Vec2 r2 = Box2DXMath.Mul(b2.GetTransform().R, _localAnchor2 - b2.GetLocalCenter());

                Vec2 C = b2._sweep.C + r2 - b1._sweep.C - r1;
                positionError = C.Length();

                float invMass1 = b1._invMass, invMass2 = b2._invMass;
                float invI1 = b1._invI, invI2 = b2._invI;

                // Handle large detachment.
                float k_allowedStretch = 10.0f * Settings.LinearSlop;
                if (C.LengthSquared() > k_allowedStretch * k_allowedStretch)
                {
                    // Use a particle solution (no rotation).
                    Vec2  u = C; u.Normalize();
                    float k = invMass1 + invMass2;
                    Box2DXDebug.Assert(k > Settings.FLT_EPSILON);
                    float m       = 1.0f / k;
                    Vec2  impulse = m * (-C);
                    float k_beta  = 0.5f;
                    b1._sweep.C -= k_beta * invMass1 * impulse;
                    b2._sweep.C += k_beta * invMass2 * impulse;

                    C = b2._sweep.C + r2 - b1._sweep.C - r1;
                }

                Mat22 K1 = new Mat22();
                K1.Col1.X = invMass1 + invMass2; K1.Col2.X = 0.0f;
                K1.Col1.Y = 0.0f; K1.Col2.Y = invMass1 + invMass2;

                Mat22 K2 = new Mat22();
                K2.Col1.X = invI1 * r1.Y * r1.Y; K2.Col2.X = -invI1 * r1.X * r1.Y;
                K2.Col1.Y = -invI1 * r1.X * r1.Y; K2.Col2.Y = invI1 * r1.X * r1.X;

                Mat22 K3 = new Mat22();
                K3.Col1.X = invI2 * r2.Y * r2.Y; K3.Col2.X = -invI2 * r2.X * r2.Y;
                K3.Col1.Y = -invI2 * r2.X * r2.Y; K3.Col2.Y = invI2 * r2.X * r2.X;

                Mat22 K        = K1 + K2 + K3;
                Vec2  impulse_ = K.Solve(-C);

                b1._sweep.C -= b1._invMass * impulse_;
                b1._sweep.A -= b1._invI * Vec2.Cross(r1, impulse_);

                b2._sweep.C += b2._invMass * impulse_;
                b2._sweep.A += b2._invI * Vec2.Cross(r2, impulse_);

                b1.SynchronizeTransform();
                b2.SynchronizeTransform();
            }

            return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop);
        }
Example #23
0
 /// <summary>
 /// Get a vertex by index. Used by Distance.
 /// </summary>
 public override Vector2 GetVertex(int index)
 {
     Box2DXDebug.Assert(index == 0);
     return(_position);
 }
Example #24
0
 public PolyAndCircleContact(Fixture fixtureA, Fixture fixtureB)
     : base(fixtureA, fixtureB)
 {
     Box2DXDebug.Assert(_fixtureA.GetType() == ShapeType.PolygonShape);
     Box2DXDebug.Assert(_fixtureB.GetType() == ShapeType.CircleShape);
 }
Example #25
0
        // TODO_ERIN adjust linear velocity and torque to account for movement of center.
        /// <summary>
        /// Compute the mass properties from the attached shapes. You typically call this
        /// after adding all the shapes. If you add or remove shapes later, you may want
        /// to call this again. Note that this changes the center of mass position.
        /// </summary>
        public void SetMassFromShapes()
        {
            lock (_world._lock) {
                // Compute mass data from shapes. Each shape has its own density.
                _mass    = 0.0f;
                _invMass = 0.0f;
                _I       = 0.0f;
                _invI    = 0.0f;

                Vec2 center = Vec2.Zero;
                for (Shape s = _shapeList; s != null; s = s._next)
                {
                    MassData massData;
                    s.ComputeMass(out massData);
                    _mass  += massData.Mass;
                    center += massData.Mass * massData.Center;
                    _I     += massData.I;
                }

                // Compute center of mass, and shift the origin to the COM.
                if (_mass > 0.0f)
                {
                    _invMass = 1.0f / _mass;
                    center  *= _invMass;
                }

                if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
                {
                    // Center the inertia about the center of mass.
                    _I -= _mass * Vec2.Dot(center, center);
                    Box2DXDebug.Assert(_I > 0.0f);
                    _invI = 1.0f / _I;
                }
                else
                {
                    _I    = 0.0f;
                    _invI = 0.0f;
                }

                // Move center of mass.
                _sweep.LocalCenter = center;
                _sweep.C0          = _sweep.C = Common.Math.Mul(_xf, _sweep.LocalCenter);

                // Update the sweep radii of all child shapes.
                for (Shape s = _shapeList; s != null; s = s._next)
                {
                    s.UpdateSweepRadius(_sweep.LocalCenter);
                }

                BodyType oldType = _type;
                if (_invMass == 0.0f && _invI == 0.0f)
                {
                    _type = BodyType.Static;
                }
                else
                {
                    _type = BodyType.Dynamic;
                }

                // If the body type changed, we need to refilter the broad-phase proxies.
                if (oldType != _type)
                {
                    for (Shape s = _shapeList; s != null; s = s._next)
                    {
                        s.RefilterProxy(_world._broadPhase, _xf);
                    }
                }
            }
        }
Example #26
0
        public override SegmentCollide TestSegment(Transform xf, out float lambda, out Vector2 normal, Segment segment, float maxLambda)
        {
            lambda = 0f;
            normal = Vector2.zero;

            float lower = 0.0f, upper = maxLambda;

            Vector2 p1    = xf.InverseTransformDirection(segment.P1 - xf.position);
            Vector2 p2    = xf.InverseTransformDirection(segment.P2 - xf.position);
            Vector2 d     = p2 - p1;
            int     index = -1;

            for (int i = 0; i < _vertexCount; ++i)
            {
                // p = p1 + a * d
                // dot(normal, p - v) = 0
                // dot(normal, p1 - v) + a * dot(normal, d) = 0
                float numerator   = Vector2.Dot(_normals[i], _vertices[i] - p1);
                float denominator = Vector2.Dot(_normals[i], d);

                if (denominator == 0.0f)
                {
                    if (numerator < 0.0f)
                    {
                        return(SegmentCollide.MissCollide);
                    }
                }
                else
                {
                    // Note: we want this predicate without division:
                    // lower < numerator / denominator, where denominator < 0
                    // Since denominator < 0, we have to flip the inequality:
                    // lower < numerator / denominator <==> denominator * lower > numerator.
                    if (denominator < 0.0f && numerator < lower * denominator)
                    {
                        // Increase lower.
                        // The segment enters this half-space.
                        lower = numerator / denominator;
                        index = i;
                    }
                    else if (denominator > 0.0f && numerator < upper * denominator)
                    {
                        // Decrease upper.
                        // The segment exits this half-space.
                        upper = numerator / denominator;
                    }
                }

                if (upper < lower)
                {
                    return(SegmentCollide.MissCollide);
                }
            }

            Box2DXDebug.Assert(0.0f <= lower && lower <= maxLambda);

            if (index >= 0)
            {
                lambda = lower;
                normal = xf.TransformDirection(_normals[index]);
                return(SegmentCollide.HitCollide);
            }

            lambda = 0f;
            return(SegmentCollide.StartInsideCollide);
        }
        static void Distance(out DistanceOutput output, ref SimplexCache cache, ref DistanceInput input, Shape shapeA, Shape shapeB)
        {
            output = new DistanceOutput();

            Transform transformA = input.TransformA;
            Transform transformB = input.TransformB;

            // Initialize the simplex.
            Simplex simplex = new Simplex();

#if ALLOWUNSAFE
            fixed(SimplexCache *sPtr = &cache)
            {
                simplex.ReadCache(sPtr, shapeA, transformA, shapeB, transformB);
            }
#else
            simplex.ReadCache(cache, shapeA, transformA, shapeB, transformB);
#endif

            // Get simplex vertices as an array.
#if ALLOWUNSAFE
            SimplexVertex *vertices = &simplex._v1;
#else
            SimplexVertex[] vertices = new SimplexVertex[] { simplex._v1, simplex._v2, simplex._v3 };
#endif

            // These store the vertices of the last simplex so that we
            // can check for duplicates and prevent cycling.
#if ALLOWUNSAFE
            int *lastA = stackalloc int[4], lastB = stackalloc int[4];
#else
            int[] lastA = new int[4];
            int[] lastB = new int[4];
#endif // ALLOWUNSAFE
            int lastCount;

            // Main iteration loop.
            int       iter = 0;
            const int k_maxIterationCount = 20;
            while (iter < k_maxIterationCount)
            {
                // Copy simplex so we can identify duplicates.
                lastCount = simplex._count;
                int i;
                for (i = 0; i < lastCount; ++i)
                {
                    lastA[i] = vertices[i].indexA;
                    lastB[i] = vertices[i].indexB;
                }

                switch (simplex._count)
                {
                case 1:
                    break;

                case 2:
                    simplex.Solve2();
                    break;

                case 3:
                    simplex.Solve3();
                    break;

                default:
#if DEBUG
                    Box2DXDebug.Assert(false);
#endif
                    break;
                }

                // If we have 3 points, then the origin is in the corresponding triangle.
                if (simplex._count == 3)
                {
                    break;
                }

                // Compute closest point.
                Vector2 p           = simplex.GetClosestPoint();
                float   distanceSqr = p.LengthSquared;

                // Ensure the search direction is numerically fit.
                if (distanceSqr < Common.Settings.FLT_EPSILON_SQUARED)
                {
                    // The origin is probably contained by a line segment
                    // or triangle. Thus the shapes are overlapped.

                    // We can't return zero here even though there may be overlap.
                    // In case the simplex is a point, segment, or triangle it is difficult
                    // to determine if the origin is contained in the CSO or very close to it.
                    break;
                }

                // Compute a tentative new simplex vertex using support points.
#if ALLOWUNSAFE
                SimplexVertex *vertex = vertices + simplex._count;
                vertex->indexA = shapeA.GetSupport(transformA.InverseTransformDirection(p));
                vertex->wA     = transformA.TransformPoint(shapeA.GetVertex(vertex->indexA));
                //Vec2 wBLocal;
                vertex->indexB = shapeB.GetSupport(transformB.InverseTransformDirection(-p));
                vertex->wB     = transformB.TransformPoint(shapeB.GetVertex(vertex->indexB));
                vertex->w      = vertex->wB - vertex->wA;
#else
                SimplexVertex vertex = vertices[simplex._count - 1];
                vertex.indexA = shapeA.GetSupport(transformA.InverseTransformDirection(p));
                vertex.wA     = transformA.TransformPoint(shapeA.GetVertex(vertex.indexA));
                //Vec2 wBLocal;
                vertex.indexB = shapeB.GetSupport(transformB.InverseTransformDirection(-p));
                vertex.wB     = transformB.TransformPoint(shapeB.GetVertex(vertex.indexB));
                vertex.w      = vertex.wB - vertex.wA;
#endif // ALLOWUNSAFE

                // Iteration count is equated to the number of support point calls.
                ++iter;

                // Check for convergence.
#if ALLOWUNSAFE
                float lowerBound = Vector2.Dot(p, vertex->w);
#else
                float lowerBound = Vector2.Dot(p, vertex.w);
#endif
                float       upperBound       = distanceSqr;
                const float k_relativeTolSqr = 0.01f * 0.01f;                   // 1:100
                if (upperBound - lowerBound <= k_relativeTolSqr * upperBound)
                {
                    // Converged!
                    break;
                }

                // Check for duplicate support points.
                bool duplicate = false;
                for (i = 0; i < lastCount; ++i)
                {
#if ALLOWUNSAFE
                    if (vertex->indexA == lastA[i] && vertex->indexB == lastB[i])
#else
                    if (vertex.indexA == lastA[i] && vertex.indexB == lastB[i])
#endif
                    {
                        duplicate = true;
                        break;
                    }
                }

                // If we found a duplicate support point we must exit to avoid cycling.
                if (duplicate)
                {
                    break;
                }

                // New vertex is ok and needed.
                ++simplex._count;
            }


#if ALLOWUNSAFE
            fixed(DistanceOutput *doPtr = &output)
            {
                // Prepare output.
                simplex.GetWitnessPoints(&doPtr->PointA, &doPtr->PointB);
                doPtr->Distance   = Vector2.Distance(doPtr->PointA, doPtr->PointB);
                doPtr->Iterations = iter;
            }

            fixed(SimplexCache *sPtr = &cache)
            {
                // Cache the simplex.
                simplex.WriteCache(sPtr);
            }
#else
            // Prepare output.
            simplex.GetWitnessPoints(ref output.PointA, ref output.PointB);
            output.Distance   = Box2DX.Common.Math.Distance(output.PointA, output.PointB);
            output.Iterations = iter;

            // Cache the simplex.
            simplex.WriteCache(cache);
#endif

            // Apply radii if requested.
            if (input.UseRadii)
            {
                float rA = shapeA._radius;
                float rB = shapeB._radius;

                if (output.Distance > rA + rB && output.Distance > Common.Settings.FLT_EPSILON)
                {
                    // Shapes are still no overlapped.
                    // Move the witness points to the outer surface.
                    output.Distance -= rA + rB;
                    Vector2 normal = output.PointB - output.PointA;
                    normal.Normalize();
                    output.PointA += rA * normal;
                    output.PointB -= rB * normal;
                }
                else
                {
                    // Shapes are overlapped when radii are considered.
                    // Move the witness points to the middle.
                    Vector2 p = 0.5f * (output.PointA + output.PointB);
                    output.PointA   = p;
                    output.PointB   = p;
                    output.Distance = 0.0f;
                }
            }
        }
Example #28
0
        public override void ComputeMass(out MassData massData, float denstity)
        {
            // Polygon mass, centroid, and inertia.
            // Let rho be the polygon density in mass per unit area.
            // Then:
            // mass = rho * int(dA)
            // centroid.x = (1/mass) * rho * int(x * dA)
            // centroid.y = (1/mass) * rho * int(y * dA)
            // I = rho * int((x*x + y*y) * dA)
            //
            // We can compute these integrals by summing all the integrals
            // for each triangle of the polygon. To evaluate the integral
            // for a single triangle, we make a change of variables to
            // the (u,v) coordinates of the triangle:
            // x = x0 + e1x * u + e2x * v
            // y = y0 + e1y * u + e2y * v
            // where 0 <= u && 0 <= v && u + v <= 1.
            //
            // We integrate u from [0,1-v] and then v from [0,1].
            // We also need to use the Jacobian of the Transformation:
            // D = cross(e1, e2)
            //
            // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
            //
            // The rest of the derivation is handled by computer algebra.

            Box2DXDebug.Assert(_vertexCount >= 3);

            Vector2 center = Vector2.zero;
            float   area   = 0.0f;
            float   I      = 0.0f;

            // pRef is the reference point for forming triangles.
            // It's location doesn't change the result (except for rounding error).
            Vector2 pRef = Vector2.zero;

#if O
            // This code would put the reference point inside the polygon.
            for (int i = 0; i < vCount; ++i)
            {
                pRef += _vertices[i];
            }
            pRef *= 1.0f / count;
#endif

            const float k_inv3 = 1.0f / 3.0f;

            for (int i = 0; i < _vertexCount; ++i)
            {
                // Triangle vertices.
                Vector2 p1 = pRef;
                Vector2 p2 = _vertices[i];
                Vector2 p3 = i + 1 < _vertexCount ? _vertices[i + 1] : _vertices[0];

                Vector2 e1 = p2 - p1;
                Vector2 e2 = p3 - p1;

                float D = e1.Cross(e2);

                float triangleArea = 0.5f * D;
                area += triangleArea;

                // Area weighted centroid
                center += triangleArea * k_inv3 * (p1 + p2 + p3);

                float px = p1.x, py = p1.y;
                float ex1 = e1.x, ey1 = e1.y;
                float ex2 = e2.x, ey2 = e2.y;

                float intx2 = k_inv3 * (0.25f * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5f * px * px;
                float inty2 = k_inv3 * (0.25f * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5f * py * py;

                I += D * (intx2 + inty2);
            }

            // Total mass
            massData.Mass = denstity * area;

            // Center of mass
            Box2DXDebug.Assert(area > Common.Settings.FLT_EPSILON);
            center         *= 1.0f / area;
            massData.Center = center;

            // Inertia tensor relative to the local origin.
            massData.I = denstity * I;
        }
Example #29
0
        public void DestroyProxy(int proxyId)
        {
            Box2DXDebug.Assert(0 < _proxyCount && _proxyCount <= Settings.MaxProxies);
            Proxy proxy = _proxyPool[proxyId];

            Box2DXDebug.Assert(proxy.IsValid);

            int boundCount = 2 * _proxyCount;

            for (int axis = 0; axis < 2; ++axis)
            {
                Bound[] bounds = _bounds[axis];

                int    lowerIndex = proxy.LowerBounds[axis];
                int    upperIndex = proxy.UpperBounds[axis];
                ushort lowerValue = bounds[lowerIndex].Value;
                ushort upperValue = bounds[upperIndex].Value;

#warning "Check this"
                //memmove(bounds + lowerIndex, bounds + lowerIndex + 1, (upperIndex - lowerIndex - 1) * sizeof(b2Bound));
                Bound[] tmp = new Bound[upperIndex - lowerIndex - 1];
                for (int i = 0; i < (upperIndex - lowerIndex - 1); i++)
                {
                    tmp[i] = bounds[lowerIndex + 1 + i].Clone();
                }
                for (int i = 0; i < (upperIndex - lowerIndex - 1); i++)
                {
                    bounds[lowerIndex + i] = tmp[i];
                }

                //memmove(bounds + upperIndex - 1, bounds + upperIndex + 1, (boundCount - upperIndex - 1) * sizeof(b2Bound));
                tmp = new Bound[boundCount - upperIndex - 1];
                for (int i = 0; i < (boundCount - upperIndex - 1); i++)
                {
                    tmp[i] = bounds[upperIndex + 1 + i].Clone();
                }
                for (int i = 0; i < (boundCount - upperIndex - 1); i++)
                {
                    bounds[upperIndex - 1 + i] = tmp[i];
                }

                // Fix bound indices.
                for (int index = lowerIndex; index < boundCount - 2; ++index)
                {
                    Proxy proxy_ = _proxyPool[bounds[index].ProxyId];
                    if (bounds[index].IsLower)
                    {
                        proxy_.LowerBounds[axis] = (ushort)index;
                    }
                    else
                    {
                        proxy_.UpperBounds[axis] = (ushort)index;
                    }
                }

                // Fix stabbing count.
                for (int index = lowerIndex; index < upperIndex - 1; ++index)
                {
                    --bounds[index].StabbingCount;
                }

                // Query for pairs to be removed. lowerIndex and upperIndex are not needed.
                Query(out lowerIndex, out upperIndex, lowerValue, upperValue, bounds, boundCount - 2, axis);
            }

            Box2DXDebug.Assert(_queryResultCount < Settings.MaxProxies);

            for (int i = 0; i < _queryResultCount; ++i)
            {
                Box2DXDebug.Assert(_proxyPool[_queryResults[i]].IsValid);
                _pairManager.RemoveBufferedPair(proxyId, _queryResults[i]);
            }

            _pairManager.Commit();

            // Prepare for next query.
            _queryResultCount = 0;
            IncrementTimeStamp();

            // Return the proxy to the pool.
            proxy.UserData       = null;
            proxy.OverlapCount   = BroadPhase.Invalid;
            proxy.LowerBounds[0] = BroadPhase.Invalid;
            proxy.LowerBounds[1] = BroadPhase.Invalid;
            proxy.UpperBounds[0] = BroadPhase.Invalid;
            proxy.UpperBounds[1] = BroadPhase.Invalid;

            proxy.Next = _freeProxy;
            _freeProxy = (ushort)proxyId;
            --_proxyCount;

            if (IsValidate)
            {
                Validate();
            }
        }
        // CCD via the secant method.
        /// <summary>
        /// Compute the time when two shapes begin to touch or touch at a closer distance.
        /// TOI considers the shape radii. It attempts to have the radii overlap by the tolerance.
        /// Iterations terminate with the overlap is within 0.5 * tolerance. The tolerance should be
        /// smaller than sum of the shape radii.
        /// Warning the sweeps must have the same time interval.
        /// </summary>
        /// <returns>
        /// The fraction between [0,1] in which the shapes first touch.
        /// fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch.
        /// </returns>
        public static float TimeOfImpact(TOIInput input, Shape shapeA, Shape shapeB)
        {
            Sweep sweepA = input.SweepA;
            Sweep sweepB = input.SweepB;

            Box2DXDebug.Assert(sweepA.T0 == sweepB.T0);
            Box2DXDebug.Assert(1.0f - sweepA.T0 > Common.Settings.FLT_EPSILON);

            float radius    = shapeA._radius + shapeB._radius;
            float tolerance = input.Tolerance;

            float alpha = 0.0f;

            const int k_maxIterations = 1000;                   // TODO_ERIN b2Settings
            int       iter            = 0;
            float     target          = 0.0f;

            // Prepare input for distance query.
            SimplexCache cache = new SimplexCache();

            cache.Count = 0;
            DistanceInput distanceInput;

            distanceInput.UseRadii = false;

            for (; ;)
            {
                XForm xfA, xfB;
                sweepA.GetTransform(out xfA, alpha);
                sweepB.GetTransform(out xfB, alpha);

                // Get the distance between shapes.
                distanceInput.TransformA = xfA;
                distanceInput.TransformB = xfB;
                DistanceOutput distanceOutput;
                Distance(out distanceOutput, ref cache, ref distanceInput, shapeA, shapeB);

                if (distanceOutput.Distance <= 0.0f)
                {
                    alpha = 1.0f;
                    break;
                }

                SeparationFunction fcn = new SeparationFunction();
                unsafe
                {
                    fcn.Initialize(&cache, shapeA, xfA, shapeB, xfB);
                }

                float separation = fcn.Evaluate(xfA, xfB);
                if (separation <= 0.0f)
                {
                    alpha = 1.0f;
                    break;
                }

                if (iter == 0)
                {
                    // Compute a reasonable target distance to give some breathing room
                    // for conservative advancement. We take advantage of the shape radii
                    // to create additional clearance.
                    if (separation > radius)
                    {
                        target = Common.Math.Max(radius - tolerance, 0.75f * radius);
                    }
                    else
                    {
                        target = Common.Math.Max(separation - tolerance, 0.02f * radius);
                    }
                }

                if (separation - target < 0.5f * tolerance)
                {
                    if (iter == 0)
                    {
                        alpha = 1.0f;
                        break;
                    }

                    break;
                }

#if _FALSE
                // Dump the curve seen by the root finder
                {
                    const int32 N  = 100;
                    float32     dx = 1.0f / N;
                    float32     xs[N + 1];