internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float   wA = data.velocities[_indexA].w;
            Vector2 vB = data.velocities[_indexB].v;
            float   wB = data.velocities[_indexB].w;

            // Cdot = dot(u, v + cross(w, r))
            Vector2 vpA  = vA + MathUtils.Cross(wA, ref _rA);
            Vector2 vpB  = vB + MathUtils.Cross(wB, ref _rB);
            float   Cdot = Vector2.Dot(_u, vpB - vpA);

            float impulse = -_mass * (Cdot + _bias + _gamma * _impulse);

            _impulse += impulse;

            Vector2 P = impulse * _u;

            vA -= _invMassA * P;
            wA -= _invIA * MathUtils.Cross(ref _rA, ref P);
            vB += _invMassB * P;
            wB += _invIB * MathUtils.Cross(ref _rB, ref P);

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
        }
Exemple #2
0
        public static float DistanceBetweenPointAndLineSegment(ref Vector2 point, ref Vector2 start, ref Vector2 end)
        {
            if (start == end)
            {
                return(Vector2.Distance(point, start));
            }

            Vector2 v = end - start;
            Vector2 w = point - start;

            float c1 = Vector2.Dot(w, v);

            if (c1 <= 0)
            {
                return(Vector2.Distance(point, start));
            }

            float c2 = Vector2.Dot(v, v);

            if (c2 <= c1)
            {
                return(Vector2.Distance(point, end));
            }

            float   b           = c1 / c2;
            Vector2 pointOnLine = start + v * b;

            return(Vector2.Distance(point, pointOnLine));
        }
        internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float   wA = data.velocities[_indexA].w;
            Vector2 vB = data.velocities[_indexB].v;
            float   wB = data.velocities[_indexB].w;

            Vector2 vpA = vA + MathUtils.Cross(wA, ref _rA);
            Vector2 vpB = vB + MathUtils.Cross(wB, ref _rB);

            float Cdot    = -Vector2.Dot(_uA, vpA) - Ratio * Vector2.Dot(_uB, vpB);
            float impulse = -_mass * Cdot;

            _impulse += impulse;

            Vector2 PA = -impulse * _uA;
            Vector2 PB = -Ratio * impulse * _uB;

            vA += _invMassA * PA;
            wA += _invIA * MathUtils.Cross(ref _rA, ref PA);
            vB += _invMassB * PB;
            wB += _invIB * MathUtils.Cross(ref _rB, ref PB);

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
        }
        public override float ComputeSubmergedArea(ref Vector2 normal, float offset, ref Transform xf, out Vector2 sc)
        {
            sc = Vector2.Zero;

            Vector2 p = Transform.Multiply(ref _position, ref xf);
            float   l = -(Vector2.Dot(normal, p) - offset);

            if (l < -Radius + Settings.Epsilon)
            {
                //Completely dry
                return(0);
            }
            if (l > Radius)
            {
                //Completely wet
                sc = p;
                return(Constant.Pi * _2radius);
            }

            //Magic
            float l2   = l * l;
            float area = _2radius * (float)((Math.Asin(l / Radius) + Constant.Pi / 2) + l * Math.Sqrt(_2radius - l2));
            float com  = -2.0f / 3.0f * (float)Math.Pow(_2radius - l2, 1.5f) / area;

            sc.X = p.X + normal.X * com;
            sc.Y = p.Y + normal.Y * com;

            return(area);
        }
        public override bool TestPoint(ref Transform transform, ref Vector2 point)
        {
            Vector2 center = transform.p + Complex.Multiply(ref _position, ref transform.q);
            Vector2 d      = point - center;

            return(Vector2.Dot(d, d) <= _2radius);
        }
Exemple #6
0
        /// <summary>
        /// Tests if a point lies on a line segment.
        /// </summary>
        /// <remarks>Used by method <c>CalculateBeta()</c>.</remarks>
        private static bool PointOnLineSegment(Vector2 start, Vector2 end, Vector2 point)
        {
            Vector2 segment = end - start;

            return(MathUtils.Area(ref start, ref end, ref point) == 0f &&
                   Vector2.Dot(point - start, segment) >= 0f &&
                   Vector2.Dot(point - end, segment) <= 0f);
        }
            public static void Initialize(ContactPositionConstraint pc, ref Transform xfA, ref Transform xfB, int index, out Vector2 normal, out Vector2 point, out float separation)
            {
                Debug.Assert(pc.pointCount > 0);

                switch (pc.type)
                {
                case ManifoldType.Circles:
                {
                    Vector2 pointA = Transform.Multiply(ref pc.localPoint, ref xfA);
                    Vector2 pointB = Transform.Multiply(pc.localPoints[0], ref xfB);
                    normal = pointB - pointA;

                    // Handle zero normalization
                    if (normal != Vector2.Zero)
                    {
                        normal.Normalize();
                    }

                    point      = 0.5f * (pointA + pointB);
                    separation = Vector2.Dot(pointB - pointA, normal) - pc.radiusA - pc.radiusB;
                }
                break;

                case ManifoldType.FaceA:
                {
                    Complex.Multiply(ref pc.localNormal, ref xfA.q, out normal);
                    Vector2 planePoint = Transform.Multiply(ref pc.localPoint, ref xfA);

                    Vector2 clipPoint = Transform.Multiply(pc.localPoints[index], ref xfB);
                    separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.radiusA - pc.radiusB;
                    point      = clipPoint;
                }
                break;

                case ManifoldType.FaceB:
                {
                    Complex.Multiply(ref pc.localNormal, ref xfB.q, out normal);
                    Vector2 planePoint = Transform.Multiply(ref pc.localPoint, ref xfB);

                    Vector2 clipPoint = Transform.Multiply(pc.localPoints[index], ref xfA);
                    separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.radiusA - pc.radiusB;
                    point      = clipPoint;

                    // Ensure normal points from A to B
                    normal = -normal;
                }
                break;

                default:
                    normal     = Vector2.Zero;
                    point      = Vector2.Zero;
                    separation = 0;
                    break;
                }
            }
        protected override sealed void ComputeProperties()
        {
            float area = Constant.Pi * _2radius;

            MassData.Area     = area;
            MassData.Mass     = Density * area;
            MassData.Centroid = Position;

            // inertia about the local origin
            MassData.Inertia = MassData.Mass * (0.5f * _2radius + Vector2.Dot(Position, Position));
        }
Exemple #9
0
        private void ApplyViscosity(FluidParticle p, float timeStep)
        {
            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index >= neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                Vector2 direction;
                Vector2.Subtract(ref neighbour.Position, ref p.Position, out direction);

                if (direction.LengthSquared() < float.Epsilon)
                {
                    continue;
                }

                direction.Normalize();

                Vector2 deltaVelocity;
                Vector2.Subtract(ref p.Velocity, ref neighbour.Velocity, out deltaVelocity);

                float u;
                Vector2.Dot(ref deltaVelocity, ref direction, out u);

                if (u > 0.0f)
                {
                    q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                    float impulseFactor = 0.5f * timeStep * q * (u * (Definition.ViscositySigma + Definition.ViscosityBeta * u));

                    Vector2 impulse;

                    Vector2.Multiply(ref direction, -impulseFactor, out impulse);
                    p.ApplyImpulse(ref impulse);

                    Vector2.Multiply(ref direction, impulseFactor, out impulse);
                    neighbour.ApplyImpulse(ref impulse);
                }
            }
        }
        public static float Evaluate(int indexA, int indexB, float t)
        {
            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t);
            _sweepB.GetTransform(out xfB, t);

            switch (_type)
            {
            case SeparationFunctionType.Points:
            {
                Vector2 localPointA = _proxyA.Vertices[indexA];
                Vector2 localPointB = _proxyB.Vertices[indexB];

                Vector2 pointA     = Transform.Multiply(ref localPointA, ref xfA);
                Vector2 pointB     = Transform.Multiply(ref localPointB, ref xfB);
                float   separation = Vector2.Dot(pointB - pointA, _axis);

                return(separation);
            }

            case SeparationFunctionType.FaceA:
            {
                Vector2 normal = Complex.Multiply(ref _axis, ref xfA.q);
                Vector2 pointA = Transform.Multiply(ref _localPoint, ref xfA);

                Vector2 localPointB = _proxyB.Vertices[indexB];
                Vector2 pointB      = Transform.Multiply(ref localPointB, ref xfB);

                float separation = Vector2.Dot(pointB - pointA, normal);
                return(separation);
            }

            case SeparationFunctionType.FaceB:
            {
                Vector2 normal = Complex.Multiply(ref _axis, ref xfB.q);
                Vector2 pointB = Transform.Multiply(ref _localPoint, ref xfB);

                Vector2 localPointA = _proxyA.Vertices[indexA];
                Vector2 pointA      = Transform.Multiply(ref localPointA, ref xfA);

                float separation = Vector2.Dot(pointA - pointB, normal);
                return(separation);
            }

            default:
                Debug.Assert(false);
                return(0.0f);
            }
        }
Exemple #11
0
        internal override bool SolvePositionConstraints(ref SolverData data)
        {
            Vector2 cA = data.positions[_indexA].c;
            float   aA = data.positions[_indexA].a;
            Vector2 cB = data.positions[_indexB].c;
            float   aB = data.positions[_indexB].a;

            Complex qA = Complex.FromAngle(aA);
            Complex qB = Complex.FromAngle(aB);

            Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
            Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
            Vector2 d  = (cB - cA) + rB - rA;

            Vector2 ay = Complex.Multiply(ref _localYAxis, ref qA);

            float sAy = MathUtils.Cross(d + rA, ay);
            float sBy = MathUtils.Cross(ref rB, ref ay);

            float C = Vector2.Dot(d, ay);

            float k = _invMassA + _invMassB + _invIA * _sAy * _sAy + _invIB * _sBy * _sBy;

            float impulse;

            if (k != 0.0f)
            {
                impulse = -C / k;
            }
            else
            {
                impulse = 0.0f;
            }

            Vector2 P  = impulse * ay;
            float   LA = impulse * sAy;
            float   LB = impulse * sBy;

            cA -= _invMassA * P;
            aA -= _invIA * LA;
            cB += _invMassB * P;
            aB += _invIB * LB;

            data.positions[_indexA].c = cA;
            data.positions[_indexA].a = aA;
            data.positions[_indexB].c = cB;
            data.positions[_indexB].a = aB;

            return(Math.Abs(C) <= Settings.LinearSlop);
        }
        public override bool TestPoint(ref Transform transform, ref Vector2 point)
        {
            Vector2 pLocal = Complex.Divide(point - transform.p, ref transform.q);

            for (int i = 0; i < Vertices.Count; ++i)
            {
                float dot = Vector2.Dot(Normals[i], pLocal - Vertices[i]);
                if (dot > 0.0f)
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Get the supporting vertex in the given direction.
        /// </summary>
        /// <param name="direction">The direction.</param>
        /// <returns></returns>
        public Vector2 GetSupportVertex(Vector2 direction)
        {
            int bestIndex = 0;
            float bestValue = Vector2.Dot(Vertices[0], direction);
            for (int i = 1; i < Vertices.Count; ++i)
            {
                float value = Vector2.Dot(Vertices[i], direction);
                if (value > bestValue)
                {
                    bestIndex = i;
                    bestValue = value;
                }
            }

            return Vertices[bestIndex];
        }
Exemple #14
0
        private void ApplyViscosity(float deltaTime)
        {
            float u, q;

            for (int i = 0; i < Particles.Count; i++)
            {
                Particle particle = Particles[i];

                _tempParticles = Particles.GetNearby(particle);

                int len2 = _tempParticles.Count;
                if (len2 > MaxNeighbors)
                {
                    len2 = MaxNeighbors;
                }

                for (int j = 0; j < len2; j++)
                {
                    Particle tempParticle = _tempParticles[j];

                    Vector2.DistanceSquared(ref particle.Position, ref tempParticle.Position, out q);
                    if ((q < InfluenceRadiusSquared) && (q != 0))
                    {
                        q = (float)Math.Sqrt(q);
                        Vector2.Subtract(ref tempParticle.Position, ref particle.Position, out _rij);
                        Vector2.Divide(ref _rij, q, out _rij);

                        Vector2.Subtract(ref particle.Velocity, ref tempParticle.Velocity, out _tempVect);
                        Vector2.Dot(ref _tempVect, ref _rij, out u);
                        if (u <= 0.0f)
                        {
                            continue;
                        }

                        q /= InfluenceRadius;

                        float I = (deltaTime * (1 - q) * (ViscositySigma * u + ViscosityBeta * u * u));
                        Vector2.Multiply(ref _rij, (I * 0.5f), out _rij);
                        Vector2.Subtract(ref particle.Velocity, ref _rij, out _tempVect);
                        particle.Velocity     = _tempVect;
                        _tempVect             = tempParticle.Velocity;
                        _tempVect            += _rij;
                        tempParticle.Velocity = _tempVect;
                    }
                }
            }
        }
        public override bool RayCast(out RayCastOutput output, ref RayCastInput input, ref Transform transform, int childIndex)
        {
            // Collision Detection in Interactive 3D Environments by Gino van den Bergen
            // From Section 3.1.2
            // x = s + a * r
            // norm(x) = radius

            output = new RayCastOutput();

            Vector2 position = transform.p + Complex.Multiply(ref _position, ref transform.q);
            Vector2 s        = input.Point1 - position;
            float   b        = Vector2.Dot(s, s) - _2radius;

            // Solve quadratic equation.
            Vector2 r     = input.Point2 - input.Point1;
            float   c     = Vector2.Dot(s, r);
            float   rr    = Vector2.Dot(r, r);
            float   sigma = c * c - rr * b;

            // Check for negative discriminant and short segment.
            if (sigma < 0.0f || rr < Settings.Epsilon)
            {
                return(false);
            }

            // Find the point of intersection of the line with the circle.
            float a = -(c + (float)Math.Sqrt(sigma));

            // Is the intersection point on the segment?
            if (0.0f <= a && a <= input.MaxFraction * rr)
            {
                a /= rr;
                output.Fraction = a;

                //TODO: Check results here
                output.Normal = s + a * r;
                output.Normal.Normalize();
                return(true);
            }

            return(false);
        }
Exemple #16
0
        /// <summary>
        /// tests if ray intersects AABB
        /// </summary>
        /// <param name="aabb"></param>
        /// <returns></returns>
        public static bool RayCastAABB(AABB aabb, Vector2 p1, Vector2 p2)
        {
            AABB segmentAABB = new AABB();

            {
                Vector2.Min(ref p1, ref p2, out segmentAABB.LowerBound);
                Vector2.Max(ref p1, ref p2, out segmentAABB.UpperBound);
            }
            if (!AABB.TestOverlap(ref aabb, ref segmentAABB))
            {
                return(false);
            }

            Vector2 rayDir = p2 - p1;
            Vector2 rayPos = p1;

            Vector2 norm = new Vector2(-rayDir.Y, rayDir.X); //normal to ray

            if (norm.Length() == 0.0f)
            {
                return(true); //if ray is just a point, return true (iff point is within aabb, as tested earlier)
            }
            norm.Normalize();

            float dPos = Vector2.Dot(rayPos, norm);

            var   verts = aabb.Vertices;
            float d0    = Vector2.Dot(verts[0], norm) - dPos;

            for (int i = 1; i < 4; i++)
            {
                float d = Vector2.Dot(verts[i], norm) - dPos;
                if (Math.Sign(d) != Math.Sign(d0))
                {
                    //return true if the ray splits the vertices (ie: sign of dot products with normal are not all same)
                    return(true);
                }
            }

            return(false);
        }
        // Solve a line segment using barycentric coordinates.
        //
        // p = a1 * w1 + a2 * w2
        // a1 + a2 = 1
        //
        // The vector from the origin to the closest point on the line is
        // perpendicular to the line.
        // e12 = w2 - w1
        // dot(p, e) = 0
        // a1 * dot(w1, e) + a2 * dot(w2, e) = 0
        //
        // 2-by-2 linear system
        // [1      1     ][a1] = [1]
        // [w1.e12 w2.e12][a2] = [0]
        //
        // Define
        // d12_1 =  dot(w2, e12)
        // d12_2 = -dot(w1, e12)
        // d12 = d12_1 + d12_2
        //
        // Solution
        // a1 = d12_1 / d12
        // a2 = d12_2 / d12

        internal void Solve2()
        {
            Vector2 w1 = V[0].W;
            Vector2 w2 = V[1].W;
            Vector2 e12 = w2 - w1;

            // w1 region
            float d12_2 = -Vector2.Dot(w1, e12);
            if (d12_2 <= 0.0f)
            {
                // a2 <= 0, so we clamp it to 0
                SimplexVertex v0 = V[0];
                v0.A = 1.0f;
                V[0] = v0;
                Count = 1;
                return;
            }

            // w2 region
            float d12_1 = Vector2.Dot(w2, e12);
            if (d12_1 <= 0.0f)
            {
                // a1 <= 0, so we clamp it to 0
                SimplexVertex v1 = V[1];
                v1.A = 1.0f;
                V[1] = v1;
                Count = 1;
                V[0] = V[1];
                return;
            }

            // Must be in e12 region.
            float inv_d12 = 1.0f / (d12_1 + d12_2);
            SimplexVertex v0_2 = V[0];
            SimplexVertex v1_2 = V[1];
            v0_2.A = d12_1 * inv_d12;
            v1_2.A = d12_2 * inv_d12;
            V[0] = v0_2;
            V[1] = v1_2;
            Count = 2;
        }
Exemple #18
0
        public void ProjectParentVelocityOnLastMoveCollisionTangent(float minimumVectorLengthSquared)
        {
#if FRB_MDX
            if (LastMoveCollisionReposition.LengthSq() > minimumVectorLengthSquared &&
#else
            if (LastMoveCollisionReposition.LengthSquared() > minimumVectorLengthSquared &&
#endif
                Vector2.Dot(
                    new Vector2(TopParent.Velocity.X, TopParent.Velocity.Y), LastMoveCollisionReposition) < 0)
            {
                Vector2 collisionAdjustmentNormalized = LastMoveCollisionReposition;
                collisionAdjustmentNormalized.Normalize();
                float temporaryFloat = collisionAdjustmentNormalized.X;
                collisionAdjustmentNormalized.X = -collisionAdjustmentNormalized.Y;
                collisionAdjustmentNormalized.Y = temporaryFloat;

                float length = Vector2.Dot(
                    new Vector2(TopParent.Velocity.X, TopParent.Velocity.Y), collisionAdjustmentNormalized);
                TopParent.Velocity.X = collisionAdjustmentNormalized.X * length;
                TopParent.Velocity.Y = collisionAdjustmentNormalized.Y * length;
            }
        }
Exemple #19
0
        internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float   wA = data.velocities[_indexA].w;
            Vector2 vB = data.velocities[_indexB].v;
            float   wB = data.velocities[_indexB].w;

            // Cdot = dot(u, v + cross(w, r))
            Vector2 vpA  = vA + MathUtils.Cross(wA, ref _rA);
            Vector2 vpB  = vB + MathUtils.Cross(wB, ref _rB);
            float   C    = _length - MaxLength;
            float   Cdot = Vector2.Dot(_u, vpB - vpA);

            // Predictive constraint.
            if (C < 0.0f)
            {
                Cdot += data.step.inv_dt * C;
            }

            float impulse    = -_mass * Cdot;
            float oldImpulse = _impulse;

            _impulse = Math.Min(0.0f, _impulse + impulse);
            impulse  = _impulse - oldImpulse;

            Vector2 P = impulse * _u;

            vA -= _invMassA * P;
            wA -= _invIA * MathUtils.Cross(ref _rA, ref P);
            vB += _invMassB * P;
            wB += _invIB * MathUtils.Cross(ref _rB, ref P);

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
        }
        internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float   wA = data.velocities[_indexA].w;
            Vector2 vB = data.velocities[_indexB].v;
            float   wB = data.velocities[_indexB].w;
            Vector2 vC = data.velocities[_indexC].v;
            float   wC = data.velocities[_indexC].w;
            Vector2 vD = data.velocities[_indexD].v;
            float   wD = data.velocities[_indexD].w;

            float Cdot = Vector2.Dot(_JvAC, vA - vC) + Vector2.Dot(_JvBD, vB - vD);

            Cdot += (_JwA * wA - _JwC * wC) + (_JwB * wB - _JwD * wD);

            float impulse = -_mass * Cdot;

            _impulse += impulse;

            vA += (_mA * impulse) * _JvAC;
            wA += _iA * impulse * _JwA;
            vB += (_mB * impulse) * _JvBD;
            wB += _iB * impulse * _JwB;
            vC -= (_mC * impulse) * _JvAC;
            wC -= _iC * impulse * _JwC;
            vD -= (_mD * impulse) * _JvBD;
            wD -= _iD * impulse * _JwD;

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
            data.velocities[_indexC].v = vC;
            data.velocities[_indexC].w = wC;
            data.velocities[_indexD].v = vD;
            data.velocities[_indexD].w = wD;
        }
Exemple #21
0
        internal void Solve(ref TimeStep step, ref Vector2 gravity)
        {
            float h = step.dt;

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

                Vector2 c = b._sweep.C;
                float   a = b._sweep.A;
                Vector2 v = b._linearVelocity;
                float   w = b._angularVelocity;

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

                if (b.BodyType == BodyType.Dynamic)
                {
                    // Integrate velocities.

                    // FPE: Only apply gravity if the body wants it.
                    if (b.IgnoreGravity)
                    {
                        v += h * (b._invMass * b._force);
                    }
                    else
                    {
                        v += h * (gravity + b._invMass * b._force);
                    }

                    w += h * b._invI * b._torque;

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

                _positions[i].c  = c;
                _positions[i].a  = a;
                _velocities[i].v = v;
                _velocities[i].w = w;
            }

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

            solverData.step       = step;
            solverData.positions  = _positions;
            solverData.velocities = _velocities;
            solverData.locks      = _locks;

            _contactSolver.Reset(ref step, ContactCount, _contacts, _positions, _velocities,
                                 _locks, _contactManager.VelocityConstraintsMultithreadThreshold, _contactManager.PositionConstraintsMultithreadThreshold);
            _contactSolver.InitializeVelocityConstraints();

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

            if (Settings.EnableDiagnostics)
            {
                _watch.Start();
            }

            for (int i = 0; i < JointCount; ++i)
            {
                if (_joints[i].Enabled)
                {
                    _joints[i].InitVelocityConstraints(ref solverData);
                }
            }

            if (Settings.EnableDiagnostics)
            {
                _watch.Stop();
            }

            // Solve velocity constraints.
            for (int i = 0; i < step.velocityIterations; ++i)
            {
                for (int j = 0; j < JointCount; ++j)
                {
                    Joint joint = _joints[j];

                    if (!joint.Enabled)
                    {
                        continue;
                    }

                    if (Settings.EnableDiagnostics)
                    {
                        _watch.Start();
                    }

                    joint.SolveVelocityConstraints(ref solverData);
                    joint.Validate(step.inv_dt);

                    if (Settings.EnableDiagnostics)
                    {
                        _watch.Stop();
                    }
                }

                _contactSolver.SolveVelocityConstraints();
            }

            // Store impulses for warm starting.
            _contactSolver.StoreImpulses();

            // Integrate positions
            for (int i = 0; i < BodyCount; ++i)
            {
                Vector2 c = _positions[i].c;
                float   a = _positions[i].a;
                Vector2 v = _velocities[i].v;
                float   w = _velocities[i].w;

                // Check for large velocities
                Vector2 translation = h * v;
                if (Vector2.Dot(translation, translation) > Settings.MaxTranslationSquared)
                {
                    float ratio = Settings.MaxTranslation / translation.Length();
                    v *= ratio;
                }

                float rotation = h * w;
                if (rotation * rotation > Settings.MaxRotationSquared)
                {
                    float ratio = Settings.MaxRotation / Math.Abs(rotation);
                    w *= ratio;
                }

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

                _positions[i].c  = c;
                _positions[i].a  = a;
                _velocities[i].v = v;
                _velocities[i].w = w;
            }


            // Solve position constraints
            bool positionSolved = false;

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

                bool jointsOkay = true;
                for (int j = 0; j < JointCount; ++j)
                {
                    Joint joint = _joints[j];

                    if (!joint.Enabled)
                    {
                        continue;
                    }

                    if (Settings.EnableDiagnostics)
                    {
                        _watch.Start();
                    }

                    bool jointOkay = joint.SolvePositionConstraints(ref solverData);

                    if (Settings.EnableDiagnostics)
                    {
                        _watch.Stop();
                    }

                    jointsOkay = jointsOkay && jointOkay;
                }

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

            if (Settings.EnableDiagnostics)
            {
                JointUpdateTime = TimeSpan.FromTicks(_watch.ElapsedTicks);
                _watch.Reset();
            }

            // Copy state buffers back to the bodies
            for (int i = 0; i < BodyCount; ++i)
            {
                Body body = Bodies[i];
                body._sweep.C         = _positions[i].c;
                body._sweep.A         = _positions[i].a;
                body._linearVelocity  = _velocities[i].v;
                body._angularVelocity = _velocities[i].w;
                body.SynchronizeTransform();
            }

            Report(_contactSolver._velocityConstraints);

            if (Settings.AllowSleep)
            {
                float minSleepTime = Settings.MaxFloat;

                for (int i = 0; i < BodyCount; ++i)
                {
                    Body b = Bodies[i];

                    if (b.BodyType == BodyType.Static)
                    {
                        continue;
                    }

                    if (!b.SleepingAllowed || b._angularVelocity * b._angularVelocity > AngTolSqr || Vector2.Dot(b._linearVelocity, b._linearVelocity) > LinTolSqr)
                    {
                        b._sleepTime = 0.0f;
                        minSleepTime = 0.0f;
                    }
                    else
                    {
                        b._sleepTime += h;
                        minSleepTime  = Math.Min(minSleepTime, b._sleepTime);
                    }
                }

                if (minSleepTime >= Settings.TimeToSleep && positionSolved)
                {
                    for (int i = 0; i < BodyCount; ++i)
                    {
                        Body b = Bodies[i];
                        b.Awake = false;
                    }
                }
            }
        }
Exemple #22
0
        /// <summary>
        /// This resets the mass properties to the sum of the mass properties of the fixtures.
        /// This normally does not need to be called unless you called SetMassData to override
        /// the mass and you later want to reset the mass.
        /// </summary>
        public void ResetMassData()
        {
            // Compute mass data from shapes. Each shape has its own density.
            _mass              = 0.0f;
            _invMass           = 0.0f;
            _inertia           = 0.0f;
            _invI              = 0.0f;
            _sweep.LocalCenter = Vector2.Zero;

            // Kinematic bodies have zero mass.
            if (BodyType == BodyType.Kinematic)
            {
                _sweep.C0 = _xf.p;
                _sweep.C  = _xf.p;
                _sweep.A0 = _sweep.A;
                return;
            }

            Debug.Assert(BodyType == BodyType.Dynamic || BodyType == BodyType.Static);

            // Accumulate mass over all fixtures.
            Vector2 localCenter = Vector2.Zero;

            foreach (Fixture f in FixtureList)
            {
                if (f.Shape._density == 0)
                {
                    continue;
                }

                MassData massData = f.Shape.MassData;
                _mass       += massData.Mass;
                localCenter += massData.Mass * massData.Centroid;
                _inertia    += massData.Inertia;
            }

            //FPE: Static bodies only have mass, they don't have other properties. A little hacky tho...
            if (BodyType == BodyType.Static)
            {
                _sweep.C0 = _sweep.C = _xf.p;
                return;
            }

            // Compute center of mass.
            if (_mass > 0.0f)
            {
                _invMass     = 1.0f / _mass;
                localCenter *= _invMass;
            }
            else
            {
                // Force all dynamic bodies to have a positive mass.
                _mass    = 1.0f;
                _invMass = 1.0f;
            }

            if (_inertia > 0.0f && !_fixedRotation)
            {
                // Center the inertia about the center of mass.
                _inertia -= _mass * Vector2.Dot(localCenter, localCenter);

                Debug.Assert(_inertia > 0.0f);
                _invI = 1.0f / _inertia;
            }
            else
            {
                _inertia = 0.0f;
                _invI    = 0.0f;
            }

            // Move center of mass.
            Vector2 oldCenter = _sweep.C;

            _sweep.LocalCenter = localCenter;
            _sweep.C0          = _sweep.C = Transform.Multiply(ref _sweep.LocalCenter, ref _xf);

            // Update center of mass velocity.
            Vector2 a = _sweep.C - oldCenter;

            _linearVelocity += new Vector2(-_angularVelocity * a.Y, _angularVelocity * a.X);
        }
Exemple #23
0
        internal override bool SolvePositionConstraints(ref SolverData data)
        {
            Vector2 cA = data.positions[_indexA].c;
            float   aA = data.positions[_indexA].a;
            Vector2 cB = data.positions[_indexB].c;
            float   aB = data.positions[_indexB].a;

            Complex qA = Complex.FromAngle(aA);
            Complex qB = Complex.FromAngle(aB);

            float mA = _invMassA, mB = _invMassB;
            float iA = _invIA, iB = _invIB;

            // Compute fresh Jacobians
            Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
            Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
            Vector2 d  = cB + rB - cA - rA;

            Vector2 axis = Complex.Multiply(ref _localXAxis, ref qA);
            float   a1   = MathUtils.Cross(d + rA, axis);
            float   a2   = MathUtils.Cross(ref rB, ref axis);
            Vector2 perp = Complex.Multiply(ref _localYAxisA, ref qA);

            float s1 = MathUtils.Cross(d + rA, perp);
            float s2 = MathUtils.Cross(ref rB, ref perp);

            Vector3 impulse;
            Vector2 C1 = new Vector2();

            C1.X = Vector2.Dot(perp, d);
            C1.Y = aB - aA - ReferenceAngle;

            float linearError  = Math.Abs(C1.X);
            float angularError = Math.Abs(C1.Y);

            bool  active = false;
            float C2     = 0.0f;

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

            if (active)
            {
                float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
                float k12 = iA * s1 + iB * s2;
                float k13 = iA * s1 * a1 + iB * s2 * a2;
                float k22 = iA + iB;
                if (k22 == 0.0f)
                {
                    // For fixed rotation
                    k22 = 1.0f;
                }
                float k23 = iA * a1 + iB * a2;
                float k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;

                Mat33 K = new Mat33();
                K.ex = new Vector3(k11, k12, k13);
                K.ey = new Vector3(k12, k22, k23);
                K.ez = new Vector3(k13, k23, k33);

                Vector3 C = new Vector3();
                C.X = C1.X;
                C.Y = C1.Y;
                C.Z = C2;

                impulse = K.Solve33(-C);
            }
            else
            {
                float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
                float k12 = iA * s1 + iB * s2;
                float k22 = iA + iB;
                if (k22 == 0.0f)
                {
                    k22 = 1.0f;
                }

                Mat22 K = new Mat22();
                K.ex = new Vector2(k11, k12);
                K.ey = new Vector2(k12, k22);

                Vector2 impulse1 = K.Solve(-C1);
                impulse   = new Vector3();
                impulse.X = impulse1.X;
                impulse.Y = impulse1.Y;
                impulse.Z = 0.0f;
            }

            Vector2 P  = impulse.X * perp + impulse.Z * axis;
            float   LA = impulse.X * s1 + impulse.Y + impulse.Z * a1;
            float   LB = impulse.X * s2 + impulse.Y + impulse.Z * a2;

            cA -= mA * P;
            aA -= iA * LA;
            cB += mB * P;
            aB += iB * LB;

            data.positions[_indexA].c = cA;
            data.positions[_indexA].a = aA;
            data.positions[_indexB].c = cB;
            data.positions[_indexB].a = aB;

            return(linearError <= Settings.LinearSlop && angularError <= Settings.AngularSlop);
        }
Exemple #24
0
        internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float   wA = data.velocities[_indexA].w;
            Vector2 vB = data.velocities[_indexB].v;
            float   wB = data.velocities[_indexB].w;

            float mA = _invMassA, mB = _invMassB;
            float iA = _invIA, iB = _invIB;

            // Solve linear motor constraint.
            if (_enableMotor && _limitState != LimitState.Equal)
            {
                float Cdot       = Vector2.Dot(_axis, vB - vA) + _a2 * wB - _a1 * wA;
                float impulse    = _motorMass * (_motorSpeed - Cdot);
                float oldImpulse = MotorImpulse;
                float maxImpulse = data.step.dt * _maxMotorForce;
                MotorImpulse = MathUtils.Clamp(MotorImpulse + impulse, -maxImpulse, maxImpulse);
                impulse      = MotorImpulse - oldImpulse;

                Vector2 P  = impulse * _axis;
                float   LA = impulse * _a1;
                float   LB = impulse * _a2;

                vA -= mA * P;
                wA -= iA * LA;

                vB += mB * P;
                wB += iB * LB;
            }

            Vector2 Cdot1 = new Vector2();

            Cdot1.X = Vector2.Dot(_perp, vB - vA) + _s2 * wB - _s1 * wA;
            Cdot1.Y = wB - wA;

            if (_enableLimit && _limitState != LimitState.Inactive)
            {
                // Solve prismatic and limit constraint in block form.
                float Cdot2;
                Cdot2 = Vector2.Dot(_axis, vB - vA) + _a2 * wB - _a1 * wA;
                Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);

                Vector3 f1 = _impulse;
                Vector3 df = _K.Solve33(-Cdot);
                _impulse += df;

                if (_limitState == LimitState.AtLower)
                {
                    _impulse.Z = Math.Max(_impulse.Z, 0.0f);
                }
                else if (_limitState == LimitState.AtUpper)
                {
                    _impulse.Z = Math.Min(_impulse.Z, 0.0f);
                }

                // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
                Vector2 b   = -Cdot1 - (_impulse.Z - f1.Z) * new Vector2(_K.ez.X, _K.ez.Y);
                Vector2 f2r = _K.Solve22(b) + new Vector2(f1.X, f1.Y);
                _impulse.X = f2r.X;
                _impulse.Y = f2r.Y;

                df = _impulse - f1;

                Vector2 P  = df.X * _perp + df.Z * _axis;
                float   LA = df.X * _s1 + df.Y + df.Z * _a1;
                float   LB = df.X * _s2 + df.Y + df.Z * _a2;

                vA -= mA * P;
                wA -= iA * LA;

                vB += mB * P;
                wB += iB * LB;
            }
            else
            {
                // Limit is inactive, just solve the prismatic constraint in block form.
                Vector2 df = _K.Solve22(-Cdot1);
                _impulse.X += df.X;
                _impulse.Y += df.Y;

                Vector2 P  = df.X * _perp;
                float   LA = df.X * _s1 + df.Y;
                float   LB = df.X * _s2 + df.Y;

                vA -= mA * P;
                wA -= iA * LA;

                vB += mB * P;
                wB += iB * LB;
            }

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
        }
        private void SolveVelocityConstraints(int start, int end)
        {
            for (int i = start; i < end; ++i)
            {
                ContactVelocityConstraint vc = _velocityConstraints[i];

#if NET40 || NET45 || NETSTANDARD2_0 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
                // find lower order item
                int orderedIndexA = vc.indexA;
                int orderedIndexB = vc.indexB;
                if (orderedIndexB < orderedIndexA)
                {
                    orderedIndexA = vc.indexB;
                    orderedIndexB = vc.indexA;
                }

                for (; ;)
                {
                    if (Interlocked.CompareExchange(ref _locks[orderedIndexA], 1, 0) == 0)
                    {
                        if (Interlocked.CompareExchange(ref _locks[orderedIndexB], 1, 0) == 0)
                        {
                            break;
                        }
                        System.Threading.Interlocked.Exchange(ref _locks[orderedIndexA], 0);
                    }
#if NET40 || NET45 || NETSTANDARD2_0
                    Thread.Sleep(0);
#endif
                }
#endif

                int   indexA     = vc.indexA;
                int   indexB     = vc.indexB;
                float mA         = vc.invMassA;
                float iA         = vc.invIA;
                float mB         = vc.invMassB;
                float iB         = vc.invIB;
                int   pointCount = vc.pointCount;

                Vector2 vA = _velocities[indexA].v;
                float   wA = _velocities[indexA].w;
                Vector2 vB = _velocities[indexB].v;
                float   wB = _velocities[indexB].w;

                Vector2 normal   = vc.normal;
                Vector2 tangent  = MathUtils.Rot270(ref normal);
                float   friction = vc.friction;

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

                // Solve tangent constraints first because non-penetration is more important
                // than friction.
                for (int j = 0; j < pointCount; ++j)
                {
                    VelocityConstraintPoint vcp = vc.points[j];

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

                    // Compute tangent force
                    float vt     = Vector2.Dot(dv, tangent) - vc.tangentSpeed;
                    float lambda = vcp.tangentMass * (-vt);

                    // b2Clamp 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
                    Vector2 P = lambda * tangent;

                    vA -= mA * P;
                    wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);

                    vB += mB * P;
                    wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
                }

                // Solve normal constraints
                if (vc.pointCount == 1)
                {
                    VelocityConstraintPoint vcp = vc.points[0];

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

                    // Compute normal impulse
                    float vn     = Vector2.Dot(dv, normal);
                    float lambda = -vcp.normalMass * (vn - vcp.velocityBias);

                    // b2Clamp the accumulated impulse
                    float newImpulse = Math.Max(vcp.normalImpulse + lambda, 0.0f);
                    lambda            = newImpulse - vcp.normalImpulse;
                    vcp.normalImpulse = newImpulse;

                    // Apply contact impulse
                    Vector2 P = lambda * normal;
                    vA -= mA * P;
                    wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);

                    vB += mB * P;
                    wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
                }
                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 = vn0 - 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;

                    VelocityConstraintPoint cp1 = vc.points[0];
                    VelocityConstraintPoint cp2 = vc.points[1];

                    Vector2 a = new Vector2(cp1.normalImpulse, cp2.normalImpulse);
                    Debug.Assert(a.X >= 0.0f && a.Y >= 0.0f);

                    // Relative velocity at contact
                    Vector2 dv1 = vB + MathUtils.Cross(wB, ref cp1.rB) - vA - MathUtils.Cross(wA, ref cp1.rA);
                    Vector2 dv2 = vB + MathUtils.Cross(wB, ref cp2.rB) - vA - MathUtils.Cross(wA, ref cp2.rA);

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

                    Vector2 b = new Vector2();
                    b.X = vn1 - cp1.velocityBias;
                    b.Y = vn2 - cp2.velocityBias;

                    // Compute b'
                    b -= MathUtils.Mul(ref vc.K, ref a);

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

                    for (; ;)
                    {
                        //
                        // Case 1: vn = 0
                        //
                        // 0 = A * x + b'
                        //
                        // Solve for x:
                        //
                        // x = - inv(A) * b'
                        //
                        Vector2 x = -MathUtils.Mul(ref vc.normalMass, ref b);

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

                            // Apply incremental impulse
                            Vector2 P1 = d.X * normal;
                            Vector2 P2 = d.Y * normal;
                            vA -= mA * (P1 + P2);
                            wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));

                            vB += mB * (P1 + P2);
                            wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));

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

#if B2_DEBUG_SOLVER
                            // Postconditions
                            dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);
                            dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);

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

                            b2Assert(b2Abs(vn1 - cp1.velocityBias) < k_errorTol);
                            b2Assert(b2Abs(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 = vc.K.ex.Y * x.X + b.Y;

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

                            // Apply incremental impulse
                            Vector2 P1 = d.X * normal;
                            Vector2 P2 = d.Y * normal;
                            vA -= mA * (P1 + P2);
                            wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));

                            vB += mB * (P1 + P2);
                            wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));

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

#if B2_DEBUG_SOLVER
                            // Postconditions
                            dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);

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

                            b2Assert(b2Abs(vn1 - cp1.velocityBias) < k_errorTol);
#endif
                            break;
                        }


                        //
                        // Case 3: vn2 = 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 = vc.K.ey.X * x.Y + b.X;
                        vn2 = 0.0f;

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

                            // Apply incremental impulse
                            Vector2 P1 = d.X * normal;
                            Vector2 P2 = d.Y * normal;
                            vA -= mA * (P1 + P2);
                            wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));

                            vB += mB * (P1 + P2);
                            wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));

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

#if B2_DEBUG_SOLVER
                            // Postconditions
                            dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);

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

                            b2Assert(b2Abs(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
                            Vector2 d = x - a;

                            // Apply incremental impulse
                            Vector2 P1 = d.X * normal;
                            Vector2 P2 = d.Y * normal;
                            vA -= mA * (P1 + P2);
                            wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));

                            vB += mB * (P1 + P2);
                            wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref 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;
                    }
                }

                _velocities[indexA].v = vA;
                _velocities[indexA].w = wA;
                _velocities[indexB].v = vB;
                _velocities[indexB].w = wB;

#if NET40 || NET45 || NETSTANDARD2_0 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
                System.Threading.Interlocked.Exchange(ref _locks[orderedIndexB], 0);
                System.Threading.Interlocked.Exchange(ref _locks[orderedIndexA], 0);
#endif
            }
        }
Exemple #26
0
 public static float Dot(Vector2 a, Vector2 b)
 {
     return(MonoGameVector2.Dot(a.MonoGameVector, b.MonoGameVector));
 }
Exemple #27
0
 public static float Dot(Vector2 v1, Vector2 v2)
 {
     return(Vector.Dot(v1, v2));
 }
Exemple #28
0
        internal void SolveTOI(ref TimeStep subStep, int toiIndexA, int toiIndexB)
        {
            Debug.Assert(toiIndexA < BodyCount);
            Debug.Assert(toiIndexB < BodyCount);

            // Initialize the body state.
            for (int i = 0; i < BodyCount; ++i)
            {
                Body b = Bodies[i];
                _positions[i].c  = b._sweep.C;
                _positions[i].a  = b._sweep.A;
                _velocities[i].v = b._linearVelocity;
                _velocities[i].w = b._angularVelocity;
            }

            _contactSolver.Reset(ref subStep, ContactCount, _contacts, _positions, _velocities,
                                 _locks, _contactManager.VelocityConstraintsMultithreadThreshold, _contactManager.PositionConstraintsMultithreadThreshold);

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

            // Leap of faith to new safe state.
            Bodies[toiIndexA]._sweep.C0 = _positions[toiIndexA].c;
            Bodies[toiIndexA]._sweep.A0 = _positions[toiIndexA].a;
            Bodies[toiIndexB]._sweep.C0 = _positions[toiIndexB].c;
            Bodies[toiIndexB]._sweep.A0 = _positions[toiIndexB].a;

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

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

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

            float h = subStep.dt;

            // Integrate positions.
            for (int i = 0; i < BodyCount; ++i)
            {
                Vector2 c = _positions[i].c;
                float   a = _positions[i].a;
                Vector2 v = _velocities[i].v;
                float   w = _velocities[i].w;

                // Check for large velocities
                Vector2 translation = h * v;
                if (Vector2.Dot(translation, translation) > Settings.MaxTranslationSquared)
                {
                    float ratio = Settings.MaxTranslation / translation.Length();
                    v *= ratio;
                }

                float rotation = h * w;
                if (rotation * rotation > Settings.MaxRotationSquared)
                {
                    float ratio = Settings.MaxRotation / Math.Abs(rotation);
                    w *= ratio;
                }

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

                _positions[i].c  = c;
                _positions[i].a  = a;
                _velocities[i].v = v;
                _velocities[i].w = w;

                // Sync bodies
                Body body = Bodies[i];
                body._sweep.C         = c;
                body._sweep.A         = a;
                body._linearVelocity  = v;
                body._angularVelocity = w;
                body.SynchronizeTransform();
            }

            Report(_contactSolver._velocityConstraints);
        }
        public override bool RayCast(out RayCastOutput output, ref RayCastInput input, ref Transform transform, int childIndex)
        {
            // p = p1 + t * d
            // v = v1 + s * e
            // p1 + t * d = v1 + s * e
            // s * e - t * d = p1 - v1

            output = new RayCastOutput();

            // Put the ray into the edge's frame of reference.
            Vector2 p1 = Complex.Divide(input.Point1 - transform.p, ref transform.q);
            Vector2 p2 = Complex.Divide(input.Point2 - transform.p, ref transform.q);
            Vector2 d  = p2 - p1;

            Vector2 v1     = _vertex1;
            Vector2 v2     = _vertex2;
            Vector2 e      = v2 - v1;
            Vector2 normal = new Vector2(e.Y, -e.X); //TODO: Could possibly cache the normal.

            normal.Normalize();

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

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

            float t = numerator / denominator;

            if (t < 0.0f || input.MaxFraction < t)
            {
                return(false);
            }

            Vector2 q = p1 + t * d;

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

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

            float s = Vector2.Dot(q - v1, r) / rr;

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

            output.Fraction = t;
            if (numerator > 0.0f)
            {
                output.Normal = -normal;
            }
            else
            {
                output.Normal = normal;
            }
            return(true);
        }
Exemple #30
0
        internal override void InitVelocityConstraints(ref SolverData data)
        {
            _indexA       = BodyA.IslandIndex;
            _indexB       = BodyB.IslandIndex;
            _localCenterA = BodyA._sweep.LocalCenter;
            _localCenterB = BodyB._sweep.LocalCenter;
            _invMassA     = BodyA._invMass;
            _invMassB     = BodyB._invMass;
            _invIA        = BodyA._invI;
            _invIB        = BodyB._invI;

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

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

            Complex qA = Complex.FromAngle(aA);
            Complex qB = Complex.FromAngle(aB);

            // Compute the effective masses.
            Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
            Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
            Vector2 d  = (cB - cA) + rB - rA;

            float mA = _invMassA, mB = _invMassB;
            float iA = _invIA, iB = _invIB;

            // Compute motor Jacobian and effective mass.
            {
                _axis = Complex.Multiply(ref _localXAxis, ref qA);
                _a1   = MathUtils.Cross(d + rA, _axis);
                _a2   = MathUtils.Cross(ref rB, ref _axis);

                _motorMass = mA + mB + iA * _a1 * _a1 + iB * _a2 * _a2;
                if (_motorMass > 0.0f)
                {
                    _motorMass = 1.0f / _motorMass;
                }
            }

            // Prismatic constraint.
            {
                _perp = Complex.Multiply(ref _localYAxisA, ref qA);

                _s1 = MathUtils.Cross(d + rA, _perp);
                _s2 = MathUtils.Cross(ref rB, ref _perp);

                float k11 = mA + mB + iA * _s1 * _s1 + iB * _s2 * _s2;
                float k12 = iA * _s1 + iB * _s2;
                float k13 = iA * _s1 * _a1 + iB * _s2 * _a2;
                float k22 = iA + iB;
                if (k22 == 0.0f)
                {
                    // For bodies with fixed rotation.
                    k22 = 1.0f;
                }
                float k23 = iA * _a1 + iB * _a2;
                float k33 = mA + mB + iA * _a1 * _a1 + iB * _a2 * _a2;

                _K.ex = new Vector3(k11, k12, k13);
                _K.ey = new Vector3(k12, k22, k23);
                _K.ez = new Vector3(k13, k23, k33);
            }

            // Compute motor and limit terms.
            if (_enableLimit)
            {
                float jointTranslation = Vector2.Dot(_axis, d);
                if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
                {
                    _limitState = LimitState.Equal;
                }
                else if (jointTranslation <= _lowerTranslation)
                {
                    if (_limitState != LimitState.AtLower)
                    {
                        _limitState = LimitState.AtLower;
                        _impulse.Z  = 0.0f;
                    }
                }
                else if (jointTranslation >= _upperTranslation)
                {
                    if (_limitState != LimitState.AtUpper)
                    {
                        _limitState = LimitState.AtUpper;
                        _impulse.Z  = 0.0f;
                    }
                }
                else
                {
                    _limitState = LimitState.Inactive;
                    _impulse.Z  = 0.0f;
                }
            }
            else
            {
                _limitState = LimitState.Inactive;
                _impulse.Z  = 0.0f;
            }

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

            if (data.step.warmStarting)
            {
                // Account for variable time step.
                _impulse     *= data.step.dtRatio;
                MotorImpulse *= data.step.dtRatio;

                Vector2 P  = _impulse.X * _perp + (MotorImpulse + _impulse.Z) * _axis;
                float   LA = _impulse.X * _s1 + _impulse.Y + (MotorImpulse + _impulse.Z) * _a1;
                float   LB = _impulse.X * _s2 + _impulse.Y + (MotorImpulse + _impulse.Z) * _a2;

                vA -= mA * P;
                wA -= iA * LA;

                vB += mB * P;
                wB += iB * LB;
            }
            else
            {
                _impulse     = Vector3.Zero;
                MotorImpulse = 0.0f;
            }

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
        }