/// <summary>
        /// Applies the corrective impulses required by the constraint.
        /// </summary>
        public override Fix64 SolveIteration()
        {
            Vector3 velocityDifference;

            Vector3.Subtract(ref connectionB.angularVelocity, ref connectionA.angularVelocity, out velocityDifference);
            Vector3 softnessVector;

            Vector3.Multiply(ref accumulatedImpulse, softness, out softnessVector);

            Vector3 lambda;

            Vector3.Add(ref velocityDifference, ref biasVelocity, out lambda);
            Vector3.Subtract(ref lambda, ref softnessVector, out lambda);
            Matrix3x3.Transform(ref lambda, ref effectiveMassMatrix, out lambda);

            Vector3.Add(ref lambda, ref accumulatedImpulse, out accumulatedImpulse);
            if (connectionA.isDynamic)
            {
                connectionA.ApplyAngularImpulse(ref lambda);
            }
            if (connectionB.isDynamic)
            {
                Vector3 torqueB;
                Vector3.Negate(ref lambda, out torqueB);
                connectionB.ApplyAngularImpulse(ref torqueB);
            }

            return(Fix64.Abs(lambda.X) + Fix64.Abs(lambda.Y) + Fix64.Abs(lambda.Z));
        }
Beispiel #2
0
        private bool IsContactUnique(ref ContactData contactCandidate, ref QuickList <ContactData> candidatesToAdd)
        {
            contactCandidate.Validate();
            Fix64          distanceSquared;
            RigidTransform meshTransform = MeshTransform;

            for (int i = 0; i < contacts.Count; i++)
            {
                Vector3.DistanceSquared(ref contacts.Elements[i].Position, ref contactCandidate.Position, out distanceSquared);
                if (distanceSquared < CollisionDetectionSettings.ContactMinimumSeparationDistanceSquared)
                {
                    //This is a nonconvex manifold.  There will be times where a an object will be shoved into a corner such that
                    //a single position will have two reasonable normals.  If the normals aren't mostly aligned, they should NOT be considered equivalent.
                    Vector3.Dot(ref contacts.Elements[i].Normal, ref contactCandidate.Normal, out distanceSquared);
                    if (Fix64.Abs(distanceSquared) >= CollisionDetectionSettings.nonconvexNormalDotMinimum)
                    {
                        //Update the existing 'redundant' contact with the new information.
                        //This works out because the new contact is the deepest contact according to the previous collision detection iteration.
                        contacts.Elements[i].Normal                     = contactCandidate.Normal;
                        contacts.Elements[i].Position                   = contactCandidate.Position;
                        contacts.Elements[i].PenetrationDepth           = contactCandidate.PenetrationDepth;
                        supplementData.Elements[i].BasePenetrationDepth = contactCandidate.PenetrationDepth;
                        RigidTransform.TransformByInverse(ref contactCandidate.Position, ref convex.worldTransform, out supplementData.Elements[i].LocalOffsetA);
                        RigidTransform.TransformByInverse(ref contactCandidate.Position, ref meshTransform, out supplementData.Elements[i].LocalOffsetB);
                        return(false);
                    }
                }
            }
            for (int i = 0; i < candidatesToAdd.Count; i++)
            {
                Vector3.DistanceSquared(ref candidatesToAdd.Elements[i].Position, ref contactCandidate.Position, out distanceSquared);
                if (distanceSquared < CollisionDetectionSettings.ContactMinimumSeparationDistanceSquared)
                {
                    //This is a nonconvex manifold.  There will be times where a an object will be shoved into a corner such that
                    //a single position will have two reasonable normals.  If the normals aren't mostly aligned, they should NOT be considered equivalent.
                    Vector3.Dot(ref candidatesToAdd.Elements[i].Normal, ref contactCandidate.Normal, out distanceSquared);
                    if (Fix64.Abs(distanceSquared) >= CollisionDetectionSettings.nonconvexNormalDotMinimum)
                    {
                        return(false);
                    }
                }
            }
            //for (int i = 0; i < edgeContacts.count; i++)
            //{
            //    Vector3.DistanceSquared(ref edgeContacts.Elements[i].ContactData.Position, ref contactCandidate.Position, out distanceSquared);
            //    if (distanceSquared < CollisionDetectionSettings.ContactMinimumSeparationDistanceSquared)
            //    {
            //        return false;
            //    }
            //}
            //for (int i = 0; i < vertexContacts.count; i++)
            //{
            //    Vector3.DistanceSquared(ref vertexContacts.Elements[i].ContactData.Position, ref contactCandidate.Position, out distanceSquared);
            //    if (distanceSquared < CollisionDetectionSettings.ContactMinimumSeparationDistanceSquared)
            //    {
            //        return false;
            //    }
            //}
            return(true);
        }
        public GGame.Math.Fix64 Area()
        {
            GGame.Math.Fix64 b = Points[0].X - Points[1].X;
            GGame.Math.Fix64 h = Points[2].Y - Points[1].Y;

            return(Fix64.Abs((b * h * 0.5f)));
        }
Beispiel #4
0
        /// <summary>
        /// Computes one iteration of the constraint to meet the solver updateable's goal.
        /// </summary>
        /// <returns>The rough applied impulse magnitude.</returns>
        public override Fix64 SolveIteration()
        {
            Fix64 velocityA, velocityB;

            //Find the velocity contribution from each connection
            Vector3.Dot(ref connectionA.angularVelocity, ref jacobianA, out velocityA);
            Vector3.Dot(ref connectionB.angularVelocity, ref jacobianB, out velocityB);
            //Add in the constraint space bias velocity
            Fix64 lambda = -(velocityA + velocityB) - biasVelocity - usedSoftness * accumulatedImpulse;

            //Transform to an impulse
            lambda *= velocityToImpulse;

            //Accumulate the impulse
            Fix64 previousAccumulatedImpulse = accumulatedImpulse;

            accumulatedImpulse = MathHelper.Clamp(accumulatedImpulse + lambda, -maxForceDt, maxForceDt);
            lambda             = accumulatedImpulse - previousAccumulatedImpulse;

            //Apply the impulse
            Vector3 impulse;

            if (connectionA.isDynamic)
            {
                Vector3.Multiply(ref jacobianA, lambda, out impulse);
                connectionA.ApplyAngularImpulse(ref impulse);
            }
            if (connectionB.isDynamic)
            {
                Vector3.Multiply(ref jacobianB, lambda, out impulse);
                connectionB.ApplyAngularImpulse(ref impulse);
            }

            return(Fix64.Abs(lambda));
        }
Beispiel #5
0
        /**
         * <summary>Solves a two-dimensional linear program subject to linear
         * constraints defined by lines and a circular constraint.</summary>
         *
         * <param name="lines">Lines defining the linear constraints.</param>
         * <param name="numObstLines">Count of obstacle lines.</param>
         * <param name="beginLine">The line on which the 2-d linear program
         * failed.</param>
         * <param name="radius">The radius of the circular constraint.</param>
         * <param name="result">A reference to the result of the linear program.
         * </param>
         */
        private void linearProgram3(IList <Line> lines, int numObstLines, int beginLine, Fix64 radius, ref Vector2 result)
        {
            Fix64 distance = Fix64.Zero;

            for (int i = beginLine; i < lines.Count; ++i)
            {
                if (RVOMath.det(lines[i].direction, lines[i].point - result) > distance)
                {
                    /* Result does not satisfy constraint of line i. */
                    IList <Line> projLines = new List <Line>();
                    for (int ii = 0; ii < numObstLines; ++ii)
                    {
                        projLines.Add(lines[ii]);
                    }

                    for (int j = numObstLines; j < i; ++j)
                    {
                        Line line;

                        Fix64 determinant = RVOMath.det(lines[i].direction, lines[j].direction);

                        if (Fix64.Abs(determinant) <= RVOMath.RVO_EPSILON)
                        {
                            /* Line i and line j are parallel. */
                            if (Vector2.Dot(lines[i].direction, lines[j].direction) > Fix64.Zero)
                            {
                                /* Line i and line j point in the same direction. */
                                continue;
                            }
                            else
                            {
                                /* Line i and line j point in opposite direction. */
                                line.point = 0.5m * (lines[i].point + lines[j].point);
                            }
                        }
                        else
                        {
                            line.point = lines[i].point + (RVOMath.det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
                        }

                        line.direction = Vector2.Normalize(lines[j].direction - lines[i].direction);
                        projLines.Add(line);
                    }

                    Vector2 tempResult = result;
                    if (linearProgram2(projLines, radius, new Vector2(-lines[i].direction.Y, lines[i].direction.X), true, ref result) < projLines.Count)
                    {
                        /*
                         * This should in principle not happen. The result is by
                         * definition already in the feasible region of this
                         * linear program. If it fails, it is due to small
                         * Fix64ing point error, and the current result is kept.
                         */
                        result = tempResult;
                    }

                    distance = RVOMath.det(lines[i].direction, lines[i].point - result);
                }
            }
        }
        /// <summary>
        /// Updates the spin velocity and spin angle for the shape.
        /// </summary>
        /// <param name="dt">Simulation timestep.</param>
        internal void UpdateSpin(Fix64 dt)
        {
            if (wheel.HasSupport && !(wheel.brake.IsBraking && FreezeWheelsWhileBraking))
            {
                //On the ground, not braking.
                spinVelocity = wheel.drivingMotor.RelativeVelocity / Radius;
            }
            else if (wheel.HasSupport && wheel.brake.IsBraking && FreezeWheelsWhileBraking)
            {
                //On the ground, braking
                Fix64 deceleratedValue = F64.C0;
                if (spinVelocity > F64.C0)
                {
                    deceleratedValue = MathHelper.Max(spinVelocity - brakeFreezeWheelDeceleration * dt, F64.C0);
                }
                else if (spinVelocity < F64.C0)
                {
                    deceleratedValue = MathHelper.Min(spinVelocity + brakeFreezeWheelDeceleration * dt, F64.C0);
                }

                spinVelocity = wheel.drivingMotor.RelativeVelocity / Radius;

                if (Fix64.Abs(deceleratedValue) < Fix64.Abs(spinVelocity))
                {
                    spinVelocity = deceleratedValue;
                }
            }
            else if (!wheel.HasSupport && wheel.drivingMotor.TargetSpeed != F64.C0)
            {
                //Airborne and accelerating, increase spin velocity.
                Fix64 maxSpeed = Fix64.Abs(wheel.drivingMotor.TargetSpeed) / Radius;
                spinVelocity = MathHelper.Clamp(spinVelocity + Fix64.Sign(wheel.drivingMotor.TargetSpeed) * airborneWheelAcceleration * dt, -maxSpeed, maxSpeed);
            }
            else if (!wheel.HasSupport && wheel.Brake.IsBraking)
            {
                //Airborne and braking
                if (spinVelocity > F64.C0)
                {
                    spinVelocity = MathHelper.Max(spinVelocity - brakeFreezeWheelDeceleration * dt, F64.C0);
                }
                else if (spinVelocity < F64.C0)
                {
                    spinVelocity = MathHelper.Min(spinVelocity + brakeFreezeWheelDeceleration * dt, F64.C0);
                }
            }
            else if (!wheel.HasSupport)
            {
                //Just idly slowing down.
                if (spinVelocity > F64.C0)
                {
                    spinVelocity = MathHelper.Max(spinVelocity - airborneWheelDeceleration * dt, F64.C0);
                }
                else if (spinVelocity < F64.C0)
                {
                    spinVelocity = MathHelper.Min(spinVelocity + airborneWheelDeceleration * dt, F64.C0);
                }
            }
            spinAngle += spinVelocity * dt;
        }
Beispiel #7
0
        internal static bool CheckBoundings(MGFObject a, MGFObject b)
        {
            Fix64Vector2 posA = a.GetPos();
            Fix64Vector2 posB = b.GetPos();

            return(Fix64.Abs(posA.X - posB.X) < a.GetHalfSize().X + b.GetHalfSize().X&&
                   Fix64.Abs(posA.Y - posB.Y) < a.GetHalfSize().Y + b.GetHalfSize().Y);
        }
Beispiel #8
0
        public static bool Gauss(Fix64[,] M, int m, int n)
        {
            // Perform Gauss-Jordan elimination
            for (int k = 0; k < m; k++)
            {
                Fix64 maxValue = Fix64.Abs(M[k, k]);
                int   iMax     = k;
                for (int i = k + 1; i < m; i++)
                {
                    Fix64 value = Fix64.Abs(M[i, k]);
                    if (value >= maxValue)
                    {
                        maxValue = value;
                        iMax     = i;
                    }
                }
                if (maxValue == F64.C0)
                {
                    return(false);
                }
                // Swap rows k, iMax
                if (k != iMax)
                {
                    for (int j = 0; j < n; j++)
                    {
                        Fix64 temp = M[k, j];
                        M[k, j]    = M[iMax, j];
                        M[iMax, j] = temp;
                    }
                }

                // Divide row by pivot
                Fix64 pivotInverse = F64.C1 / M[k, k];

                M[k, k] = F64.C1;
                for (int j = k + 1; j < n; j++)
                {
                    M[k, j] *= pivotInverse;
                }

                // Subtract row k from other rows
                for (int i = 0; i < m; i++)
                {
                    if (i == k)
                    {
                        continue;
                    }
                    Fix64 f = M[i, k];
                    for (int j = k + 1; j < n; j++)
                    {
                        M[i, j] = M[i, j] - M[k, j] * f;
                    }
                    M[i, k] = F64.C0;
                }
            }
            return(true);
        }
Beispiel #9
0
        /// <summary>
        /// Computes the angle change represented by a normalized quaternion.
        /// </summary>
        /// <param name="q">Quaternion to be converted.</param>
        /// <returns>Angle around the axis represented by the quaternion.</returns>
        public static Fix64 GetAngleFromQuaternion(ref Quaternion q)
        {
            Fix64 qw = Fix64.Abs(q.W);

            if (qw > F64.C1)
            {
                return(F64.C0);
            }
            return(F64.C2 * Fix64.Acos(qw));
        }
 /// <summary>
 /// Sets up the axes of the transform and ensures that it is an orthonormal basis.
 /// </summary>
 /// <param name="matrix">Rotation matrix representing the three axes.
 /// The matrix's backward vector is used as the primary axis.
 /// The matrix's right vector is used as the x axis.</param>
 public void SetLocalAxes(Matrix3x3 matrix)
 {
     if (Fix64.Abs(Vector3.Dot(matrix.Backward, matrix.Right)) > Toolbox.BigEpsilon)
     {
         throw new ArgumentException("The axes provided to the joint transform are not perpendicular.  Ensure that the specified axes form a valid constraint.");
     }
     localPrimaryAxis = Vector3.Normalize(matrix.Backward);
     localXAxis       = Vector3.Normalize(matrix.Right);
     ComputeWorldSpaceAxes();
 }
Beispiel #11
0
        /// <summary>
        /// Calculates and applies corrective impulses.
        /// Called automatically by space.
        /// </summary>
        public override Fix64 SolveIteration()
        {
#if !WINDOWS
            Vector3 lambda = new Vector3();
#else
            Vector3 lambda;
#endif

            //Velocity along the length.
            Vector3 cross;
            Vector3 aVel, bVel;
            Vector3.Cross(ref connectionA.angularVelocity, ref worldOffsetA, out cross);
            Vector3.Add(ref connectionA.linearVelocity, ref cross, out aVel);
            Vector3.Cross(ref connectionB.angularVelocity, ref worldOffsetB, out cross);
            Vector3.Add(ref connectionB.linearVelocity, ref cross, out bVel);

            lambda.X = aVel.X - bVel.X + biasVelocity.X - softness * accumulatedImpulse.X;
            lambda.Y = aVel.Y - bVel.Y + biasVelocity.Y - softness * accumulatedImpulse.Y;
            lambda.Z = aVel.Z - bVel.Z + biasVelocity.Z - softness * accumulatedImpulse.Z;

            //Turn the velocity into an impulse.
            Matrix3x3.Transform(ref lambda, ref massMatrix, out lambda);

            //Accumulate the impulse
            Vector3.Add(ref accumulatedImpulse, ref lambda, out accumulatedImpulse);

            //Apply the impulse
            //Constraint.applyImpulse(myConnectionA, myConnectionB, ref rA, ref rB, ref impulse);
#if !WINDOWS
            Vector3 linear = new Vector3();
#else
            Vector3 linear;
#endif
            if (connectionA.isDynamic)
            {
                linear.X = -lambda.X;
                linear.Y = -lambda.Y;
                linear.Z = -lambda.Z;
                connectionA.ApplyLinearImpulse(ref linear);
                Vector3 taImpulse;
                Vector3.Cross(ref worldOffsetA, ref linear, out taImpulse);
                connectionA.ApplyAngularImpulse(ref taImpulse);
            }
            if (connectionB.isDynamic)
            {
                connectionB.ApplyLinearImpulse(ref lambda);
                Vector3 tbImpulse;
                Vector3.Cross(ref worldOffsetB, ref lambda, out tbImpulse);
                connectionB.ApplyAngularImpulse(ref tbImpulse);
            }

            return(Fix64.Abs(lambda.X) +
                   Fix64.Abs(lambda.Y) +
                   Fix64.Abs(lambda.Z));
        }
        /// <summary>
        /// Finds and fixes "pinch points," points where two polygon
        /// vertices are at the same point.
        /// If a pinch point is found, pin is broken up into poutA and poutB
        /// and true is returned; otherwise, returns false.
        /// Mostly for internal use.
        /// O(N^2) time, which sucks...
        /// </summary>
        /// <param name="pin">The pin.</param>
        /// <param name="poutA">The pout A.</param>
        /// <param name="poutB">The pout B.</param>
        /// <param name="tolerance"></param>
        private static bool ResolvePinchPoint(Vertices pin, out Vertices poutA, out Vertices poutB, GGame.Math.Fix64 tolerance)
        {
            poutA = new Vertices();
            poutB = new Vertices();

            if (pin.Count < 3)
            {
                return(false);
            }

            bool hasPinchPoint = false;
            int  pinchIndexA   = -1;
            int  pinchIndexB   = -1;

            for (int i = 0; i < pin.Count; ++i)
            {
                for (int j = i + 1; j < pin.Count; ++j)
                {
                    //Don't worry about pinch points where the points
                    //are actually just dupe neighbors
                    if (Fix64.Abs(pin[i].X - pin[j].X) < tolerance && Fix64.Abs(pin[i].Y - pin[j].Y) < tolerance && j != i + 1)
                    {
                        pinchIndexA   = i;
                        pinchIndexB   = j;
                        hasPinchPoint = true;
                        break;
                    }
                }
                if (hasPinchPoint)
                {
                    break;
                }
            }
            if (hasPinchPoint)
            {
                int sizeA = pinchIndexB - pinchIndexA;
                if (sizeA == pin.Count)
                {
                    return(false); //has dupe points at wraparound, not a problem here
                }
                for (int i = 0; i < sizeA; ++i)
                {
                    int ind = Remainder(pinchIndexA + i, pin.Count); // is this right
                    poutA.Add(pin[ind]);
                }

                int sizeB = pin.Count - sizeA;
                for (int i = 0; i < sizeB; ++i)
                {
                    int ind = Remainder(pinchIndexB + i, pin.Count); // is this right
                    poutB.Add(pin[ind]);
                }
            }
            return(hasPinchPoint);
        }
 /// <summary>
 /// Sets up the axes of the transform and ensures that it is an orthonormal basis.
 /// </summary>
 /// <param name="matrix">Rotation matrix representing the three axes.
 /// The matrix's backward vector is used as the primary axis.
 /// The matrix's right vector is used as the x axis.</param>
 public void SetWorldAxes(Matrix3x3 matrix)
 {
     if (Fix64.Abs(Vector3.Dot(matrix.Backward, matrix.Right)) > Toolbox.BigEpsilon)
     {
         throw new ArgumentException("The axes provided to the joint transform are not perpendicular.  Ensure that the specified axes form a valid constraint.");
     }
     primaryAxis = Vector3.Normalize(matrix.Backward);
     xAxis       = Vector3.Normalize(matrix.Right);
     Matrix3x3.TransformTranspose(ref this.primaryAxis, ref rotationMatrix, out localPrimaryAxis);
     Matrix3x3.TransformTranspose(ref this.xAxis, ref rotationMatrix, out localXAxis);
 }
Beispiel #14
0
 /// <summary>
 /// Changes every sign of the matrix entry to '+'
 /// </summary>
 /// <param name="matrix">The matrix.</param>
 /// <param name="result">The absolute matrix.</param>
 #region public static void Absolute(ref JMatrix matrix,out JMatrix result)
 public static void Absolute(ref FPMatrix matrix, out FPMatrix result)
 {
     result.M11 = Fix64.Abs(matrix.M11);
     result.M12 = Fix64.Abs(matrix.M12);
     result.M13 = Fix64.Abs(matrix.M13);
     result.M21 = Fix64.Abs(matrix.M21);
     result.M22 = Fix64.Abs(matrix.M22);
     result.M23 = Fix64.Abs(matrix.M23);
     result.M31 = Fix64.Abs(matrix.M31);
     result.M32 = Fix64.Abs(matrix.M32);
     result.M33 = Fix64.Abs(matrix.M33);
 }
 internal bool IsHitUnique(RawList <RayHit> hits, ref RayHit hit)
 {
     for (int i = 0; i < hits.Count; i++)
     {
         if (Fix64.Abs(hits.Elements[i].T - hit.T) < MeshHitUniquenessThreshold)
         {
             return(false);
         }
     }
     hits.Add(hit);
     return(true);
 }
        /// <summary>
        /// Computes one iteration of the constraint to meet the solver updateable's goal.
        /// </summary>
        /// <returns>The rough applied impulse magnitude.</returns>
        public override Fix64 SolveIteration()
        {
            //Compute the current relative velocity.
            Fix64 lambda, dot;

            Vector3.Dot(ref jLinearA, ref connectionA.linearVelocity, out lambda);
            Vector3.Dot(ref jAngularA, ref connectionA.angularVelocity, out dot);
            lambda += dot;
            Vector3.Dot(ref jLinearB, ref connectionB.linearVelocity, out dot);
            lambda += dot;
            Vector3.Dot(ref jAngularB, ref connectionB.angularVelocity, out dot);
            lambda += dot;

            //Add in the constraint space bias velocity
            lambda = -lambda + biasVelocity - softness * accumulatedImpulse;

            //Transform to an impulse
            lambda *= massMatrix;

            //Clamp accumulated impulse (can't go negative)
            Fix64 previousAccumulatedImpulse = accumulatedImpulse;

            if (unadjustedError < F64.C0)
            {
                accumulatedImpulse = MathHelper.Min(accumulatedImpulse + lambda, F64.C0);
            }
            else
            {
                accumulatedImpulse = MathHelper.Max(accumulatedImpulse + lambda, F64.C0);
            }
            lambda = accumulatedImpulse - previousAccumulatedImpulse;

            //Apply the impulse
            Vector3 impulse;

            if (connectionA.isDynamic)
            {
                Vector3.Multiply(ref jLinearA, lambda, out impulse);
                connectionA.ApplyLinearImpulse(ref impulse);
                Vector3.Multiply(ref jAngularA, lambda, out impulse);
                connectionA.ApplyAngularImpulse(ref impulse);
            }
            if (connectionB.isDynamic)
            {
                Vector3.Multiply(ref jLinearB, lambda, out impulse);
                connectionB.ApplyLinearImpulse(ref impulse);
                Vector3.Multiply(ref jAngularB, lambda, out impulse);
                connectionB.ApplyAngularImpulse(ref impulse);
            }

            return(Fix64.Abs(lambda));
        }
Beispiel #17
0
        public void Abs()
        {
            Assert.AreEqual(Fix64.MaxValue(), Fix64.Abs(Fix64.MinValue()));
            var sources   = new[] { -1, 0, 1, int.MaxValue };
            var expecteds = new[] { 1, 0, 1, int.MaxValue };

            for (int i = 0; i < sources.Length; ++i)
            {
                var actual   = Fix64.Abs((Fix64)sources[i]);
                var expected = (Fix64)expecteds[i];
                Assert.AreEqual(expected, actual);
            }
        }
        internal override bool SolvePositionConstraints(ref SolverData data)
        {
            Vector2 cA = data.Positions[_indexA].C;

            GGame.Math.Fix64 aA = data.Positions[_indexA].A;
            Vector2          cB = data.Positions[_indexB].C;

            GGame.Math.Fix64 aB = data.Positions[_indexB].A;

            Rot qA = new Rot(aA), qB = new Rot(aB);

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

            Vector2 ay = MathUtils.Mul(qA, _localYAxis);

            GGame.Math.Fix64 sAy = MathUtils.Cross(d + rA, ay);
            GGame.Math.Fix64 sBy = MathUtils.Cross(rB, ay);

            GGame.Math.Fix64 C = Vector2.Dot(d, ay);

            GGame.Math.Fix64 k = _invMassA + _invMassB + _invIA * _sAy * _sAy + _invIB * _sBy * _sBy;

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

            Vector2 P = impulse * ay;

            GGame.Math.Fix64 LA = impulse * sAy;
            GGame.Math.Fix64 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(Fix64.Abs(C) <= Settings.LinearSlop);
        }
Beispiel #19
0
        /// <summary>
        /// Cylinder shape used to compute the expanded bounding box of the character.
        /// </summary>
        void ExpandBoundingBox()
        {
            if (Body.ActivityInformation.IsActive)
            {
                //This runs after the bounding box updater is run, but before the broad phase.
                //Expanding the character's bounding box ensures that minor variations in velocity will not cause
                //any missed information.

                //TODO: seems a bit silly to do this work sequentially. Would be better if it could run in parallel in the proper location.

                var down        = Down;
                var boundingBox = Body.CollisionInformation.BoundingBox;
                //Expand the bounding box up and down using the step height.
                Vector3 expansion;
                Vector3.Multiply(ref down, StepManager.MaximumStepHeight, out expansion);
                expansion.X = Fix64.Abs(expansion.X);
                expansion.Y = Fix64.Abs(expansion.Y);
                expansion.Z = Fix64.Abs(expansion.Z);

                //When the character climbs a step, it teleports horizontally a little to gain support. Expand the bounding box to accommodate the margin.
                //Compute the expansion caused by the extra radius along each axis.
                //There's a few ways to go about doing this.

                //The following is heavily cooked, but it is based on the angle between the vertical axis and a particular axis.
                //Given that, the amount of the radial expansion required along that axis can be computed.
                //The dot product would provide the cos(angle) between the vertical axis and a chosen axis.
                //Equivalently, it is how much expansion would be along that axis, if the vertical axis was the axis of expansion.
                //However, it's not. The dot product actually gives us the expansion along an axis perpendicular to the chosen axis, pointing away from the character's vertical axis.

                //What we need is actually given by the sin(angle), which is given by ||verticalAxis x testAxis||.
                //The sin(angle) is the projected length of the verticalAxis (not the expansion!) on the axis perpendicular to the testAxis pointing away from the character's vertical axis.
                //That projected length, however is equal to the expansion along the test axis, which is exactly what we want.
                //To show this, try setting up the triangles at the corner of a cylinder with the world axes and cylinder axes.

                //Since the test axes we're using are all standard directions ({0,0,1}, {0,1,0}, and {0,0,1}), most of the cross product logic simplifies out, and we are left with:
                var     horizontalExpansionAmount = Body.CollisionInformation.Shape.CollisionMargin * F64.C1p1;
                Vector3 squaredDown;
                squaredDown.X = down.X * down.X;
                squaredDown.Y = down.Y * down.Y;
                squaredDown.Z = down.Z * down.Z;
                expansion.X  += horizontalExpansionAmount * Fix64.Sqrt(squaredDown.Y + squaredDown.Z);
                expansion.Y  += horizontalExpansionAmount * Fix64.Sqrt(squaredDown.X + squaredDown.Z);
                expansion.Z  += horizontalExpansionAmount * Fix64.Sqrt(squaredDown.X + squaredDown.Y);

                Vector3.Add(ref expansion, ref boundingBox.Max, out boundingBox.Max);
                Vector3.Subtract(ref boundingBox.Min, ref expansion, out boundingBox.Min);

                Body.CollisionInformation.BoundingBox = boundingBox;
            }
        }
        /// <summary>
        /// Sets up the axes of the transform and ensures that it is an orthonormal basis.
        /// </summary>
        /// <param name="primaryAxis">First axis in the transform.  Usually aligned along the main axis of a joint, like the twist axis of a TwistLimit.</param>
        /// <param name="xAxis">Second axis in the transform.</param>
        /// <param name="yAxis">Third axis in the transform.</param>
        public void SetLocalAxes(Vector3 primaryAxis, Vector3 xAxis, Vector3 yAxis)
        {
            if (Fix64.Abs(Vector3.Dot(primaryAxis, xAxis)) > Toolbox.BigEpsilon ||
                Fix64.Abs(Vector3.Dot(primaryAxis, yAxis)) > Toolbox.BigEpsilon ||
                Fix64.Abs(Vector3.Dot(xAxis, yAxis)) > Toolbox.BigEpsilon)
            {
                throw new ArgumentException("The axes provided to the joint transform do not form an orthonormal basis.  Ensure that each axis is perpendicular to the other two.");
            }

            localPrimaryAxis = Vector3.Normalize(primaryAxis);
            localXAxis       = Vector3.Normalize(xAxis);
            localYAxis       = Vector3.Normalize(yAxis);
            ComputeWorldSpaceAxes();
        }
        /// <summary>
        /// Sets up the axes of the transform and ensures that it is an orthonormal basis.
        /// </summary>
        /// <param name="matrix">Rotation matrix representing the three axes.
        /// The matrix's backward vector is used as the primary axis.
        /// The matrix's right vector is used as the x axis.
        /// The matrix's up vector is used as the y axis.</param>
        public void SetLocalAxes(Matrix3x3 matrix)
        {
            if (Fix64.Abs(Vector3.Dot(matrix.Backward, matrix.Right)) > Toolbox.BigEpsilon ||
                Fix64.Abs(Vector3.Dot(matrix.Backward, matrix.Up)) > Toolbox.BigEpsilon ||
                Fix64.Abs(Vector3.Dot(matrix.Right, matrix.Up)) > Toolbox.BigEpsilon)
            {
                throw new ArgumentException("The axes provided to the joint transform do not form an orthonormal basis.  Ensure that each axis is perpendicular to the other two.");
            }

            localPrimaryAxis = Vector3.Normalize(matrix.Backward);
            localXAxis       = Vector3.Normalize(matrix.Right);
            localYAxis       = Vector3.Normalize(matrix.Up);
            ComputeWorldSpaceAxes();
        }
Beispiel #22
0
        /// <summary>
        /// Applies the corrective impulses required by the constraint.
        /// </summary>
        public override Fix64 SolveIteration()
        {
#if !WINDOWS
            Vector3 lambda = new Vector3();
#else
            Vector3 lambda;
#endif
            Vector3 aVel = connectionA.angularVelocity;
            Vector3 bVel = connectionB.angularVelocity;
            lambda.X = bVel.X - aVel.X - biasVelocity.X - usedSoftness * accumulatedImpulse.X;
            lambda.Y = bVel.Y - aVel.Y - biasVelocity.Y - usedSoftness * accumulatedImpulse.Y;
            lambda.Z = bVel.Z - aVel.Z - biasVelocity.Z - usedSoftness * accumulatedImpulse.Z;

            Matrix3x3.Transform(ref lambda, ref effectiveMassMatrix, out lambda);

            Vector3 previousAccumulatedImpulse = accumulatedImpulse;
            accumulatedImpulse.X += lambda.X;
            accumulatedImpulse.Y += lambda.Y;
            accumulatedImpulse.Z += lambda.Z;
            Fix64 sumLengthSquared = accumulatedImpulse.LengthSquared();

            if (sumLengthSquared > maxForceDtSquared)
            {
                //max / impulse gives some value 0 < x < 1.  Basically, normalize the vector (divide by the length) and scale by the maximum.
                Fix64 multiplier = maxForceDt / Fix64.Sqrt(sumLengthSquared);
                accumulatedImpulse.X *= multiplier;
                accumulatedImpulse.Y *= multiplier;
                accumulatedImpulse.Z *= multiplier;

                //Since the limit was exceeded by this corrective impulse, limit it so that the accumulated impulse remains constrained.
                lambda.X = accumulatedImpulse.X - previousAccumulatedImpulse.X;
                lambda.Y = accumulatedImpulse.Y - previousAccumulatedImpulse.Y;
                lambda.Z = accumulatedImpulse.Z - previousAccumulatedImpulse.Z;
            }


            if (connectionA.isDynamic)
            {
                connectionA.ApplyAngularImpulse(ref lambda);
            }
            if (connectionB.isDynamic)
            {
                Vector3 torqueB;
                Vector3.Negate(ref lambda, out torqueB);
                connectionB.ApplyAngularImpulse(ref torqueB);
            }

            return(Fix64.Abs(lambda.X) + Fix64.Abs(lambda.Y) + Fix64.Abs(lambda.Z));
        }
        // From Eric Jordan's convex decomposition library
        /// <summary>
        /// Check if the lines a0->a1 and b0->b1 cross.
        /// If they do, intersectionPoint will be filled
        /// with the point of crossing.
        /// Grazing lines should not return true.
        /// </summary>
        public static bool LineIntersect2(ref Vector2 a0, ref Vector2 a1, ref Vector2 b0, ref Vector2 b1, out Vector2 intersectionPoint)
        {
            intersectionPoint = Vector2.Zero;

            if (a0 == b0 || a0 == b1 || a1 == b0 || a1 == b1)
            {
                return(false);
            }

            GGame.Math.Fix64 x1 = a0.X;
            GGame.Math.Fix64 y1 = a0.Y;
            GGame.Math.Fix64 x2 = a1.X;
            GGame.Math.Fix64 y2 = a1.Y;
            GGame.Math.Fix64 x3 = b0.X;
            GGame.Math.Fix64 y3 = b0.Y;
            GGame.Math.Fix64 x4 = b1.X;
            GGame.Math.Fix64 y4 = b1.Y;

            //AABB early exit
            if (Math.Max((float)x1, (float)x2) < Math.Min((float)x3, (float)x4) || Math.Max((float)x3, (float)x4) < Math.Min((float)x1, (float)x2))
            {
                return(false);
            }

            if (Math.Max((float)y1, (float)y2) < Math.Min((float)y3, (float)y4) || Math.Max((float)y3, (float)y4) < Math.Min((float)y1, (float)y2))
            {
                return(false);
            }

            GGame.Math.Fix64 ua    = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));
            GGame.Math.Fix64 ub    = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));
            GGame.Math.Fix64 denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
            if (Fix64.Abs(denom) < Settings.Epsilon)
            {
                //Lines are too close to parallel to call
                return(false);
            }
            ua /= denom;
            ub /= denom;

            if ((0 < ua) && (ua < 1) && (0 < ub) && (ub < 1))
            {
                intersectionPoint.X = (x1 + ua * (x2 - x1));
                intersectionPoint.Y = (y1 + ua * (y2 - y1));
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Calculates and applies corrective impulses.
        /// Called automatically by space.
        /// </summary>
        public override Fix64 SolveIteration()
        {
            Fix64 linearSpeed = entity.linearVelocity.LengthSquared();

            if (linearSpeed > maximumSpeedSquared)
            {
                linearSpeed = Fix64.Sqrt(linearSpeed);
                Vector3 impulse;
                //divide by linearSpeed to normalize the velocity.
                //Multiply by linearSpeed - maximumSpeed to get the 'velocity change vector.'
                Vector3.Multiply(ref entity.linearVelocity, -(linearSpeed - maximumSpeed) / linearSpeed, out impulse);

                //incorporate softness
                Vector3 softnessImpulse;
                Vector3.Multiply(ref accumulatedImpulse, usedSoftness, out softnessImpulse);
                Vector3.Subtract(ref impulse, ref softnessImpulse, out impulse);

                //Transform into impulse
                Vector3.Multiply(ref impulse, effectiveMassMatrix, out impulse);


                //Accumulate
                Vector3 previousAccumulatedImpulse = accumulatedImpulse;
                Vector3.Add(ref accumulatedImpulse, ref impulse, out accumulatedImpulse);
                Fix64 forceMagnitude = accumulatedImpulse.LengthSquared();
                if (forceMagnitude > maxForceDtSquared)
                {
                    //max / impulse gives some value 0 < x < 1.  Basically, normalize the vector (divide by the length) and scale by the maximum.
                    Fix64 multiplier = maxForceDt / Fix64.Sqrt(forceMagnitude);
                    accumulatedImpulse.X *= multiplier;
                    accumulatedImpulse.Y *= multiplier;
                    accumulatedImpulse.Z *= multiplier;

                    //Since the limit was exceeded by this corrective impulse, limit it so that the accumulated impulse remains constrained.
                    impulse.X = accumulatedImpulse.X - previousAccumulatedImpulse.X;
                    impulse.Y = accumulatedImpulse.Y - previousAccumulatedImpulse.Y;
                    impulse.Z = accumulatedImpulse.Z - previousAccumulatedImpulse.Z;
                }

                entity.ApplyLinearImpulse(ref impulse);


                return(Fix64.Abs(impulse.X) + Fix64.Abs(impulse.Y) + Fix64.Abs(impulse.Z));
            }


            return(F64.C0);
        }
        /// <summary>
        /// Sets up the axes of the transform and ensures that it is an orthonormal basis.
        /// </summary>
        /// <param name="matrix">Rotation matrix representing the three axes.
        /// The matrix's backward vector is used as the primary axis.
        /// The matrix's right vector is used as the x axis.
        /// The matrix's up vector is used as the y axis.</param>
        public void SetWorldAxes(Matrix3x3 matrix)
        {
            if (Fix64.Abs(Vector3.Dot(matrix.Backward, matrix.Right)) > Toolbox.BigEpsilon ||
                Fix64.Abs(Vector3.Dot(matrix.Backward, matrix.Up)) > Toolbox.BigEpsilon ||
                Fix64.Abs(Vector3.Dot(matrix.Right, matrix.Up)) > Toolbox.BigEpsilon)
            {
                throw new ArgumentException("The axes provided to the joint transform do not form an orthonormal basis.  Ensure that each axis is perpendicular to the other two.");
            }

            primaryAxis = Vector3.Normalize(matrix.Backward);
            xAxis       = Vector3.Normalize(matrix.Right);
            yAxis       = Vector3.Normalize(matrix.Up);
            Matrix3x3.TransformTranspose(ref this.primaryAxis, ref rotationMatrix, out localPrimaryAxis);
            Matrix3x3.TransformTranspose(ref this.xAxis, ref rotationMatrix, out localXAxis);
            Matrix3x3.TransformTranspose(ref this.yAxis, ref rotationMatrix, out localYAxis);
        }
Beispiel #26
0
        // 判断给定扇形是否与指定圆形相交
        public static bool IsFunOverlappedCircle(Vec2 circleCenter, Fix64 circleR, Vec2 fanCenter, Fix64 fanR, Fix64 fanDir, Fix64 fanAngle)
        {
            // 先判断圆心距离
            var dc = circleCenter - fanCenter;
            var r  = dc.Length;

            if (r > circleR + fanR)
            {
                return(false);
            }

            // 在判断方向角度
            var dir = MU.v2Degree(dc.x, dc.y);
            var dd  = (dir - fanDir).RangeIn180();

            return(Fix64.Abs(dd) <= fanAngle / 2);
        }
Beispiel #27
0
 private Fix64 minValueFunc(Fix64 a, Fix64 b, Fix64 c, Fix64 l1, Fix64 l2, Fix64 aDelta, out Fix64 et)
 {
     if (Fix64.Abs(a) <= aDelta)
     {
         var r1 = b * l1 + c;
         var r2 = b * l2 + c;
         et = (r1 < r2) ? l1 : l2;
         return((r1 < r2) ? r1 : r2);
     }
     if (a > Fix64.Zero)
     {
         var ext = -b / ((Fix64)2 * a);
         if (ext < l1)
         {
             et = l1;
             return(a * l1 * l1 + b * l1 + c);
         }
         if (ext > l2)
         {
             et = l2;
             return(a * l2 * l2 + b * l2 + c);
         }
         et = ext;
         return(a * ext * ext + b * ext + c);
     }
     if (a < Fix64.Zero)
     {
         var ext = -b / ((Fix64)2 * a);
         if (ext < l1)
         {
             et = l2;
             return(a * l2 * l2 + b * l2 + c);
         }
         if (ext > l2)
         {
             et = l1;
             return(a * l1 * l1 + b * l1 + c);
         }
         var r1 = a * l2 * l2 + b * l2 + c;
         var r2 = a * l1 * l1 + b * l1 + c;
         et = (r1 < r2) ? l1 : l2;
         return((r1 < r2) ? r1 : r2);
     }
     et = Fix64.Zero;
     return((Fix64)0);
 }
Beispiel #28
0
        /// <summary>
        /// Determines if and when the ray intersects the plane.
        /// </summary>
        /// <param name="plane">Plane to test against.</param>
        /// <param name="t">The length along the ray to the impact, if any impact occurs.</param>
        /// <returns>True if the ray intersects the target, false otherwise.</returns>
        public bool Intersects(ref Plane plane, out Fix64 t)
        {
            Fix64 velocity;

            Vector3.Dot(ref Direction, ref plane.Normal, out velocity);
            if (Fix64.Abs(velocity) < Toolbox.Epsilon)
            {
                t = F64.C0;
                return(false);
            }
            Fix64 distanceAlongNormal;

            Vector3.Dot(ref Position, ref plane.Normal, out distanceAlongNormal);
            distanceAlongNormal += plane.D;
            t = -distanceAlongNormal / velocity;
            return(t >= -Toolbox.Epsilon);
        }
        /// <summary>
        /// Computes one iteration of the constraint to meet the solver updateable's goal.
        /// </summary>
        /// <returns>The rough applied impulse magnitude.</returns>
        public override Fix64 SolveIteration()
        {
            //Compute relative velocity
            Vector3 lambda;

            Vector3.Cross(ref r, ref entity.angularVelocity, out lambda);
            Vector3.Subtract(ref lambda, ref entity.linearVelocity, out lambda);

            //Add in bias velocity
            Vector3.Add(ref biasVelocity, ref lambda, out lambda);

            //Add in softness
            Vector3 softnessVelocity;

            Vector3.Multiply(ref accumulatedImpulse, usedSoftness, out softnessVelocity);
            Vector3.Subtract(ref lambda, ref softnessVelocity, out lambda);

            //In terms of an impulse (an instantaneous change in momentum), what is it?
            Matrix3x3.Transform(ref lambda, ref effectiveMassMatrix, out lambda);

            //Sum the impulse.
            Vector3 previousAccumulatedImpulse = accumulatedImpulse;

            accumulatedImpulse += lambda;

            //If the impulse it takes to get to the goal is too high for the motor to handle, scale it back.
            Fix64 sumImpulseLengthSquared = accumulatedImpulse.LengthSquared();

            if (sumImpulseLengthSquared > maxForceDtSquared)
            {
                //max / impulse gives some value 0 < x < 1.  Basically, normalize the vector (divide by the length) and scale by the maximum.
                accumulatedImpulse *= maxForceDt / Fix64.Sqrt(sumImpulseLengthSquared);

                //Since the limit was exceeded by this corrective impulse, limit it so that the accumulated impulse remains constrained.
                lambda = accumulatedImpulse - previousAccumulatedImpulse;
            }


            entity.ApplyLinearImpulse(ref lambda);
            Vector3 taImpulse;

            Vector3.Cross(ref r, ref lambda, out taImpulse);
            entity.ApplyAngularImpulse(ref taImpulse);

            return(Fix64.Abs(lambda.X) + Fix64.Abs(lambda.Y) + Fix64.Abs(lambda.Z));
        }
        /// <summary>
        /// Computes one iteration of the constraint to meet the solver updateable's goal.
        /// </summary>
        /// <returns>The rough applied impulse magnitude.</returns>
        public override Fix64 SolveIteration()
        {
            //Compute relative velocity and convert to impulse
            Fix64 lambda = RelativeVelocity * velocityToImpulse;


            //Clamp accumulated impulse
            Fix64 previousAccumulatedImpulse = accumulatedImpulse;
            Fix64 maxForce = friction * penetrationConstraint.accumulatedImpulse;

            accumulatedImpulse = MathHelper.Clamp(accumulatedImpulse + lambda, -maxForce, maxForce);
            lambda             = accumulatedImpulse - previousAccumulatedImpulse;

            //Apply the impulse
#if !WINDOWS
            Vector3 linear  = new Vector3();
            Vector3 angular = new Vector3();
#else
            Vector3 linear, angular;
#endif
            linear.X = lambda * linearAX;
            linear.Y = lambda * linearAY;
            linear.Z = lambda * linearAZ;
            if (entityAIsDynamic)
            {
                angular.X = lambda * angularAX;
                angular.Y = lambda * angularAY;
                angular.Z = lambda * angularAZ;
                entityA.ApplyLinearImpulse(ref linear);
                entityA.ApplyAngularImpulse(ref angular);
            }
            if (entityBIsDynamic)
            {
                linear.X  = -linear.X;
                linear.Y  = -linear.Y;
                linear.Z  = -linear.Z;
                angular.X = lambda * angularBX;
                angular.Y = lambda * angularBY;
                angular.Z = lambda * angularBZ;
                entityB.ApplyLinearImpulse(ref linear);
                entityB.ApplyAngularImpulse(ref angular);
            }

            return(Fix64.Abs(lambda));
        }