Esempio n. 1
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()
        {
            Box2DXDebug.Assert(_world._lock == false);
            if (_world._lock == true)
            {
                return;
            }

            // 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 (Fixture f = _fixtureList; f != null; f = f.Next)
            {
                MassData massData;
                f.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);

            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 (Fixture f = _fixtureList; f != null; f = f.Next)
                {
                    f.RefilterProxy(_world._broadPhase, _xf);
                }
            }
        }
Esempio n. 2
0
        public override SegmentCollide TestSegment(XForm xf, out float lambda, out Vec2 normal, Segment segment, float maxLambda)
        {
            lambda = 0f;
            normal = Vec2.Zero;

            float lower = 0.0f, upper = maxLambda;

            Vec2 p1    = Common.Math.MulT(xf.R, segment.P1 - xf.Position);
            Vec2 p2    = Common.Math.MulT(xf.R, segment.P2 - xf.Position);
            Vec2 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   = Vec2.Dot(_normals[i], _vertices[i] - p1);
                float denominator = Vec2.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 = Common.Math.Mul(xf.R, _normals[index]);
                return(SegmentCollide.HitCollide);
            }

            lambda = 0f;
            return(SegmentCollide.StartInsideCollide);
        }
        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.MathB2.Mul(xf2, circle._position);
            Vec2 cLocal = Common.MathB2.MulT(xf1, c);

            // Find the min separating edge.
            int   normalIndex = 0;
            float separation  = -Settings.FLT_MAX;
            float radius      = polygon._radius + circle._radius;
            int   vertexCount = polygon._vertexCount;

            Vec2[] vertices = polygon._vertices;
            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;
                }
            }

            // Vertices that subtend the incident face.
            int  vertIndex1 = normalIndex;
            int  vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
            Vec2 v1         = vertices[vertIndex1];
            Vec2 v2         = vertices[vertIndex2];

            // If the center is inside the polygon ...
            if (separation < Common.Settings.FLT_EPSILON)
            {
                manifold.PointCount           = 1;
                manifold.Type                 = ManifoldType.FaceA;
                manifold.LocalPlaneNormal     = normals[normalIndex];
                manifold.LocalPoint           = 0.5f * (v1 + v2);
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
                return;
            }

            // Compute barycentric coordinates
            float u1 = Vec2.Dot(cLocal - v1, v2 - v1);
            float u2 = Vec2.Dot(cLocal - v2, v1 - v2);

            if (u1 <= 0.0f)
            {
                if (Vec2.DistanceSquared(cLocal, v1) > radius * radius)
                {
                    return;
                }

                manifold.PointCount       = 1;
                manifold.Type             = ManifoldType.FaceA;
                manifold.LocalPlaneNormal = cLocal - v1;
                manifold.LocalPlaneNormal.Normalize();
                manifold.LocalPoint           = v1;
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
            }
            else if (u2 <= 0.0f)
            {
                if (Vec2.DistanceSquared(cLocal, v2) > radius * radius)
                {
                    return;
                }

                manifold.PointCount       = 1;
                manifold.Type             = ManifoldType.FaceA;
                manifold.LocalPlaneNormal = cLocal - v2;
                manifold.LocalPlaneNormal.Normalize();
                manifold.LocalPoint           = v2;
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
            }
            else
            {
                Vec2  faceCenter  = 0.5f * (v1 + v2);
                float separation_ = Vec2.Dot(cLocal - faceCenter, normals[vertIndex1]);
                if (separation_ > radius)
                {
                    return;
                }

                manifold.PointCount           = 1;
                manifold.Type                 = ManifoldType.FaceA;
                manifold.LocalPlaneNormal     = normals[vertIndex1];
                manifold.LocalPoint           = faceCenter;
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
            }
        }
Esempio n. 4
0
        internal override void SolveVelocityConstraints(TimeStep step)
        {
            Body b1 = _body1;
            Body b2 = _body2;

            Vec2  v1 = b1._linearVelocity;
            float w1 = b1._angularVelocity;
            Vec2  v2 = b2._linearVelocity;
            float w2 = b2._angularVelocity;

            // Solve linear motor constraint.
            if (_enableMotor && _limitState != LimitState.EqualLimits)
            {
                float Cdot       = Vec2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
                float impulse    = _motorMass * (_motorSpeed - Cdot);
                float oldImpulse = _motorImpulse;
                float maxImpulse = step.Dt * _maxMotorForce;
                _motorImpulse = Box2DNet.Common.Math.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
                impulse       = _motorImpulse - oldImpulse;

                Vec2  P  = impulse * _axis;
                float L1 = impulse * _a1;
                float L2 = impulse * _a2;

                v1 -= _invMass1 * P;
                w1 -= _invI1 * L1;

                v2 += _invMass2 * P;
                w2 += _invI2 * L2;
            }

            float Cdot1 = Vec2.Dot(_perp, v2 - v1) + _s2 * w2 - _s1 * w1;

            if (_enableLimit && _limitState != LimitState.InactiveLimit)
            {
                // Solve prismatic and limit constraint in block form.
                float Cdot2 = Vec2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
                Vec2  Cdot  = new Vec2(Cdot1, Cdot2);

                Vec2 f1 = _impulse;
                Vec2 df = _K.Solve(-Cdot);
                _impulse += df;

                if (_limitState == LimitState.AtLowerLimit)
                {
                    _impulse.Y = Box2DNet.Common.Math.Max(_impulse.Y, 0.0f);
                }
                else if (_limitState == LimitState.AtUpperLimit)
                {
                    _impulse.Y = Box2DNet.Common.Math.Min(_impulse.Y, 0.0f);
                }

                // f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)
                float b   = -Cdot1 - (_impulse.Y - f1.Y) * _K.Col2.X;
                float f2r = b / _K.Col1.X + f1.X;
                _impulse.X = f2r;

                df = _impulse - f1;

                Vec2  P  = df.X * _perp + df.Y * _axis;
                float L1 = df.X * _s1 + df.Y * _a1;
                float L2 = df.X * _s2 + df.Y * _a2;

                v1 -= _invMass1 * P;
                w1 -= _invI1 * L1;

                v2 += _invMass2 * P;
                w2 += _invI2 * L2;
            }
            else
            {
                // Limit is inactive, just solve the prismatic constraint in block form.
                float df = (-Cdot1) / _K.Col1.X;
                _impulse.X += df;

                Vec2  P  = df * _perp;
                float L1 = df * _s1;
                float L2 = df * _s2;

                v1 -= _invMass1 * P;
                w1 -= _invI1 * L1;

                v2 += _invMass2 * P;
                w2 += _invI2 * L2;
            }

            b1._linearVelocity  = v1;
            b1._angularVelocity = w1;
            b2._linearVelocity  = v2;
            b2._angularVelocity = w2;
        }
Esempio n. 5
0
 public override int GetSupport(Vec2 d)
 {
     return(Vec2.Dot(_v1, d) > Vec2.Dot(_v2, d) ? 0 : 1);
 }
Esempio n. 6
0
        internal override bool SolvePositionConstraints()
        {
            Body b1 = _body1;
            Body b2 = _body2;

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

            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 d   = p2 - p1;
            Vec2 ay1 = Box2DXMath.Mul(b1.GetXForm().R, _localYAxis1);

            // Solve linear (point-to-line) constraint.
            float linearC = Vec2.Dot(ay1, d);

            // Prevent overly large corrections.
            linearC = Box2DXMath.Clamp(linearC, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
            float linearImpulse = -_linearMass * linearC;

            b1._sweep.C += (invMass1 * linearImpulse) * _linearJacobian.Linear1;
            b1._sweep.A += invI1 * linearImpulse * _linearJacobian.Angular1;
            //b1->SynchronizeTransform(); // updated by angular constraint
            b2._sweep.C += (invMass2 * linearImpulse) * _linearJacobian.Linear2;
            b2._sweep.A += invI2 * linearImpulse * _linearJacobian.Angular2;
            //b2->SynchronizeTransform(); // updated by angular constraint

            float positionError = Box2DXMath.Abs(linearC);

            // Solve angular constraint.
            float angularC = b2._sweep.A - b1._sweep.A - _refAngle;

            // Prevent overly large corrections.
            angularC = Box2DXMath.Clamp(angularC, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);
            float angularImpulse = -_angularMass * angularC;

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

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

            float angularError = Box2DXMath.Abs(angularC);

            // Solve linear limit constraint.
            if (_enableLimit && _limitState != LimitState.InactiveLimit)
            {
                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 d_  = p2_ - p1_;
                Vec2 ax1 = Box2DXMath.Mul(b1.GetXForm().R, _localXAxis1);

                float translation  = Vec2.Dot(ax1, d_);
                float limitImpulse = 0.0f;

                if (_limitState == LimitState.EqualLimits)
                {
                    // Prevent large angular corrections
                    float limitC = Box2DXMath.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
                    limitImpulse  = -_motorMass * limitC;
                    positionError = Box2DXMath.Max(positionError, Box2DXMath.Abs(angularC));
                }
                else if (_limitState == LimitState.AtLowerLimit)
                {
                    float limitC = translation - _lowerTranslation;
                    positionError = Box2DXMath.Max(positionError, -limitC);

                    // Prevent large linear corrections and allow some slop.
                    limitC       = Box2DXMath.Clamp(limitC + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
                    limitImpulse = -_motorMass * limitC;
                    float oldLimitImpulse = _limitPositionImpulse;
                    _limitPositionImpulse = Box2DXMath.Max(_limitPositionImpulse + limitImpulse, 0.0f);
                    limitImpulse          = _limitPositionImpulse - oldLimitImpulse;
                }
                else if (_limitState == LimitState.AtUpperLimit)
                {
                    float limitC = translation - _upperTranslation;
                    positionError = Box2DXMath.Max(positionError, limitC);

                    // Prevent large linear corrections and allow some slop.
                    limitC       = Box2DXMath.Clamp(limitC - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection);
                    limitImpulse = -_motorMass * limitC;
                    float oldLimitImpulse = _limitPositionImpulse;
                    _limitPositionImpulse = Box2DXMath.Min(_limitPositionImpulse + limitImpulse, 0.0f);
                    limitImpulse          = _limitPositionImpulse - oldLimitImpulse;
                }

                b1._sweep.C += (invMass1 * limitImpulse) * _motorJacobian.Linear1;
                b1._sweep.A += invI1 * limitImpulse * _motorJacobian.Angular1;
                b2._sweep.C += (invMass2 * limitImpulse) * _motorJacobian.Linear2;
                b2._sweep.A += invI2 * limitImpulse * _motorJacobian.Angular2;

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

            return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop);
        }
Esempio n. 7
0
        /// Ray-cast against the proxies in the tree. This relies on the callback
        /// to perform a exact ray-cast in the case were the proxy contains a shape.
        /// The callback also performs the any collision filtering. This has performance
        /// roughly equal to k * log(n), where k is the number of collisions and n is the
        /// number of proxies in the tree.
        /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
        /// @param callback a callback class that is called for each proxy that is hit by the ray.
        public void RayCast(IRayCastEnabled callback, RayCastInput input)
        {
            Vec2 p1 = input.P1;
            Vec2 p2 = input.P2;
            Vec2 r  = p2 - p1;

            Box2DXDebug.Assert(r.LengthSquared() > 0.0f);
            r.Normalize();

            // v is perpendicular to the segment.
            Vec2 v     = Vec2.Cross(1.0f, r);
            Vec2 abs_v = Math.Abs(v);

            // Separating axis for segment (Gino, p80).
            // |dot(v, p1 - c)| > dot(|v|, h)

            float maxFraction = input.MaxFraction;

            // Build a bounding box for the segment.
            AABB segmentAABB = new AABB();
            {
                Vec2 t = p1 + maxFraction * (p2 - p1);
                segmentAABB.LowerBound = Math.Min(p1, t);
                segmentAABB.UpperBound = Math.Max(p1, t);
            }

            const int k_stackSize = 128;

            int[] stack = new int[k_stackSize];

            int count = 0;

            stack[count++] = _root;

            while (count > 0)
            {
                int nodeId = stack[--count];
                if (nodeId == NullNode)
                {
                    continue;
                }

                DynamicTreeNode node = _nodes[nodeId];

                if (Collision.TestOverlap(node.Aabb, segmentAABB) == false)
                {
                    continue;
                }

                // Separating axis for segment (Gino, p80).
                // |dot(v, p1 - c)| > dot(|v|, h)
                Vec2  c          = node.Aabb.GetCenter();
                Vec2  h          = node.Aabb.GetExtents();
                float separation = Math.Abs(Vec2.Dot(v, p1 - c)) - Vec2.Dot(abs_v, h);
                if (separation > 0.0f)
                {
                    continue;
                }

                if (node.IsLeaf())
                {
                    RayCastInput subInput = new RayCastInput();
                    subInput.P1          = input.P1;
                    subInput.P2          = input.P2;
                    subInput.MaxFraction = maxFraction;

                    maxFraction = callback.RayCastCallback(subInput, nodeId);

                    if (maxFraction == 0.0f)
                    {
                        return;
                    }

                    // Update segment bounding box.
                    {
                        Vec2 t = p1 + maxFraction * (p2 - p1);
                        segmentAABB.LowerBound = Math.Min(p1, t);
                        segmentAABB.UpperBound = Math.Max(p1, t);
                    }
                }
                else
                {
                    Box2DXDebug.Assert(count + 1 < k_stackSize);
                    stack[count++] = node.Child1;
                    stack[count++] = node.Child2;
                }
            }
        }
Esempio n. 8
0
        // Possible regions:
        // - points[2]
        // - edge points[0]-points[2]
        // - edge points[1]-points[2]
        // - inside the triangle
        internal void Solve3()
        {
            Vec2 w1 = _v1.w;
            Vec2 w2 = _v2.w;
            Vec2 w3 = _v3.w;

            // Edge12
            // [1      1     ][a1] = [1]
            // [w1.e12 w2.e12][a2] = [0]
            // a3 = 0
            Vec2  e12   = w2 - w1;
            float w1e12 = Vec2.Dot(w1, e12);
            float w2e12 = Vec2.Dot(w2, e12);
            float d12_1 = w2e12;
            float d12_2 = -w1e12;

            // Edge13
            // [1      1     ][a1] = [1]
            // [w1.e13 w3.e13][a3] = [0]
            // a2 = 0
            Vec2  e13   = w3 - w1;
            float w1e13 = Vec2.Dot(w1, e13);
            float w3e13 = Vec2.Dot(w3, e13);
            float d13_1 = w3e13;
            float d13_2 = -w1e13;

            // Edge23
            // [1      1     ][a2] = [1]
            // [w2.e23 w3.e23][a3] = [0]
            // a1 = 0
            Vec2  e23   = w3 - w2;
            float w2e23 = Vec2.Dot(w2, e23);
            float w3e23 = Vec2.Dot(w3, e23);
            float d23_1 = w3e23;
            float d23_2 = -w2e23;

            // Triangle123
            float n123 = Vec2.Cross(e12, e13);

            float d123_1 = n123 * Vec2.Cross(w2, w3);
            float d123_2 = n123 * Vec2.Cross(w3, w1);
            float d123_3 = n123 * Vec2.Cross(w1, w2);

            // w1 region
            if (d12_2 <= 0.0f && d13_2 <= 0.0f)
            {
                _v1.a  = 1.0f;
                _count = 1;
                return;
            }

            // e12
            if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
            {
                float inv_d12 = 1.0f / (d12_1 + d12_2);
                _v1.a  = d12_1 * inv_d12;
                _v2.a  = d12_1 * inv_d12;
                _count = 2;
                return;
            }

            // e13
            if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)
            {
                float inv_d13 = 1.0f / (d13_1 + d13_2);
                _v1.a  = d13_1 * inv_d13;
                _v3.a  = d13_2 * inv_d13;
                _count = 2;
                _v2    = _v3;
                return;
            }

            // w2 region
            if (d12_1 <= 0.0f && d23_2 <= 0.0f)
            {
                _v2.a  = 1.0f;
                _count = 1;
                _v1    = _v2;
                return;
            }

            // w3 region
            if (d13_1 <= 0.0f && d23_1 <= 0.0f)
            {
                _v3.a  = 1.0f;
                _count = 1;
                _v1    = _v3;
                return;
            }

            // e23
            if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)
            {
                float inv_d23 = 1.0f / (d23_1 + d23_2);
                _v2.a  = d23_1 * inv_d23;
                _v3.a  = d23_2 * inv_d23;
                _count = 2;
                _v1    = _v3;
                return;
            }

            // Must be in triangle123
            float inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);

            _v1.a  = d123_1 * inv_d123;
            _v2.a  = d123_2 * inv_d123;
            _v3.a  = d123_3 * inv_d123;
            _count = 3;
        }
Esempio n. 9
0
        /// <summary>
        /// Compute the closest points between two shapes. Supports any combination of:
        /// CircleShape, PolygonShape, EdgeShape. The simplex cache is input/output.
        /// On the first call set SimplexCache.Count to zero.
        /// </summary>
        public unsafe static void Distance(out DistanceOutput output, ref SimplexCache cache, ref DistanceInput input, Shape shapeA, Shape shapeB)
        {
            output = new DistanceOutput();

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

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

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

            // Get simplex vertices as an array.
            SimplexVertex *vertices = &simplex._v1;

            // These store the vertices of the last simplex so that we
            // can check for duplicates and prevent cycling.
            int *lastA = stackalloc int[4], lastB = stackalloc int[4];
            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.
                Vec2  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.
                SimplexVertex *vertex = vertices + simplex._count;
                vertex->indexA = shapeA.GetSupport(Common.Math.MulT(transformA.R, p));
                vertex->wA     = Common.Math.Mul(transformA, shapeA.GetVertex(vertex->indexA));
                //Vec2 wBLocal;
                vertex->indexB = shapeB.GetSupport(Common.Math.MulT(transformB.R, -p));
                vertex->wB     = Common.Math.Mul(transformB, shapeB.GetVertex(vertex->indexB));
                vertex->w      = vertex->wB - vertex->wA;

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

                // Check for convergence.
                float       lowerBound       = Vec2.Dot(p, vertex->w);
                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 (vertex->indexA == lastA[i] && vertex->indexB == lastB[i])
                    {
                        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;
            }

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

            fixed(SimplexCache *sPtr = &cache)
            {
                // Cache the simplex.
                simplex.WriteCache(sPtr);
            }

            // 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;
                    Vec2 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.
                    Vec2 p = 0.5f * (output.PointA + output.PointB);
                    output.PointA   = p;
                    output.PointB   = p;
                    output.Distance = 0.0f;
                }
            }
        }
Esempio n. 10
0
        internal override bool SolvePositionConstraints(float baumgarte)
        {
            Body  body  = this._body1;
            Body  body2 = this._body2;
            Vec2  vec   = body._sweep.C;
            float num   = body._sweep.A;
            Vec2  vec2  = body2._sweep.C;
            float num2  = body2._sweep.A;
            float num3  = 0f;
            bool  flag  = false;
            float z     = 0f;
            Mat22 a     = new Mat22(num);
            Mat22 a2    = new Mat22(num2);
            Vec2  v     = Box2DX.Common.Math.Mul(a, this._localAnchor1 - this._localCenter1);
            Vec2  vec3  = Box2DX.Common.Math.Mul(a2, this._localAnchor2 - this._localCenter2);
            Vec2  vec4  = vec2 + vec3 - vec - v;

            if (this._enableLimit)
            {
                this._axis = Box2DX.Common.Math.Mul(a, this._localXAxis1);
                this._a1   = Vec2.Cross(vec4 + v, this._axis);
                this._a2   = Vec2.Cross(vec3, this._axis);
                float num4 = Vec2.Dot(this._axis, vec4);
                if (Box2DX.Common.Math.Abs(this._upperTranslation - this._lowerTranslation) < 2f * Settings.LinearSlop)
                {
                    z    = Box2DX.Common.Math.Clamp(num4, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
                    num3 = Box2DX.Common.Math.Abs(num4);
                    flag = true;
                }
                else
                {
                    if (num4 <= this._lowerTranslation)
                    {
                        z    = Box2DX.Common.Math.Clamp(num4 - this._lowerTranslation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0f);
                        num3 = this._lowerTranslation - num4;
                        flag = true;
                    }
                    else
                    {
                        if (num4 >= this._upperTranslation)
                        {
                            z    = Box2DX.Common.Math.Clamp(num4 - this._upperTranslation - Settings.LinearSlop, 0f, Settings.MaxLinearCorrection);
                            num3 = num4 - this._upperTranslation;
                            flag = true;
                        }
                    }
                }
            }
            this._perp = Box2DX.Common.Math.Mul(a, this._localYAxis1);
            this._s1   = Vec2.Cross(vec4 + v, this._perp);
            this._s2   = Vec2.Cross(vec3, this._perp);
            Vec2 v2 = default(Vec2);

            v2.X = Vec2.Dot(this._perp, vec4);
            v2.Y = num2 - num - this._refAngle;
            num3 = Box2DX.Common.Math.Max(num3, Box2DX.Common.Math.Abs(v2.X));
            float num5 = Box2DX.Common.Math.Abs(v2.Y);
            Vec3  vec5;

            if (flag)
            {
                float invMass  = this._invMass1;
                float invMass2 = this._invMass2;
                float invI     = this._invI1;
                float invI2    = this._invI2;
                float x        = invMass + invMass2 + invI * this._s1 * this._s1 + invI2 * this._s2 * this._s2;
                float num6     = invI * this._s1 + invI2 * this._s2;
                float num7     = invI * this._s1 * this._a1 + invI2 * this._s2 * this._a2;
                float y        = invI + invI2;
                float num8     = invI * this._a1 + invI2 * this._a2;
                float z2       = invMass + invMass2 + invI * this._a1 * this._a1 + invI2 * this._a2 * this._a2;
                this._K.Col1.Set(x, num6, num7);
                this._K.Col2.Set(num6, y, num8);
                this._K.Col3.Set(num7, num8, z2);
                vec5 = this._K.Solve33(-new Vec3
                {
                    X = v2.X,
                    Y = v2.Y,
                    Z = z
                });
            }
            else
            {
                float invMass  = this._invMass1;
                float invMass2 = this._invMass2;
                float invI     = this._invI1;
                float invI2    = this._invI2;
                float x        = invMass + invMass2 + invI * this._s1 * this._s1 + invI2 * this._s2 * this._s2;
                float num6     = invI * this._s1 + invI2 * this._s2;
                float y        = invI + invI2;
                this._K.Col1.Set(x, num6, 0f);
                this._K.Col2.Set(num6, y, 0f);
                Vec2 vec6 = this._K.Solve22(-v2);
                vec5.X = vec6.X;
                vec5.Y = vec6.Y;
                vec5.Z = 0f;
            }
            Vec2  v3    = vec5.X * this._perp + vec5.Z * this._axis;
            float num9  = vec5.X * this._s1 + vec5.Y + vec5.Z * this._a1;
            float num10 = vec5.X * this._s2 + vec5.Y + vec5.Z * this._a2;

            vec           -= this._invMass1 * v3;
            num           -= this._invI1 * num9;
            vec2          += this._invMass2 * v3;
            num2          += this._invI2 * num10;
            body._sweep.C  = vec;
            body._sweep.A  = num;
            body2._sweep.C = vec2;
            body2._sweep.A = num2;
            body.SynchronizeTransform();
            body2.SynchronizeTransform();
            return(num3 <= Settings.LinearSlop && num5 <= Settings.AngularSlop);
        }
Esempio n. 11
0
        // This implements 2-sided edge vs circle collision.
        public static void CollideEdgeAndCircle(ref Manifold manifold, EdgeShape edge, XForm transformA, CircleShape circle, XForm transformB)
        {
            manifold.PointCount = 0;
            Vec2  cLocal = Common.Math.MulT(transformA, Common.Math.Mul(transformB, circle._position));
            Vec2  normal = edge._normal;
            Vec2  v1     = edge._v1;
            Vec2  v2     = edge._v2;
            float radius = edge._radius + circle._radius;

            // Barycentric coordinates
            float u1 = Vec2.Dot(cLocal - v1, v2 - v1);
            float u2 = Vec2.Dot(cLocal - v2, v1 - v2);

            if (u1 <= 0.0f)
            {
                // Behind v1
                if (Vec2.DistanceSquared(cLocal, v1) > radius * radius)
                {
                    return;
                }

                manifold.PointCount       = 1;
                manifold.Type             = ManifoldType.FaceA;
                manifold.LocalPlaneNormal = cLocal - v1;
                manifold.LocalPlaneNormal.Normalize();
                manifold.LocalPoint           = v1;
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
            }
            else if (u2 <= 0.0f)
            {
                // Ahead of v2
                if (Vec2.DistanceSquared(cLocal, v2) > radius * radius)
                {
                    return;
                }

                manifold.PointCount       = 1;
                manifold.Type             = ManifoldType.FaceA;
                manifold.LocalPlaneNormal = cLocal - v2;
                manifold.LocalPlaneNormal.Normalize();
                manifold.LocalPoint           = v2;
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
            }
            else
            {
                float separation = Vec2.Dot(cLocal - v1, normal);
                if (separation < -radius || radius < separation)
                {
                    return;
                }

                manifold.PointCount           = 1;
                manifold.Type                 = ManifoldType.FaceA;
                manifold.LocalPlaneNormal     = separation < 0.0f ? -normal : normal;
                manifold.LocalPoint           = 0.5f * (v1 + v2);
                manifold.Points[0].LocalPoint = circle._position;
                manifold.Points[0].ID.Key     = 0;
            }
        }
Esempio n. 12
0
        internal override void SolveVelocityConstraints(TimeStep step)
        {
            Body  body  = this._body1;
            Body  body2 = this._body2;
            Vec2  vec   = body._linearVelocity;
            float num   = body._angularVelocity;
            Vec2  vec2  = body2._linearVelocity;
            float num2  = body2._angularVelocity;

            if (this._enableMotor && this._limitState != LimitState.EqualLimits)
            {
                float num3         = Vec2.Dot(this._axis, vec2 - vec) + this._a2 * num2 - this._a1 * num;
                float num4         = this._motorMass * (this._motorSpeed - num3);
                float motorImpulse = this._motorImpulse;
                float num5         = step.Dt * this._maxMotorForce;
                this._motorImpulse = Box2DX.Common.Math.Clamp(this._motorImpulse + num4, -num5, num5);
                num4 = this._motorImpulse - motorImpulse;
                Vec2  v    = num4 * this._axis;
                float num6 = num4 * this._a1;
                float num7 = num4 * this._a2;
                vec  -= this._invMass1 * v;
                num  -= this._invI1 * num6;
                vec2 += this._invMass2 * v;
                num2 += this._invI2 * num7;
            }
            Vec2 v2;

            v2.X = Vec2.Dot(this._perp, vec2 - vec) + this._s2 * num2 - this._s1 * num;
            v2.Y = num2 - num;
            if (this._enableLimit && this._limitState != LimitState.InactiveLimit)
            {
                float z       = Vec2.Dot(this._axis, vec2 - vec) + this._a2 * num2 - this._a1 * num;
                Vec3  v3      = new Vec3(v2.X, v2.Y, z);
                Vec3  impulse = this._impulse;
                Vec3  v4      = this._K.Solve33(-v3);
                this._impulse += v4;
                if (this._limitState == LimitState.AtLowerLimit)
                {
                    this._impulse.Z = Box2DX.Common.Math.Max(this._impulse.Z, 0f);
                }
                else
                {
                    if (this._limitState == LimitState.AtUpperLimit)
                    {
                        this._impulse.Z = Box2DX.Common.Math.Min(this._impulse.Z, 0f);
                    }
                }
                Vec2 b    = -v2 - (this._impulse.Z - impulse.Z) * new Vec2(this._K.Col3.X, this._K.Col3.Y);
                Vec2 vec3 = this._K.Solve22(b) + new Vec2(impulse.X, impulse.Y);
                this._impulse.X = vec3.X;
                this._impulse.Y = vec3.Y;
                v4 = this._impulse - impulse;
                Vec2  v    = v4.X * this._perp + v4.Z * this._axis;
                float num6 = v4.X * this._s1 + v4.Y + v4.Z * this._a1;
                float num7 = v4.X * this._s2 + v4.Y + v4.Z * this._a2;
                vec  -= this._invMass1 * v;
                num  -= this._invI1 * num6;
                vec2 += this._invMass2 * v;
                num2 += this._invI2 * num7;
            }
            else
            {
                Vec2 vec4 = this._K.Solve22(-v2);
                this._impulse.X = this._impulse.X + vec4.X;
                this._impulse.Y = this._impulse.Y + vec4.Y;
                Vec2  v    = vec4.X * this._perp;
                float num6 = vec4.X * this._s1 + vec4.Y;
                float num7 = vec4.X * this._s2 + vec4.Y;
                vec  -= this._invMass1 * v;
                num  -= this._invI1 * num6;
                vec2 += this._invMass2 * v;
                num2 += this._invI2 * num7;
            }
            body._linearVelocity   = vec;
            body._angularVelocity  = num;
            body2._linearVelocity  = vec2;
            body2._angularVelocity = num2;
        }
Esempio n. 13
0
        internal override void InitVelocityConstraints(TimeStep step)
        {
            Body body  = this._body1;
            Body body2 = this._body2;

            this._localCenter1 = body.GetLocalCenter();
            this._localCenter2 = body2.GetLocalCenter();
            XForm xForm  = body.GetXForm();
            XForm xForm2 = body2.GetXForm();
            Vec2  v      = Box2DX.Common.Math.Mul(xForm.R, this._localAnchor1 - this._localCenter1);
            Vec2  vec    = Box2DX.Common.Math.Mul(xForm2.R, this._localAnchor2 - this._localCenter2);
            Vec2  vec2   = body2._sweep.C + vec - body._sweep.C - v;

            this._invMass1  = body._invMass;
            this._invI1     = body._invI;
            this._invMass2  = body2._invMass;
            this._invI2     = body2._invI;
            this._axis      = Box2DX.Common.Math.Mul(xForm.R, this._localXAxis1);
            this._a1        = Vec2.Cross(vec2 + v, this._axis);
            this._a2        = Vec2.Cross(vec, this._axis);
            this._motorMass = this._invMass1 + this._invMass2 + this._invI1 * this._a1 * this._a1 + this._invI2 * this._a2 * this._a2;
            Box2DXDebug.Assert(this._motorMass > Settings.FLT_EPSILON);
            this._motorMass = 1f / this._motorMass;
            this._perp      = Box2DX.Common.Math.Mul(xForm.R, this._localYAxis1);
            this._s1        = Vec2.Cross(vec2 + v, this._perp);
            this._s2        = Vec2.Cross(vec, this._perp);
            float invMass  = this._invMass1;
            float invMass2 = this._invMass2;
            float invI     = this._invI1;
            float invI2    = this._invI2;
            float x        = invMass + invMass2 + invI * this._s1 * this._s1 + invI2 * this._s2 * this._s2;
            float num      = invI * this._s1 + invI2 * this._s2;
            float num2     = invI * this._s1 * this._a1 + invI2 * this._s2 * this._a2;
            float y        = invI + invI2;
            float num3     = invI * this._a1 + invI2 * this._a2;
            float z        = invMass + invMass2 + invI * this._a1 * this._a1 + invI2 * this._a2 * this._a2;

            this._K.Col1.Set(x, num, num2);
            this._K.Col2.Set(num, y, num3);
            this._K.Col3.Set(num2, num3, z);
            if (this._enableLimit)
            {
                float num4 = Vec2.Dot(this._axis, vec2);
                if (Box2DX.Common.Math.Abs(this._upperTranslation - this._lowerTranslation) < 2f * Settings.LinearSlop)
                {
                    this._limitState = LimitState.EqualLimits;
                }
                else
                {
                    if (num4 <= this._lowerTranslation)
                    {
                        if (this._limitState != LimitState.AtLowerLimit)
                        {
                            this._limitState = LimitState.AtLowerLimit;
                            this._impulse.Z  = 0f;
                        }
                    }
                    else
                    {
                        if (num4 >= this._upperTranslation)
                        {
                            if (this._limitState != LimitState.AtUpperLimit)
                            {
                                this._limitState = LimitState.AtUpperLimit;
                                this._impulse.Z  = 0f;
                            }
                        }
                        else
                        {
                            this._limitState = LimitState.InactiveLimit;
                            this._impulse.Z  = 0f;
                        }
                    }
                }
            }
            if (!this._enableMotor)
            {
                this._motorImpulse = 0f;
            }
            if (step.WarmStarting)
            {
                this._impulse      *= step.DtRatio;
                this._motorImpulse *= step.DtRatio;
                Vec2  v2       = this._impulse.X * this._perp + (this._motorImpulse + this._impulse.Z) * this._axis;
                float num5     = this._impulse.X * this._s1 + this._impulse.Y + (this._motorImpulse + this._impulse.Z) * this._a1;
                float num6     = this._impulse.X * this._s2 + this._impulse.Y + (this._motorImpulse + this._impulse.Z) * this._a2;
                Body  expr_4BB = body;
                expr_4BB._linearVelocity -= this._invMass1 * v2;
                body._angularVelocity    -= this._invI1 * num5;
                Body expr_4EF = body2;
                expr_4EF._linearVelocity += this._invMass2 * v2;
                body2._angularVelocity   += this._invI2 * num6;
            }
            else
            {
                this._impulse.SetZero();
                this._motorImpulse = 0f;
            }
        }
Esempio n. 14
0
        public override bool Raycast(RayCastOutput output, RayCastInput input, Transform xf, int childIndex)
        {
            // Put the ray into the edge's frame of reference.
            Vec2 p1 = pool0.Set(input.P1).SubLocal(xf.P);

            Rot.MulTrans(xf.Q, p1, p1);
            Vec2 p2 = pool1.Set(input.P2).SubLocal(xf.P);

            Rot.MulTrans(xf.Q, p1, p1);
            Vec2 d = p2.SubLocal(p1); // we don't use p2 later

            Vec2 v1     = Vertex1;
            Vec2 v2     = Vertex2;
            Vec2 normal = pool2.Set(v2).SubLocal(v1);

            normal.Set(normal.Y, -normal.X);
            normal.Normalize();

            // q = p1 + t * d
            // dot(normal, q - v1) = 0
            // dot(normal, p1 - v1) + t * dot(normal, d) = 0
            pool3.Set(v1).SubLocal(p1);
            float numerator   = Vec2.Dot(normal, pool3);
            float denominator = Vec2.Dot(normal, d);

            if (denominator == 0.0f)
            {
                return(false);
            }

            float t = numerator / denominator;

            if (t < 0.0f || 1.0f < t)
            {
                return(false);
            }

            Vec2 q = pool3;
            Vec2 r = pool4;

            // Vec2 q = p1 + t * d;
            q.Set(d).MulLocal(t).AddLocal(p1);

            // q = v1 + s * r
            // s = dot(q - v1, r) / dot(r, r)
            // Vec2 r = v2 - v1;
            r.Set(v2).SubLocal(v1);
            float rr = Vec2.Dot(r, r);

            if (rr == 0.0f)
            {
                return(false);
            }

            pool5.Set(q).SubLocal(v1);
            float s = Vec2.Dot(pool5, r) / rr;

            if (s < 0.0f || 1.0f < s)
            {
                return(false);
            }

            output.Fraction = t;
            if (numerator > 0.0f)
            {
                // argOutput.normal = -normal;
                output.Normal.Set(normal).NegateLocal();
            }
            else
            {
                // output.normal = normal;
                output.Normal.Set(normal);
            }
            return(true);
        }
Esempio n. 15
0
        public void SolveVelocityConstraints()
        {
            for (int i = 0; i < Count; ++i)
            {
                ContactVelocityConstraint vc = VelocityConstraints[i];

                int indexA = vc.IndexA;
                int indexB = vc.IndexB;

                float mA         = vc.InvMassA;
                float mB         = vc.InvMassB;
                float iA         = vc.InvIA;
                float iB         = vc.InvIB;
                int   pointCount = vc.PointCount;

                Vec2  vA = Velocities[indexA].V;
                float wA = Velocities[indexA].W;
                Vec2  vB = Velocities[indexB].V;
                float wB = Velocities[indexB].W;
                //Debug.Assert(wA == 0);
                //Debug.Assert(wB == 0);

                Vec2 normal = vc.Normal;
                //Vec2.crossToOutUnsafe(normal, 1f, tangent);
                tangent.X = 1.0f * vc.Normal.Y;
                tangent.Y = (-1.0f) * vc.Normal.X;
                float friction = vc.Friction;

                Debug.Assert(pointCount == 1 || pointCount == 2);

                // Solve tangent constraints
                for (int j = 0; j < pointCount; ++j)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp = vc.Points[j];
                    //Vec2.crossToOutUnsafe(wA, vcp.rA, temp);
                    //Vec2.crossToOutUnsafe(wB, vcp.rB, dv);
                    //dv.addLocal(vB).subLocal(vA).subLocal(temp);
                    Vec2 a = vcp.RA;

                    dv.X = (-wB) * vcp.RB.Y + vB.X - vA.X + wA * a.Y;
                    dv.Y = wB * vcp.RB.X + vB.Y - vA.Y - wA * a.X;

                    // Compute tangent force
                    float vt     = dv.X * tangent.X + dv.Y * tangent.Y - vc.TangentSpeed;
                    float lambda = vcp.TangentMass * (-vt);

                    // Clamp the accumulated force
                    float maxFriction = friction * vcp.NormalImpulse;
                    float newImpulse  = MathUtils.Clamp(vcp.TangentImpulse + lambda, -maxFriction, maxFriction);
                    lambda             = newImpulse - vcp.TangentImpulse;
                    vcp.TangentImpulse = newImpulse;

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

                    float Px = tangent.X * lambda;
                    float Py = tangent.Y * lambda;

                    // vA -= invMassA * P;
                    vA.X -= Px * mA;
                    vA.Y -= Py * mA;
                    wA   -= iA * (vcp.RA.X * Py - vcp.RA.Y * Px);

                    // vB += invMassB * P;
                    vB.X += Px * mB;
                    vB.Y += Py * mB;
                    wB   += iB * (vcp.RB.X * Py - vcp.RB.Y * Px);

                    //Console.WriteLine("tangent solve velocity (point "+j+") for " + indexA + " is " + vA.x + "," + vA.y + " rot " + wA);
                    //Console.WriteLine("tangent solve velocity (point "+j+") for " + indexB + " is " + vB.x + "," + vB.y + " rot " + wB);
                }

                // Solve normal constraints
                if (vc.PointCount == 1)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp = vc.Points[0];
                    Vec2 a1 = vcp.RA;

                    // Relative velocity at contact
                    //Vec2 dv = vB + Cross(wB, vcp.rB) - vA - Cross(wA, vcp.rA);

                    //Vec2.crossToOut(wA, vcp.rA, temp1);
                    //Vec2.crossToOut(wB, vcp.rB, dv);
                    //dv.addLocal(vB).subLocal(vA).subLocal(temp1);

                    dv.X = (-wB) * vcp.RB.Y + vB.X - vA.X + wA * a1.Y;
                    dv.Y = wB * vcp.RB.X + vB.Y - vA.Y - wA * a1.X;

                    // Compute normal impulse
                    float vn     = dv.X * normal.X + dv.Y * normal.Y;
                    float lambda = (-vcp.NormalMass) * (vn - vcp.VelocityBias);

                    // Clamp the accumulated impulse
                    float a          = vcp.NormalImpulse + lambda;
                    float newImpulse = (a > 0.0f ? a : 0.0f);
                    lambda = newImpulse - vcp.NormalImpulse;
                    //Debug.Assert(newImpulse == 0);
                    vcp.NormalImpulse = newImpulse;

                    // Apply contact impulse
                    float Px = normal.X * lambda;
                    float Py = normal.Y * lambda;

                    // vA -= invMassA * P;
                    vA.X -= Px * mA;
                    vA.Y -= Py * mA;
                    wA   -= iA * (vcp.RA.X * Py - vcp.RA.Y * Px);
                    //Debug.Assert(vA.x == 0);

                    // vB += invMassB * P;
                    vB.X += Px * mB;
                    vB.Y += Py * mB;
                    wB   += iB * (vcp.RB.X * Py - vcp.RB.Y * Px);
                    //Debug.Assert(vB.x == 0);
                }
                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 = a + d
                    //
                    // a := old total impulse
                    // x := new total impulse
                    // d := incremental impulse
                    //
                    // For the current iteration we extend the formula for the incremental impulse
                    // to compute the new total impulse:
                    //
                    // vn = A * d + b
                    // = A * (x - a) + b
                    // = A * x + b - A * a
                    // = A * x + b'
                    // b' = b - A * a;

                    ContactVelocityConstraint.VelocityConstraintPoint cp1 = vc.Points[0];
                    ContactVelocityConstraint.VelocityConstraintPoint cp2 = vc.Points[1];
                    a.X = cp1.NormalImpulse;
                    a.Y = cp2.NormalImpulse;

                    Debug.Assert(a.X >= 0.0f && a.Y >= 0.0f);
                    // Relative velocity at contact
                    // Vec2 dv1 = vB + Cross(wB, cp1.rB) - vA - Cross(wA, cp1.rA);
                    dv1.X = (-wB) * cp1.RB.Y + vB.X - vA.X + wA * cp1.RA.Y;
                    dv1.Y = wB * cp1.RB.X + vB.Y - vA.Y - wA * cp1.RA.X;

                    // Vec2 dv2 = vB + Cross(wB, cp2.rB) - vA - Cross(wA, cp2.rA);
                    dv2.X = (-wB) * cp2.RB.Y + vB.X - vA.X + wA * cp2.RA.Y;
                    dv2.Y = wB * cp2.RB.X + vB.Y - vA.Y - wA * cp2.RA.X;

                    // Compute normal velocity
                    float vn1 = dv1.X * normal.X + dv1.Y * normal.Y;
                    float vn2 = dv2.X * normal.X + dv2.Y * normal.Y;

                    b.X = vn1 - cp1.VelocityBias;
                    b.Y = vn2 - cp2.VelocityBias;
                    //Console.WriteLine("b is " + b.x + "," + b.y);

                    // Compute b'
                    Mat22 R = vc.K;
                    b.X -= (R.Ex.X * a.X + R.Ey.X * a.Y);
                    b.Y -= (R.Ex.Y * a.X + R.Ey.Y * a.Y);
                    //Console.WriteLine("b' is " + b.x + "," + b.y);

                    // final 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 = - Mul(c.normalMass, b);
                        Mat22.MulToOutUnsafe(vc.NormalMass, b, x);
                        x.MulLocal(-1);

                        if (x.X >= 0.0f && x.Y >= 0.0f)
                        {
                            //Console.WriteLine("case 1");
                            // Get the incremental impulse
                            // Vec2 d = x - a;
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse
                            // Vec2 P1 = d.x * normal;
                            // Vec2 P2 = d.y * normal;
                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            /*
                             * vA -= invMassA * (P1 + P2); wA -= invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));

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

                            /*
                             * #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = vB + Cross(wB, cp1.rB) - vA -
                             * Cross(wA, cp1.rA); dv2 = vB + Cross(wB, cp2.rB) - vA - Cross(wA, cp2.rA);
                             *
                             * // Compute normal velocity vn1 = Dot(dv1, normal); vn2 = Dot(dv2, normal);
                             *
                             * Debug.Assert(Abs(vn1 - cp1.velocityBias) < k_errorTol); Debug.Assert(Abs(vn2 - cp2.velocityBias)
                             * < k_errorTol); #endif
                             */
                            if (DEBUG_SOLVER)
                            {
                                // Postconditions
                                Vec2 _dv1 = vB.Add(Vec2.Cross(wB, cp1.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp1.RA)));
                                Vec2 _dv2 = vB.Add(Vec2.Cross(wB, cp2.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp2.RA)));
                                // Compute normal velocity
                                vn1 = Vec2.Dot(_dv1, normal);
                                vn2 = Vec2.Dot(_dv2, normal);

                                Debug.Assert(MathUtils.Abs(vn1 - cp1.VelocityBias) < ERROR_TO_I);
                                Debug.Assert(MathUtils.Abs(vn2 - cp2.VelocityBias) < ERROR_TO_I);
                            }
                            break;
                        }

                        //
                        // Case 2: vn1 = 0 and x2 = 0
                        //
                        // 0 = a11 * x1' + a12 * 0 + b1'
                        // vn2 = a21 * x1' + a22 * 0 + '
                        //
                        x.X = (-cp1.NormalMass) * b.X;
                        x.Y = 0.0f;
                        vn1 = 0.0f;
                        vn2 = vc.K.Ex.Y * x.X + b.Y;

                        if (x.X >= 0.0f && vn2 >= 0.0f)
                        {
                            //Console.WriteLine("case 2");
                            // Get the incremental impulse
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse
                            // Vec2 P1 = d.x * normal;
                            // Vec2 P2 = d.y * normal;
                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            /*
                             * Vec2 P1 = d.x * normal; Vec2 P2 = d.y * normal; vA -= invMassA * (P1 + P2); wA -=
                             * invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));


                            // Accumulate
                            //Debug.Assert(x.x == 0 && x.y == 0);
                            cp1.NormalImpulse = x.X;
                            cp2.NormalImpulse = x.Y;

                            /*
                             * #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = vB + Cross(wB, cp1.rB) - vA -
                             * Cross(wA, cp1.rA);
                             *
                             * // Compute normal velocity vn1 = Dot(dv1, normal);
                             *
                             * Debug.Assert(Abs(vn1 - cp1.velocityBias) < k_errorTol); #endif
                             */
                            if (DEBUG_SOLVER)
                            {
                                // Postconditions
                                Vec2 _dv1 = vB.Add(Vec2.Cross(wB, cp1.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp1.RA)));
                                // Compute normal velocity
                                vn1 = Vec2.Dot(_dv1, normal);

                                Debug.Assert(MathUtils.Abs(vn1 - cp1.VelocityBias) < ERROR_TO_I);
                            }
                            break;
                        }


                        //
                        // Case 3: wB = 0 and x1 = 0
                        //
                        // vn1 = a11 * 0 + a12 * x2' + b1'
                        // 0 = a21 * 0 + a22 * x2' + '
                        //
                        x.X = 0.0f;
                        x.Y = (-cp2.NormalMass) * b.Y;
                        vn1 = vc.K.Ey.X * x.Y + b.X;
                        vn2 = 0.0f;

                        if (x.Y >= 0.0f && vn1 >= 0.0f)
                        {
                            //Console.WriteLine("case 3");
                            // Resubstitute for the incremental impulse
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse

                            /*
                             * Vec2 P1 = d.x * normal; Vec2 P2 = d.y * normal; vA -= invMassA * (P1 + P2); wA -=
                             * invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));

                            // Accumulate
                            //Debug.Assert(x.x == 0 && x.y == 0);
                            cp1.NormalImpulse = x.X;
                            cp2.NormalImpulse = x.Y;

                            /*
                             * #if B2_DEBUG_SOLVER == 1 // Postconditions dv2 = vB + Cross(wB, cp2.rB) - vA -
                             * Cross(wA, cp2.rA);
                             *
                             * // Compute normal velocity vn2 = Dot(dv2, normal);
                             *
                             * Debug.Assert(Abs(vn2 - cp2.velocityBias) < k_errorTol); #endif
                             */
                            if (DEBUG_SOLVER)
                            {
                                // Postconditions
                                Vec2 _dv2 =
                                    vB.Add(Vec2.Cross(wB, cp2.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp2.RA)));
                                // Compute normal velocity
                                vn2 = Vec2.Dot(_dv2, normal);

                                Debug.Assert(MathUtils.Abs(vn2 - cp2.VelocityBias) < ERROR_TO_I);
                            }
                            break;
                        }

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

                        if (vn1 >= 0.0f && vn2 >= 0.0f)
                        {
                            //Console.WriteLine("case 4");
                            // Resubstitute for the incremental impulse
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse

                            /*
                             * Vec2 P1 = d.x * normal; Vec2 P2 = d.y * normal; vA -= invMassA * (P1 + P2); wA -=
                             * invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));


                            // Accumulate
                            //Debug.Assert(x.x == 0 && x.y == 0);
                            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;
                    }
                }

                Velocities[indexA].V.Set(vA);
                Velocities[indexA].W = wA;
                Velocities[indexB].V.Set(vB);
                Velocities[indexB].W = wB;

                //Console.WriteLine("Ending velocity for " + indexA + " is " + vA.x + "," + vA.y + " rot " + wA);
                //Console.WriteLine("Ending velocity for " + indexB + " is " + vB.x + "," + vB.y + " rot " + wB);
            }
        }
Esempio n. 16
0
        public void SolveVelocityConstraints()
        {
            for (int i = 0; i < _constraintCount; ++i)
            {
                ContactConstraint c = _constraints[i];
                Body  b1            = c.Body1;
                Body  b2            = c.Body2;
                float w1            = b1._angularVelocity;
                float w2            = b2._angularVelocity;
                Vec2  v1            = b1._linearVelocity;
                Vec2  v2            = b2._linearVelocity;
                float invMass1      = b1._invMass;
                float invI1         = b1._invI;
                float invMass2      = b2._invMass;
                float invI2         = b2._invI;
                Vec2  normal        = c.Normal;
                Vec2  tangent       = Vec2.Cross(normal, 1.0f);
                float friction      = c.Friction;

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

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

                    // Relative velocity at contact
                    Vec2 dv = v2 + Vec2.Cross(w2, ccp.R2) - v1 - Vec2.Cross(w1, ccp.R1);

                    // 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;

                    v1 -= invMass1 * P;
                    w1 -= invI1 * Vec2.Cross(ccp.R1, P);

                    v2 += invMass2 * P;
                    w2 += invI2 * Vec2.Cross(ccp.R2, 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 = c.Points[0];
                    ContactConstraintPoint cp2 = c.Points[1];

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

                    // Relative velocity at contact
                    Vec2 dv1 = v2 + Vec2.Cross(w2, cp1.R2) - v1 - Vec2.Cross(w1, cp1.R1);
                    Vec2 dv2 = v2 + Vec2.Cross(w2, cp2.R2) - v1 - Vec2.Cross(w1, cp2.R1);

                    // 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;
                    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;
                            v1 -= invMass1 * (P1 + P2);
                            w1 -= invI1 * (Vec2.Cross(cp1.R1, P1) + Vec2.Cross(cp2.R1, P2));

                            v2 += invMass2 * (P1 + P2);
                            w2 += invI2 * (Vec2.Cross(cp1.R2, P1) + Vec2.Cross(cp2.R2, P2));

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

#if B2_DEBUG_SOLVER
                            // Postconditions
                            dv1 = v2 + Vector2.Cross(w2, cp1.R2) - v1 - Vector2.Cross(w1, cp1.R1);
                            dv2 = v2 + Vector2.Cross(w2, cp2.R2) - v1 - Vector2.Cross(w1, cp2.R1);

                            // Compute normal velocity
                            vn1 = Vector2.Dot(dv1, normal);
                            vn2 = Vector2.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;
                            v1 -= invMass1 * (P1 + P2);
                            w1 -= invI1 * (Vec2.Cross(cp1.R1, P1) + Vec2.Cross(cp2.R1, P2));

                            v2 += invMass2 * (P1 + P2);
                            w2 += invI2 * (Vec2.Cross(cp1.R2, P1) + Vec2.Cross(cp2.R2, P2));

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

#if B2_DEBUG_SOLVER
                            // Postconditions
                            dv1 = v2 + Vector2.Cross(w2, cp1.R2) - v1 - Vector2.Cross(w1, cp1.R1);

                            // Compute normal velocity
                            vn1 = Vector2.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;
                            v1 -= invMass1 * (P1 + P2);
                            w1 -= invI1 * (Vec2.Cross(cp1.R1, P1) + Vec2.Cross(cp2.R1, P2));

                            v2 += invMass2 * (P1 + P2);
                            w2 += invI2 * (Vec2.Cross(cp1.R2, P1) + Vec2.Cross(cp2.R2, P2));

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

#if B2_DEBUG_SOLVER
                            // Postconditions
                            dv2 = v2 + Vector2.Cross(w2, cp2.R2) - v1 - Vector2.Cross(w1, cp2.R1);

                            // Compute normal velocity
                            vn2 = Vector2.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;
                            v1 -= invMass1 * (P1 + P2);
                            w1 -= invI1 * (Vec2.Cross(cp1.R1, P1) + Vec2.Cross(cp2.R1, P2));

                            v2 += invMass2 * (P1 + P2);
                            w2 += invI2 * (Vec2.Cross(cp1.R2, P1) + Vec2.Cross(cp2.R2, 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;
                    }
                }

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

                    // Relative velocity at contact
                    Vec2 dv = v2 + Vec2.Cross(w2, ccp.R2) - v1 - Vec2.Cross(w1, ccp.R1);

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

                    // Clamp 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;

                    v1 -= invMass1 * P;
                    w1 -= invI1 * Vec2.Cross(ccp.R1, P);

                    v2 += invMass2 * P;
                    w2 += invI2 * Vec2.Cross(ccp.R2, P);

                    ccp.TangentImpulse = newImpulse;
                }

                b1._linearVelocity  = v1;
                b1._angularVelocity = w1;
                b2._linearVelocity  = v2;
                b2._angularVelocity = w2;
            }
        }
Esempio n. 17
0
        internal override void InitVelocityConstraints(TimeStep step)
        {
            Body b1 = _body1;
            Body b2 = _body2;

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

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

            // Compute point to line constraint effective mass.
            // J = [-ay1 -cross(d+r1,ay1) ay1 cross(r2,ay1)]
            Vec2 ay1 = Box2DXMath.Mul(b1.GetXForm().R, _localYAxis1);
            Vec2 e   = b2._sweep.C + r2 - b1._sweep.C;                  // e = d + r1

            _linearJacobian.Set(-ay1, -Vec2.Cross(e, ay1), ay1, Vec2.Cross(r2, ay1));
            _linearMass = invMass1 + invI1 * _linearJacobian.Angular1 * _linearJacobian.Angular1 +
                          invMass2 + invI2 * _linearJacobian.Angular2 * _linearJacobian.Angular2;
            Box2DXDebug.Assert(_linearMass > Settings.FLT_EPSILON);
            _linearMass = 1.0f / _linearMass;

            // Compute angular constraint effective mass.
            _angularMass = invI1 + invI2;
            if (_angularMass > Settings.FLT_EPSILON)
            {
                _angularMass = 1.0f / _angularMass;
            }

            // Compute motor and limit terms.
            if (_enableLimit || _enableMotor)
            {
                // The motor and limit share a Jacobian and effective mass.
                Vec2 ax1 = Box2DXMath.Mul(b1.GetXForm().R, _localXAxis1);
                _motorJacobian.Set(-ax1, -Vec2.Cross(e, ax1), ax1, Vec2.Cross(r2, ax1));
                _motorMass = invMass1 + invI1 * _motorJacobian.Angular1 * _motorJacobian.Angular1 +
                             invMass2 + invI2 * _motorJacobian.Angular2 * _motorJacobian.Angular2;
                Box2DXDebug.Assert(_motorMass > Settings.FLT_EPSILON);
                _motorMass = 1.0f / _motorMass;

                if (_enableLimit)
                {
                    Vec2  d = e - r1;                           // p2 - p1
                    float jointTranslation = Vec2.Dot(ax1, d);
                    if (Box2DXMath.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
                    {
                        _limitState = LimitState.EqualLimits;
                    }
                    else if (jointTranslation <= _lowerTranslation)
                    {
                        if (_limitState != LimitState.AtLowerLimit)
                        {
                            _limitForce = 0.0f;
                        }
                        _limitState = LimitState.AtLowerLimit;
                    }
                    else if (jointTranslation >= _upperTranslation)
                    {
                        if (_limitState != LimitState.AtUpperLimit)
                        {
                            _limitForce = 0.0f;
                        }
                        _limitState = LimitState.AtUpperLimit;
                    }
                    else
                    {
                        _limitState = LimitState.InactiveLimit;
                        _limitForce = 0.0f;
                    }
                }
            }

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

            if (_enableLimit == false)
            {
                _limitForce = 0.0f;
            }

            if (step.WarmStarting)
            {
                Vec2  P1 = Settings.FORCE_SCALE(step.Dt) * (_force * _linearJacobian.Linear1 + (_motorForce + _limitForce) * _motorJacobian.Linear1);
                Vec2  P2 = Settings.FORCE_SCALE(step.Dt) * (_force * _linearJacobian.Linear2 + (_motorForce + _limitForce) * _motorJacobian.Linear2);
                float L1 = Settings.FORCE_SCALE(step.Dt) * (_force * _linearJacobian.Angular1 - _torque + (_motorForce + _limitForce) * _motorJacobian.Angular1);
                float L2 = Settings.FORCE_SCALE(step.Dt) * (_force * _linearJacobian.Angular2 + _torque + (_motorForce + _limitForce) * _motorJacobian.Angular2);

                b1._linearVelocity  += invMass1 * P1;
                b1._angularVelocity += invI1 * L1;

                b2._linearVelocity  += invMass2 * P2;
                b2._angularVelocity += invI2 * L2;
            }
            else
            {
                _force      = 0.0f;
                _torque     = 0.0f;
                _limitForce = 0.0f;
                _motorForce = 0.0f;
            }

            _limitPositionImpulse = 0.0f;
        }
Esempio n. 18
0
        public ContactSolver(TimeStep step, Contact[] contacts, int contactCount)
        {
            _step = step;

            _constraintCount = 0;
            for (int i = 0; i < contactCount; ++i)
            {
                Box2DXDebug.Assert(contacts[i].IsSolid());
                _constraintCount += contacts[i].GetManifoldCount();
            }

            _constraints = new ContactConstraint[_constraintCount];
            for (int i = 0; i < _constraintCount; i++)
            {
                _constraints[i] = new ContactConstraint();
            }

            int count = 0;

            for (int i = 0; i < contactCount; ++i)
            {
                Contact contact = contacts[i];

                Shape      shape1        = contact._shape1;
                Shape      shape2        = contact._shape2;
                Body       b1            = shape1.GetBody();
                Body       b2            = shape2.GetBody();
                int        manifoldCount = contact.GetManifoldCount();
                Manifold[] manifolds     = contact.GetManifolds();

                float friction    = Settings.MixFriction(shape1.Friction, shape2.Friction);
                float restitution = Settings.MixRestitution(shape1.Restitution, shape2.Restitution);

                Vec2  v1 = b1._linearVelocity;
                Vec2  v2 = b2._linearVelocity;
                float w1 = b1._angularVelocity;
                float w2 = b2._angularVelocity;

                for (int j = 0; j < manifoldCount; ++j)
                {
                    Manifold manifold = manifolds[j];

                    Box2DXDebug.Assert(manifold.PointCount > 0);

                    Vec2 normal = manifold.Normal;

                    Box2DXDebug.Assert(count < _constraintCount);
                    ContactConstraint cc = _constraints[count];
                    cc.Body1       = b1;
                    cc.Body2       = b2;
                    cc.Manifold    = manifold;
                    cc.Normal      = normal;
                    cc.PointCount  = manifold.PointCount;
                    cc.Friction    = friction;
                    cc.Restitution = restitution;

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

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

                        ccp.LocalAnchor1 = cp.LocalPoint1;
                        ccp.LocalAnchor2 = cp.LocalPoint2;
                        ccp.R1           = Common.Math.Mul(b1.GetXForm().R, cp.LocalPoint1 - b1.GetLocalCenter());
                        ccp.R2           = Common.Math.Mul(b2.GetXForm().R, cp.LocalPoint2 - b2.GetLocalCenter());

                        float rn1 = Vec2.Cross(ccp.R1, normal);
                        float rn2 = Vec2.Cross(ccp.R2, normal);
                        rn1 *= rn1;
                        rn2 *= rn2;

                        float kNormal = b1._invMass + b2._invMass + b1._invI * rn1 + b2._invI * rn2;

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

                        float kEqualized = b1._mass * b1._invMass + b2._mass * b2._invMass;
                        kEqualized += b1._mass * b1._invI * rn1 + b2._mass * b2._invI * rn2;

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

                        Vec2 tangent = Vec2.Cross(normal, 1.0f);

                        float rt1 = Vec2.Cross(ccp.R1, tangent);
                        float rt2 = Vec2.Cross(ccp.R2, tangent);
                        rt1 *= rt1;
                        rt2 *= rt2;

                        float kTangent = b1._invMass + b2._invMass + b1._invI * rt1 + b2._invI * rt2;

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

                        // Setup a velocity bias for restitution.
                        ccp.VelocityBias = 0.0f;
                        if (ccp.Separation > 0.0f)
                        {
                            ccp.VelocityBias = -step.Inv_Dt * ccp.Separation;                             // TODO_ERIN b2TimeStep
                        }
                        else
                        {
                            float vRel = Vec2.Dot(cc.Normal, v2 + Vec2.Cross(w2, ccp.R2) - v1 - Vec2.Cross(w1, ccp.R1));
                            if (vRel < -Settings.VelocityThreshold)
                            {
                                ccp.VelocityBias = -cc.Restitution * vRel;
                            }
                        }
                    }

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

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

                        float rn11 = Vec2.Cross(ccp1.R1, normal);
                        float rn12 = Vec2.Cross(ccp1.R2, normal);
                        float rn21 = Vec2.Cross(ccp2.R1, normal);
                        float rn22 = Vec2.Cross(ccp2.R2, normal);

                        float k11 = invMass1 + invMass2 + invI1 * rn11 * rn11 + invI2 * rn12 * rn12;
                        float k22 = invMass1 + invMass2 + invI1 * rn21 * rn21 + invI2 * rn22 * rn22;
                        float k12 = invMass1 + invMass2 + invI1 * rn11 * rn21 + invI2 * rn12 * rn22;

                        // 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.Set(k11, k12);
                            cc.K.Col2.Set(k12, k22);
                            cc.NormalMass = cc.K.Invert();
                        }
                        else
                        {
                            // The constraints are redundant, just use one.
                            // TODO_ERIN use deepest?
                            cc.PointCount = 1;
                        }
                    }

                    ++count;
                }
            }

            Box2DXDebug.Assert(count == _constraintCount);
        }
Esempio n. 19
0
        public void Solve(TimeStep step, Vec2 gravity, bool allowSleep)
        {
            for (int i = 0; i < this._bodyCount; i++)
            {
                Body body = this._bodies[i];
                if (!body.IsStatic())
                {
                    Body expr_27 = body;
                    //expr_27._linearVelocity += step.Dt * (gravity + body._invMass * body._force);
                    expr_27._linearVelocity += step.Dt * (body._useGravity ? body._gravity : gravity + body._invMass * body._force); //Steve body gravity
                    body._angularVelocity   += step.Dt * body._invI * body._torque;
                    body._force.Set(0f, 0f);
                    body._torque = 0f;
                    Body expr_9E = body;
                    expr_9E._linearVelocity *= Box2DX.Common.Math.Clamp(1f - step.Dt * body._linearDamping, 0f, 1f);
                    body._angularVelocity   *= Box2DX.Common.Math.Clamp(1f - step.Dt * body._angularDamping, 0f, 1f);
                    if (Vec2.Dot(body._linearVelocity, body._linearVelocity) > Settings.MaxLinearVelocitySquared)
                    {
                        body._linearVelocity.Normalize();
                        Body expr_130 = body;
                        expr_130._linearVelocity *= Settings.MaxLinearVelocity;
                    }
                    if (body._angularVelocity * body._angularVelocity > Settings.MaxAngularVelocitySquared)
                    {
                        if (body._angularVelocity < 0f)
                        {
                            body._angularVelocity = -Settings.MaxAngularVelocity;
                        }
                        else
                        {
                            body._angularVelocity = Settings.MaxAngularVelocity;
                        }
                    }
                }
            }
            ContactSolver contactSolver = new ContactSolver(step, this._contacts, this._contactCount);

            contactSolver.InitVelocityConstraints(step);
            for (int i = 0; i < this._jointCount; i++)
            {
                this._joints[i].InitVelocityConstraints(step);
            }
            for (int i = 0; i < step.VelocityIterations; i++)
            {
                for (int j = 0; j < this._jointCount; j++)
                {
                    this._joints[j].SolveVelocityConstraints(step);
                }
                contactSolver.SolveVelocityConstraints();
            }
            contactSolver.FinalizeVelocityConstraints();
            for (int i = 0; i < this._bodyCount; i++)
            {
                Body body = this._bodies[i];
                if (!body.IsStatic())
                {
                    body._sweep.C0 = body._sweep.C;
                    body._sweep.A0 = body._sweep.A;
                    Body expr_296_cp_0 = body;
                    expr_296_cp_0._sweep.C = expr_296_cp_0._sweep.C + step.Dt * body._linearVelocity;
                    Body expr_2BE_cp_0 = body;
                    expr_2BE_cp_0._sweep.A = expr_2BE_cp_0._sweep.A + step.Dt * body._angularVelocity;
                    body.SynchronizeTransform();
                }
            }
            for (int k = 0; k < step.PositionIterations; k++)
            {
                bool flag  = contactSolver.SolvePositionConstraints(Settings.ContactBaumgarte);
                bool flag2 = true;
                for (int i = 0; i < this._jointCount; i++)
                {
                    bool flag3 = this._joints[i].SolvePositionConstraints(Settings.ContactBaumgarte);
                    flag2 = (flag2 && flag3);
                }
                if (flag && flag2)
                {
                    break;
                }
            }
            this.Report(contactSolver._constraints);
            if (allowSleep)
            {
                float num  = Settings.FLT_MAX;
                float num2 = Settings.LinearSleepTolerance * Settings.LinearSleepTolerance;
                float num3 = Settings.AngularSleepTolerance * Settings.AngularSleepTolerance;
                for (int i = 0; i < this._bodyCount; i++)
                {
                    Body body = this._bodies[i];
                    if (body._invMass != 0f)
                    {
                        if ((body._flags & Body.BodyFlags.AllowSleep) == (Body.BodyFlags) 0)
                        {
                            body._sleepTime = 0f;
                            num             = 0f;
                        }
                        if ((body._flags & Body.BodyFlags.AllowSleep) == (Body.BodyFlags) 0 || body._angularVelocity * body._angularVelocity > num3 || Vec2.Dot(body._linearVelocity, body._linearVelocity) > num2)
                        {
                            body._sleepTime = 0f;
                            num             = 0f;
                        }
                        else
                        {
                            body._sleepTime += step.Dt;
                            num              = Box2DX.Common.Math.Min(num, body._sleepTime);
                        }
                    }
                }
                if (num >= Settings.TimeToSleep)
                {
                    for (int i = 0; i < this._bodyCount; i++)
                    {
                        Body body = this._bodies[i];
                        body._flags          |= Body.BodyFlags.Sleep;
                        body._linearVelocity  = Vec2.Zero;
                        body._angularVelocity = 0f;
                    }
                }
            }
        }
Esempio n. 20
0
        /// <summary>
        /// update override
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            if (Active)
            {
                var rotationDegrees = RigidBody.GetAngle() * 180 / System.Math.PI;

                if (Keyboard.GetState().IsKeyDown(Keys.OemOpenBrackets))
                {
                    if (Vec2.Distance(Vec2.Zero, RigidBody.GetLinearVelocity()) < GameData.PlayerMaxSpeed)
                    {
                        //apply impulse to push the player to left
                        var impulseVec = GameUtils.RotationToVec2((float)rotationDegrees - 90);
                        RigidBody.ApplyImpulse(impulseVec * GameData.PlayerLateralImpulse
                                               , RigidBody.GetPosition());
                    }
                }

                if (Keyboard.GetState().IsKeyDown(Keys.OemCloseBrackets))
                {
                    if (Vec2.Distance(Vec2.Zero, RigidBody.GetLinearVelocity()) < GameData.PlayerMaxSpeed)
                    {
                        //apply impulse to push the player to right
                        var impulseVec = GameUtils.RotationToVec2((float)rotationDegrees + 90);

                        RigidBody.ApplyImpulse(impulseVec * GameData.PlayerLateralImpulse
                                               , RigidBody.GetPosition());
                    }
                }

                if (FilteredInputListener.WasKeyPressed(Keys.Left))
                {
                    WeaponInventory.SelectPreviousWeapon();
                    FilteredInputListener.ResetKey(Keys.Left);
                }

                if (FilteredInputListener.WasKeyPressed(Keys.Right))
                {
                    WeaponInventory.SelectNextWeapon();
                    FilteredInputListener.ResetKey(Keys.Right);
                }

                if (Keyboard.GetState().IsKeyDown(Keys.W))
                {
                    if (Vec2.Distance(Vec2.Zero, RigidBody.GetLinearVelocity()) < GameData.PlayerMaxSpeed)
                    {
                        var impulseVec = GameUtils.RotationToVec2((float)rotationDegrees);
                        if (Vec2.Dot(impulseVec, RigidBody.GetLinearVelocity()) == 0)
                        {
                            RigidBody.SetLinearVelocity(Vec2.Zero);
                        }
                        RigidBody.ApplyImpulse(impulseVec * GameData.PlayerImpulse
                                               , RigidBody.GetPosition());
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.S))
                {
                    if (Vec2.Distance(Vec2.Zero, RigidBody.GetLinearVelocity()) < GameData.PlayerMaxSpeed)
                    {
                        var impulseVec = GameUtils.RotationToVec2((float)rotationDegrees);
                        RigidBody.ApplyImpulse(impulseVec * -GameData.PlayerImpulse
                                               , RigidBody.GetPosition());
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.D))
                {
                    //DecreaseLinearVelocity(GameData.PlayerTurnVelocityDecrement, 1);
                    RigidBody.ApplyTorque(GameData.PlayerTurnTorque);
                }
                if (Keyboard.GetState().IsKeyDown(Keys.A))
                {
                    //DecreaseLinearVelocity(GameData.PlayerTurnVelocityDecrement, 1);
                    RigidBody.ApplyTorque(-GameData.PlayerTurnTorque);
                }
                if (Keyboard.GetState().IsKeyDown(Keys.Space))
                {
                    var weapon = WeaponInventory.GetSelectedWeapon();
                    if (weapon != null && weapon.RemainingAmmo > 0)
                    {
                        if (DateTime.Now - _lastProjectileTime > TimeSpan.FromMilliseconds(100))
                        {
                            ShootingEffect.Play();

                            _lastProjectileTime = DateTime.Now;
                            WeaponInventory.DecreaseAmmo(1);
                            SpawnProjectile(weapon.ProjectileName, ProjectileSource.Player);
                        }
                    }
                }

                if (Keyboard.GetState().IsKeyUp(Keys.W) &&
                    Keyboard.GetState().IsKeyUp(Keys.A) &&
                    Keyboard.GetState().IsKeyUp(Keys.S) &&
                    Keyboard.GetState().IsKeyUp(Keys.D))
                {
                    DecreaseLinearVelocity(GameData.PlayerTurnVelocityDecrement, 0);
                }

                if (Keyboard.GetState().IsKeyUp(Keys.A) && Keyboard.GetState().IsKeyUp(Keys.D))
                {
                    RigidBody.SetAngularVelocity(0);
                }
            }
        }
Esempio n. 21
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 = Box2DNet.Common.Math.Mul(xf1.R, _localAnchor1 - _localCenter1);
            Vec2 r2 = Box2DNet.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 = Box2DNet.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;
                Box2DNetDebug.Assert(_motorMass > Settings.FLT_EPSILON);
                _motorMass = 1.0f / _motorMass;
            }

            // Prismatic constraint.
            {
                _perp = Box2DNet.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 (Box2DNet.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;
            }
        }
Esempio n. 22
0
        // Find edge normal of max separation on A - return if separating axis is found
        // Find edge normal of max separation on B - return if separation axis is found
        // Choose reference edge as min(minA, minB)
        // Find incident edge
        // Clip
        // The normal points from 1 to 2
        public static void CollidePolygons(ref Manifold manifold,
                                           PolygonShape polyA, XForm xfA, PolygonShape polyB, XForm xfB)
        {
            manifold.PointCount = 0;
            float totalRadius = polyA._radius + polyB._radius;

            int   edgeA       = 0;
            float separationA = Collision.FindMaxSeparation(ref edgeA, polyA, xfA, polyB, xfB);

            if (separationA > totalRadius)
            {
                return;
            }

            int   edgeB       = 0;
            float separationB = Collision.FindMaxSeparation(ref edgeB, polyB, xfB, polyA, xfA);

            if (separationB > totalRadius)
            {
                return;
            }

            PolygonShape poly1;                 // reference poly
            PolygonShape poly2;                 // incident poly
            XForm        xf1, xf2;
            int          edge1;                 // reference edge
            byte         flip;
            const float  k_relativeTol = 0.98f;
            const float  k_absoluteTol = 0.001f;

            if (separationB > k_relativeTol * separationA + k_absoluteTol)
            {
                poly1         = polyB;
                poly2         = polyA;
                xf1           = xfB;
                xf2           = xfA;
                edge1         = edgeB;
                manifold.Type = ManifoldType.FaceB;
                flip          = 1;
            }
            else
            {
                poly1         = polyA;
                poly2         = polyB;
                xf1           = xfA;
                xf2           = xfB;
                edge1         = edgeA;
                manifold.Type = ManifoldType.FaceA;
                flip          = 0;
            }

            ClipVertex[] incidentEdge;
            Collision.FindIncidentEdge(out incidentEdge, poly1, xf1, edge1, poly2, xf2);

            int count1 = poly1._vertexCount;

            Vec2[] vertices1 = poly1._vertices;

            Vec2 v11 = vertices1[edge1];
            Vec2 v12 = edge1 + 1 < count1 ? vertices1[edge1 + 1] : vertices1[0];

            Vec2 dv = v12 - v11;

            Vec2 localNormal = Vec2.Cross(dv, 1.0f);

            localNormal.Normalize();
            Vec2 planePoint = 0.5f * (v11 + v12);

            Vec2 sideNormal = Common.Math.Mul(xf1.R, v12 - v11);

            sideNormal.Normalize();
            Vec2 frontNormal = Vec2.Cross(sideNormal, 1.0f);

            v11 = Common.Math.Mul(xf1, v11);
            v12 = Common.Math.Mul(xf1, v12);

            float frontOffset = Vec2.Dot(frontNormal, v11);
            float sideOffset1 = -Vec2.Dot(sideNormal, v11);
            float sideOffset2 = Vec2.Dot(sideNormal, v12);

            // Clip incident edge against extruded edge1 side edges.
            ClipVertex[] clipPoints1;
            ClipVertex[] clipPoints2;
            int          np;

            // Clip to box side 1
            np = Collision.ClipSegmentToLine(out clipPoints1, incidentEdge, -sideNormal, sideOffset1);

            if (np < 2)
            {
                return;
            }

            // Clip to negative box side 1
            np = ClipSegmentToLine(out clipPoints2, clipPoints1, sideNormal, sideOffset2);

            if (np < 2)
            {
                return;
            }

            // Now clipPoints2 contains the clipped points.
            manifold.LocalPlaneNormal = localNormal;
            manifold.LocalPoint       = planePoint;

            int pointCount = 0;

            for (int i = 0; i < Settings.MaxManifoldPoints; ++i)
            {
                float separation = Vec2.Dot(frontNormal, clipPoints2[i].V) - frontOffset;

                if (separation <= totalRadius)
                {
                    ManifoldPoint cp = manifold.Points[pointCount];
                    cp.LocalPoint       = Common.Math.MulT(xf2, clipPoints2[i].V);
                    cp.ID               = clipPoints2[i].ID;
                    cp.ID.Features.Flip = flip;
                    ++pointCount;
                }
            }

            manifold.PointCount = pointCount;
        }
Esempio n. 23
0
        internal override bool SolvePositionConstraints(float baumgarte)
        {
            Body b1 = _body1;
            Body b2 = _body2;

            Vec2  c1 = b1._sweep.C;
            float a1 = b1._sweep.A;

            Vec2  c2 = b2._sweep.C;
            float a2 = b2._sweep.A;

            // Solve linear limit constraint.
            float linearError = 0.0f, angularError = 0.0f;
            bool  active = false;
            float C2     = 0.0f;

            Mat22 R1 = new Mat22(a1), R2 = new Mat22(a2);

            Vec2 r1 = Box2DNet.Common.Math.Mul(R1, _localAnchor1 - _localCenter1);
            Vec2 r2 = Box2DNet.Common.Math.Mul(R2, _localAnchor2 - _localCenter2);
            Vec2 d  = c2 + r2 - c1 - r1;

            if (_enableLimit)
            {
                _axis = Box2DNet.Common.Math.Mul(R1, _localXAxis1);

                _a1 = Vec2.Cross(d + r1, _axis);
                _a2 = Vec2.Cross(r2, _axis);

                float translation = Vec2.Dot(_axis, d);
                if (Box2DNet.Common.Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
                {
                    // Prevent large angular corrections
                    C2          = Box2DNet.Common.Math.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
                    linearError = Box2DNet.Common.Math.Abs(translation);
                    active      = true;
                }
                else if (translation <= _lowerTranslation)
                {
                    // Prevent large linear corrections and allow some slop.
                    C2          = Box2DNet.Common.Math.Clamp(translation - _lowerTranslation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
                    linearError = _lowerTranslation - translation;
                    active      = true;
                }
                else if (translation >= _upperTranslation)
                {
                    // Prevent large linear corrections and allow some slop.
                    C2          = Box2DNet.Common.Math.Clamp(translation - _upperTranslation - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection);
                    linearError = translation - _upperTranslation;
                    active      = true;
                }
            }

            _perp = Box2DNet.Common.Math.Mul(R1, _localYAxis1);

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

            Vec2  impulse;
            float C1;

            C1 = Vec2.Dot(_perp, d);

            linearError  = Box2DNet.Common.Math.Max(linearError, Box2DNet.Common.Math.Abs(C1));
            angularError = 0.0f;

            if (active)
            {
                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);

                Vec2 C = new Vec2();
                C.X = C1;
                C.Y = C2;

                impulse = _K.Solve(-C);
            }
            else
            {
                float m1 = _invMass1, m2 = _invMass2;
                float i1 = _invI1, i2 = _invI2;

                float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;

                float impulse1 = (-C1) / k11;
                impulse.X = impulse1;
                impulse.Y = 0.0f;
            }

            Vec2  P  = impulse.X * _perp + impulse.Y * _axis;
            float L1 = impulse.X * _s1 + impulse.Y * _a1;
            float L2 = impulse.X * _s2 + impulse.Y * _a2;

            c1 -= _invMass1 * P;
            a1 -= _invI1 * L1;
            c2 += _invMass2 * P;
            a2 += _invI2 * L2;

            // TODO_ERIN remove need for this.
            b1._sweep.C = c1;
            b1._sweep.A = a1;
            b2._sweep.C = c2;
            b2._sweep.A = a2;
            b1.SynchronizeTransform();
            b2.SynchronizeTransform();

            return(linearError <= Settings.LinearSlop && angularError <= Settings.AngularSlop);
        }
Esempio n. 24
0
        /// <summary>
        /// Find the max separation between poly1 and poly2 using edge normals from poly1.
        /// </summary>
        public static float FindMaxSeparation(ref int edgeIndex, PolygonShape poly1, XForm xf1, PolygonShape poly2, XForm xf2)
        {
            int count1 = poly1._vertexCount;

            Vec2[] normals1 = poly1._normals;

            // Vector pointing from the centroid of poly1 to the centroid of poly2.
            Vec2 d       = Common.Math.Mul(xf2, poly2._centroid) - Common.Math.Mul(xf1, poly1._centroid);
            Vec2 dLocal1 = Common.Math.MulT(xf1.R, d);

            // Find edge normal on poly1 that has the largest projection onto d.
            int   edge   = 0;
            float maxDot = -Common.Settings.FLT_MAX;

            for (int i = 0; i < count1; ++i)
            {
                float dot = Vec2.Dot(normals1[i], dLocal1);
                if (dot > maxDot)
                {
                    maxDot = dot;
                    edge   = i;
                }
            }

            // Get the separation for the edge normal.
            float s = Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2);

            // Check the separation for the previous edge normal.
            int   prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
            float sPrev    = Collision.EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);

            // Check the separation for the next edge normal.
            int   nextEdge = edge + 1 < count1 ? edge + 1 : 0;
            float sNext    = Collision.EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);

            // Find the best edge and the search direction.
            int   bestEdge;
            float bestSeparation;
            int   increment;

            if (sPrev > s && sPrev > sNext)
            {
                increment      = -1;
                bestEdge       = prevEdge;
                bestSeparation = sPrev;
            }
            else if (sNext > s)
            {
                increment      = 1;
                bestEdge       = nextEdge;
                bestSeparation = sNext;
            }
            else
            {
                edgeIndex = edge;
                return(s);
            }

            // Perform a local search for the best edge normal.
            for (; ;)
            {
                if (increment == -1)
                {
                    edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
                }
                else
                {
                    edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
                }

                s = Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2);

                if (s > bestSeparation)
                {
                    bestEdge       = edge;
                    bestSeparation = s;
                }
                else
                {
                    break;
                }
            }

            edgeIndex = bestEdge;
            return(bestSeparation);
        }
Esempio n. 25
0
 public override Vec2 GetSupportVertex(Vec2 d)
 {
     return(Vec2.Dot(_v1, d) > Vec2.Dot(_v2, d) ? _v1 : _v2);
 }
Esempio n. 26
0
        public void Solve(TimeStep step, Vec2 gravity, bool allowSleep)
        {
            // Integrate velocities and apply damping.
            for (int i = 0; i < _bodyCount; ++i)
            {
                Body b = _bodies[i];

                if (b.IsStatic())
                {
                    continue;
                }

                // Integrate velocities.
                b._linearVelocity  += step.Dt * (gravity + b._invMass * b._force);
                b._angularVelocity += step.Dt * b._invI * b._torque;

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

                // Apply damping.
                // ODE: dv/dt + c * v = 0
                // Solution: v(t) = v0 * exp(-c * t)
                // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
                // v2 = exp(-c * dt) * v1
                // Taylor expansion:
                // v2 = (1.0f - c * dt) * v1
                b._linearVelocity  *= Common.Math.Clamp(1.0f - step.Dt * b._linearDamping, 0.0f, 1.0f);
                b._angularVelocity *= Common.Math.Clamp(1.0f - step.Dt * b._angularDamping, 0.0f, 1.0f);

                // Check for large velocities.
#if TARGET_FLOAT32_IS_FIXED
                // Fixed point code written this way to prevent
                // overflows, float code is optimized for speed

                float vMagnitude = b._linearVelocity.Length();
                if (vMagnitude > Settings.MaxLinearVelocity)
                {
                    b._linearVelocity *= Settings.MaxLinearVelocity / vMagnitude;
                }
                b._angularVelocity = Vector2.Clamp(b._angularVelocity,
                                                   -Settings.MaxAngularVelocity, Settings.MaxAngularVelocity);
#else
                if (Vec2.Dot(b._linearVelocity, b._linearVelocity) > Settings.MaxLinearVelocitySquared)
                {
                    b._linearVelocity.Normalize();
                    b._linearVelocity *= Settings.MaxLinearVelocity;
                }

                if (b._angularVelocity * b._angularVelocity > Settings.MaxAngularVelocitySquared)
                {
                    if (b._angularVelocity < 0.0f)
                    {
                        b._angularVelocity = -Settings.MaxAngularVelocity;
                    }
                    else
                    {
                        b._angularVelocity = Settings.MaxAngularVelocity;
                    }
                }
#endif
            }

            ContactSolver contactSolver = new ContactSolver(step, _contacts, _contactCount);

            // Initialize velocity constraints.
            contactSolver.InitVelocityConstraints(step);

            for (int i = 0; i < _jointCount; ++i)
            {
                _joints[i].InitVelocityConstraints(step);
            }

            // Solve velocity constraints.
            for (int i = 0; i < step.VelocityIterations; ++i)
            {
                for (int j = 0; j < _jointCount; ++j)
                {
                    _joints[j].SolveVelocityConstraints(step);
                }
                contactSolver.SolveVelocityConstraints();
            }

            // Post-solve (store impulses for warm starting).
            contactSolver.FinalizeVelocityConstraints();

            // Integrate positions.
            for (int i = 0; i < _bodyCount; ++i)
            {
                Body b = _bodies[i];

                if (b.IsStatic())
                {
                    continue;
                }

                // Store positions for continuous collision.
                b._sweep.C0 = b._sweep.C;
                b._sweep.A0 = b._sweep.A;

                // Integrate
                b._sweep.C += step.Dt * b._linearVelocity;
                b._sweep.A += step.Dt * b._angularVelocity;

                // Compute new transform
                b.SynchronizeTransform();

                // Note: shapes are synchronized later.
            }

            // Iterate over constraints.
            for (int ii = 0; ii < step.PositionIterations; ++ii)
            {
                bool contactsOkay = contactSolver.SolvePositionConstraints(Settings.ContactBaumgarte);
                bool jointsOkay   = true;
                for (int i = 0; i < _jointCount; ++i)
                {
                    bool jointOkay = _joints[i].SolvePositionConstraints(/*Settings.ContactBaumgarte*/);
                    jointsOkay = jointsOkay && jointOkay;
                }

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

            Report(contactSolver._constraints);

            if (allowSleep)
            {
                float minSleepTime = Common.Settings.FLT_MAX;
#if !TARGET_FLOAT32_IS_FIXED
                float linTolSqr = Settings.LinearSleepTolerance * Settings.LinearSleepTolerance;
                float angTolSqr = Settings.AngularSleepTolerance * Settings.AngularSleepTolerance;
#endif

                for (int i = 0; i < _bodyCount; ++i)
                {
                    Body b = _bodies[i];
                    if (b._invMass == 0.0f)
                    {
                        continue;
                    }

                    if ((b._flags & Body.BodyFlags.AllowSleep) == 0)
                    {
                        b._sleepTime = 0.0f;
                        minSleepTime = 0.0f;
                    }

                    if ((b._flags & Body.BodyFlags.AllowSleep) == 0 ||
#if TARGET_FLOAT32_IS_FIXED
                        Common.Math.Abs(b._angularVelocity) > Settings.AngularSleepTolerance ||
                        Common.Math.Abs(b._linearVelocity.X) > Settings.LinearSleepTolerance ||
                        Common.Math.Abs(b._linearVelocity.Y) > Settings.LinearSleepTolerance)
#else
                        b._angularVelocity *b._angularVelocity > angTolSqr ||
                        Vec2.Dot(b._linearVelocity, b._linearVelocity) > linTolSqr)
#endif
                    {
                        b._sleepTime = 0.0f;
                        minSleepTime = 0.0f;
                    }
                    else
                    {
                        b._sleepTime += step.Dt;
                        minSleepTime  = Common.Math.Min(minSleepTime, b._sleepTime);
                    }
                }
Esempio n. 27
0
        public override float ComputeSubmergedArea(Vec2 normal, float offset, XForm xf, out Vec2 c)
        {
            //Transform plane into shape co-ordinates
            Vec2  normalL = Box2DX.Common.Math.MulT(xf.R, normal);
            float offsetL = offset - Vec2.Dot(normal, xf.Position);

            float[] depths    = new float[Common.Settings.MaxPolygonVertices];
            int     diveCount = 0;
            int     intoIndex = -1;
            int     outoIndex = -1;

            bool lastSubmerged = false;
            int  i;

            for (i = 0; i < _vertexCount; i++)
            {
                depths[i] = Vec2.Dot(normalL, _vertices[i]) - offsetL;
                bool isSubmerged = depths[i] < -Common.Settings.FLT_EPSILON;
                if (i > 0)
                {
                    if (isSubmerged)
                    {
                        if (!lastSubmerged)
                        {
                            intoIndex = i - 1;
                            diveCount++;
                        }
                    }
                    else
                    {
                        if (lastSubmerged)
                        {
                            outoIndex = i - 1;
                            diveCount++;
                        }
                    }
                }
                lastSubmerged = isSubmerged;
            }
            switch (diveCount)
            {
            case 0:
                if (lastSubmerged)
                {
                    //Completely submerged
                    MassData md;
                    ComputeMass(out md, 1f);
                    c = Common.Math.Mul(xf, md.Center);
                    return(md.Mass);
                }
                else
                {
                    //Completely dry
                    c = new Vec2();
                    return(0);
                }
                break;

            case 1:
                if (intoIndex == -1)
                {
                    intoIndex = _vertexCount - 1;
                }
                else
                {
                    outoIndex = _vertexCount - 1;
                }
                break;
            }
            int intoIndex2 = (intoIndex + 1) % _vertexCount;
            int outoIndex2 = (outoIndex + 1) % _vertexCount;

            float intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]);
            float outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]);

            Vec2 intoVec = new Vec2(_vertices[intoIndex].X * (1 - intoLambda) + _vertices[intoIndex2].X * intoLambda,
                                    _vertices[intoIndex].Y * (1 - intoLambda) + _vertices[intoIndex2].Y * intoLambda);
            Vec2 outoVec = new Vec2(_vertices[outoIndex].X * (1 - outoLambda) + _vertices[outoIndex2].X * outoLambda,
                                    _vertices[outoIndex].Y * (1 - outoLambda) + _vertices[outoIndex2].Y * outoLambda);

            //Initialize accumulator
            float area   = 0;
            Vec2  center = new Vec2(0, 0);
            Vec2  p2     = _vertices[intoIndex2];
            Vec2  p3;

            const float k_inv3 = 1.0f / 3.0f;

            //An awkward loop from intoIndex2+1 to outIndex2
            i = intoIndex2;
            while (i != outoIndex2)
            {
                i = (i + 1) % _vertexCount;
                if (i == outoIndex2)
                {
                    p3 = outoVec;
                }
                else
                {
                    p3 = _vertices[i];
                }
                //Add the triangle formed by intoVec,p2,p3
                {
                    Vec2 e1 = p2 - intoVec;
                    Vec2 e2 = p3 - intoVec;

                    float D = Vec2.Cross(e1, e2);

                    float triangleArea = 0.5f * D;

                    area += triangleArea;

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

            //Normalize and transform centroid
            center *= 1.0f / area;

            c = Common.Math.Mul(xf, center);

            return(area);
        }
Esempio n. 28
0
        public void InitializeVelocityConstraints()
        {
            //Console.WriteLine("Initializing velocity constraints for " + m_count + " contacts");
            // Warm start.
            for (int i = 0; i < Count; ++i)
            {
                ContactVelocityConstraint vc = VelocityConstraints[i];
                ContactPositionConstraint pc = PositionConstraints[i];

                float    radiusA  = pc.RadiusA;
                float    radiusB  = pc.RadiusB;
                Manifold manifold = Contacts[vc.ContactIndex].Manifold;

                int indexA = vc.IndexA;
                int indexB = vc.IndexB;

                float mA           = vc.InvMassA;
                float mB           = vc.InvMassB;
                float iA           = vc.InvIA;
                float iB           = vc.InvIB;
                Vec2  localCenterA = pc.LocalCenterA;
                Vec2  localCenterB = pc.LocalCenterB;

                Vec2  cA = Positions[indexA].C;
                float aA = Positions[indexA].A;
                Vec2  vA = Velocities[indexA].V;
                float wA = Velocities[indexA].W;

                Vec2  cB = Positions[indexB].C;
                float aB = Positions[indexB].A;
                Vec2  vB = Velocities[indexB].V;
                float wB = Velocities[indexB].W;

                Debug.Assert(manifold.PointCount > 0);

                xfA.Q.Set(aA);
                xfB.Q.Set(aB);
                Rot.MulToOutUnsafe(xfA.Q, localCenterA, temp);
                xfA.P.Set(cA).SubLocal(temp);
                Rot.MulToOutUnsafe(xfB.Q, localCenterB, temp);
                xfB.P.Set(cB).SubLocal(temp);

                worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB);

                vc.Normal.Set(worldManifold.Normal);

                int pointCount = vc.PointCount;
                for (int j = 0; j < pointCount; ++j)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp = vc.Points[j];

                    vcp.RA.Set(worldManifold.Points[j]).SubLocal(cA);
                    vcp.RB.Set(worldManifold.Points[j]).SubLocal(cB);

                    float rnA = Vec2.Cross(vcp.RA, vc.Normal);
                    float rnB = Vec2.Cross(vcp.RB, vc.Normal);

                    float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;

                    vcp.NormalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;

                    Vec2.CrossToOutUnsafe(vc.Normal, 1.0f, tangent);

                    float rtA = Vec2.Cross(vcp.RA, tangent);
                    float rtB = Vec2.Cross(vcp.RB, tangent);

                    float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;

                    vcp.TangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;

                    // Setup a velocity bias for restitution.
                    vcp.VelocityBias = 0.0f;
                    Vec2.CrossToOutUnsafe(wB, vcp.RB, temp1);
                    Vec2.CrossToOutUnsafe(wA, vcp.RA, temp2);
                    temp.Set(vB).AddLocal(temp1).SubLocal(vA).SubLocal(temp2);
                    float vRel = Vec2.Dot(vc.Normal, temp);
                    if (vRel < -Settings.VELOCITY_THRESHOLD)
                    {
                        vcp.VelocityBias = (-vc.Restitution) * vRel;
                    }
                }

                // If we have two points, then prepare the block solver.
                if (vc.PointCount == 2)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp1 = vc.Points[0];
                    ContactVelocityConstraint.VelocityConstraintPoint vcp2 = vc.Points[1];

                    float rn1A = Vec2.Cross(vcp1.RA, vc.Normal);
                    float rn1B = Vec2.Cross(vcp1.RB, vc.Normal);
                    float rn2A = Vec2.Cross(vcp2.RA, vc.Normal);
                    float rn2B = Vec2.Cross(vcp2.RB, vc.Normal);

                    float k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
                    float k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
                    float k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;
                    if (k11 * k11 < MAX_CONDITION_NUMBER * (k11 * k22 - k12 * k12))
                    {
                        // K is safe to invert.
                        vc.K.Ex.Set(k11, k12);
                        vc.K.Ey.Set(k12, k22);
                        vc.K.InvertToOut(vc.NormalMass);
                    }
                    else
                    {
                        // The constraints are redundant, just use one.
                        // TODO_ERIN use deepest?
                        vc.PointCount = 1;
                    }
                }
            }
        }
Esempio n. 29
0
 public float Compute(Vec2 x1, float a1, Vec2 x2, float a2)
 {
     return(Vec2.Dot(Linear1, x1) + Angular1 * a1 + Vec2.Dot(Linear2, x2) + Angular2 * a2);
 }
Esempio n. 30
0
 /// <summary>
 ///     Gets the support vertex using the specified d
 /// </summary>
 /// <param name="d">The </param>
 /// <returns>The vec</returns>
 public override Vec2 GetSupportVertex(Vec2 d)
 {
     return(Vec2.Dot(Vertex1, d) > Vec2.Dot(Vertex2, d) ? Vertex1 : Vertex2);
 }