예제 #1
0
        /// <summary>
        /// Rotates the view direction up or down relative to the locked up vector.
        /// </summary>
        /// <param name="radians">Amount to rotate.</param>
        public void Pitch(Fix64 radians)
        {
            //Do not allow the new view direction to violate the maximum pitch.
            Fix64 dot;

            Vector3.Dot(ref viewDirection, ref lockedUp, out dot);

            //While this could be rephrased in terms of dot products alone, converting to actual angles can be more intuitive.
            //Consider +Pi/2 to be up, and -Pi/2 to be down.
            Fix64 currentPitch = Fix64.Acos(MathHelper.Clamp(-dot, -1, 1)) - MathHelper.PiOver2;
            //Compute our new pitch by clamping the current + change.
            Fix64 newPitch      = MathHelper.Clamp(currentPitch + radians, -maximumPitch, maximumPitch);
            Fix64 allowedChange = newPitch - currentPitch;

            //Compute and apply the rotation.
            Vector3 pitchAxis;

            Vector3.Cross(ref viewDirection, ref lockedUp, out pitchAxis);
            //This is guaranteed safe by all interaction points stopping viewDirection from being aligned with lockedUp.
            pitchAxis.Normalize();
            Matrix3x3 rotation;

            Matrix3x3.CreateFromAxisAngle(ref pitchAxis, allowedChange, out rotation);
            Matrix3x3.Transform(ref viewDirection, ref rotation, out viewDirection);

            //Avoid drift by renormalizing.
            viewDirection.Normalize();
        }
예제 #2
0
        /// <summary>
        /// Computes the axis angle representation of a normalized quaternion.
        /// </summary>
        /// <param name="q">Quaternion to be converted.</param>
        /// <param name="axis">Axis represented by the quaternion.</param>
        /// <param name="angle">Angle around the axis represented by the quaternion.</param>
        public static void GetAxisAngleFromQuaternion(ref Quaternion q, out Vector3 axis, out Fix64 angle)
        {
#if !WINDOWS
            axis = new Vector3();
#endif
            Fix64 qw = q.W;
            if (qw > F64.C0)
            {
                axis.X = q.X;
                axis.Y = q.Y;
                axis.Z = q.Z;
            }
            else
            {
                axis.X = -q.X;
                axis.Y = -q.Y;
                axis.Z = -q.Z;
                qw     = -qw;
            }

            Fix64 lengthSquared = axis.LengthSquared();
            if (lengthSquared > F64.C1em14)
            {
                Vector3.Divide(ref axis, Fix64.Sqrt(lengthSquared), out axis);
                angle = F64.C2 * Fix64.Acos(MathHelper.Clamp(qw, -1, F64.C1));
            }
            else
            {
                axis  = Toolbox.UpVector;
                angle = F64.C0;
            }
        }
예제 #3
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));
        }
예제 #4
0
    public static Fix64 Angle(FixQuaternion a, FixQuaternion b)
    {
        FixQuaternion aInv = FixQuaternion.Inverse(a);
        FixQuaternion f    = b * aInv;

        Fix64 angle = Fix64.Acos(f.w) * 2 * Fix64.Rad2Deg;

        if (angle > 180)
        {
            angle = 360 - angle;
        }

        return(angle);
    }
예제 #5
0
        /// <summary>
        /// Updates the upright constraint.
        /// Called automatically by its owning space.
        /// </summary>
        /// <param name="dt">Time since last frame in simulation seconds.</param>
        void IDuringForcesUpdateable.Update(Fix64 dt)
        {
            myWorldUpVector = Matrix3x3.Transform(myLocalUpVector, Entity.OrientationMatrix);

            //Compute the axis and angle
            Vector3 axis  = Vector3.Cross(myWorldUpVector, Vector3.Up);
            var     angle = Fix64.Acos(Vector3.Dot(Vector3.Up, myWorldUpVector));

            if (angle > MinimumAngle && angle < MaximumAngle)
            {
                angle = angle - MinimumAngle;
                axis.Normalize();
                Entity.AngularMomentum += (axis * (angle * CorrectionFactor * dt));
            }
        }
예제 #6
0
    public static FixQuaternion Slerp(FixQuaternion from, FixQuaternion to, Fix64 t)
    {
        t = FixMath.Clamp(t, 0, 1);

        Fix64 dot = Dot(from, to);

        if (dot < 0.0f)
        {
            to  = Multiply(to, -1);
            dot = -dot;
        }

        Fix64 halfTheta = Fix64.Acos(dot);

        return(Multiply(Multiply(from, Fix64.Sin((1 - t) * halfTheta)) + Multiply(to, Fix64.Sin(t * halfTheta)), 1 / Fix64.Sin(halfTheta)));
    }
예제 #7
0
        public Fix64 GetAngleFromX()
        {
            if (sqrtMagnitude <= (Fix64)0)
            {
                return((Fix64)0);
            }
            Fix64 cosA = x / magnitude;
            Fix64 sinA = y / magnitude;

            if (sinA == (Fix64)0 && cosA < -Fix64.One / (Fix64)2)
            {
                return((Fix64)Fix64.Pi);
            }
            Fix64 temAngle = (Fix64)Fix64.Sign(sinA) * (Fix64)Fix64.Acos(cosA);

            return(temAngle);
        }
예제 #8
0
        protected internal override void UpdateJacobiansAndVelocityBias()
        {
            linearJacobianA = linearJacobianB = new Matrix3x3();


            //There are two free axes and one restricted axis.
            //The constraint attempts to keep the hinge axis attached to connection A and the twist axis attached to connection B perpendicular to each other.
            //The restricted axis is the cross product between the twist and hinge axes.

            Vector3 worldTwistAxis, worldHingeAxis;

            Quaternion.Transform(ref LocalHingeAxis, ref ConnectionA.Orientation, out worldHingeAxis);
            Quaternion.Transform(ref LocalTwistAxis, ref ConnectionB.Orientation, out worldTwistAxis);

            Vector3 restrictedAxis;

            Vector3.Cross(ref worldHingeAxis, ref worldTwistAxis, out restrictedAxis);
            //Attempt to normalize the restricted axis.
            Fix64 lengthSquared = restrictedAxis.LengthSquared();

            if (lengthSquared > Toolbox.Epsilon)
            {
                Vector3.Divide(ref restrictedAxis, Fix64.Sqrt(lengthSquared), out restrictedAxis);
            }
            else
            {
                restrictedAxis = new Vector3();
            }


            angularJacobianA = new Matrix3x3
            {
                M11 = restrictedAxis.X,
                M12 = restrictedAxis.Y,
                M13 = restrictedAxis.Z,
            };
            Matrix3x3.Negate(ref angularJacobianA, out angularJacobianB);

            Fix64 error;

            Vector3.Dot(ref worldHingeAxis, ref worldTwistAxis, out error);
            error = Fix64.Acos(MathHelper.Clamp(error, -1, F64.C1)) - MathHelper.PiOver2;

            velocityBias = new Vector3(errorCorrectionFactor * error, F64.C0, F64.C0);
        }
예제 #9
0
        protected internal override void UpdateJacobiansAndVelocityBias()
        {
            //This constraint doesn't consider linear motion.
            linearJacobianA = linearJacobianB = new Matrix3x3();

            //Compute the world axes.
            Vector3 axisA, axisB;

            Quaternion.Transform(ref LocalAxisA, ref ConnectionA.Orientation, out axisA);
            Quaternion.Transform(ref LocalAxisB, ref ConnectionB.Orientation, out axisB);

            Fix64 dot;

            Vector3.Dot(ref axisA, ref axisB, out dot);

            //Yes, we could avoid this acos here. Performance is not the highest goal of this system; the less tricks used, the easier it is to understand.
            // TODO investigate performance
            Fix64 angle = Fix64.Acos(MathHelper.Clamp(dot, -1, F64.C1));

            //One angular DOF is constrained by this limit.
            Vector3 hingeAxis;

            Vector3.Cross(ref axisA, ref axisB, out hingeAxis);

            angularJacobianA = new Matrix3x3 {
                M11 = hingeAxis.X, M12 = hingeAxis.Y, M13 = hingeAxis.Z
            };
            angularJacobianB = new Matrix3x3 {
                M11 = -hingeAxis.X, M12 = -hingeAxis.Y, M13 = -hingeAxis.Z
            };

            //Note how we've computed the jacobians despite the limit being potentially inactive.
            //This is to enable 'speculative' limits.
            if (angle >= maximumAngle)
            {
                velocityBias = new Vector3(errorCorrectionFactor * (angle - maximumAngle), F64.C0, F64.C0);
            }
            else
            {
                //The constraint is not yet violated. But, it may be- allow only as much motion as could occur without violating the constraint.
                //Limits can't 'pull,' so this will not result in erroneous sticking.
                velocityBias = new Vector3(angle - maximumAngle, F64.C0, F64.C0);
            }
        }
예제 #10
0
    public static Fix64 Angle(FractionalHex origin, FractionalHex direction, FractionalHex x, bool inRadians = true)
    {
        var diference = x - origin;

        direction = direction.Normalized();

        var adjacent   = DotProduct(direction, diference);
        var hipotenuse = diference.Magnitude();
        var cos        = hipotenuse != Fix64.Zero? adjacent / hipotenuse: Fix64.One;

        cos = cos.Clamp(Fix64.One, -Fix64.One);

        if (inRadians)
        {
            return(Fix64.Acos(cos));
        }
        else
        {
            return(Fix64.Acos(Fix64.Degrees(cos)));
        }
    }
예제 #11
0
        /// <summary>
        /// Blends two quaternions together to get an intermediate state.
        /// </summary>
        /// <param name="start">Starting point of the interpolation.</param>
        /// <param name="end">Ending point of the interpolation.</param>
        /// <param name="interpolationAmount">Amount of the end point to use.</param>
        /// <param name="result">Interpolated intermediate quaternion.</param>
        public static void Slerp(ref Quaternion start, ref Quaternion end, Fix64 interpolationAmount, out Quaternion result)
        {
            Fix64 cosHalfTheta = start.W * end.W + start.X * end.X + start.Y * end.Y + start.Z * end.Z;

            if (cosHalfTheta < F64.C0)
            {
                //Negating a quaternion results in the same orientation,
                //but we need cosHalfTheta to be positive to get the shortest path.
                end.X        = -end.X;
                end.Y        = -end.Y;
                end.Z        = -end.Z;
                end.W        = -end.W;
                cosHalfTheta = -cosHalfTheta;
            }
            // If the orientations are similar enough, then just pick one of the inputs.
            if (cosHalfTheta > F64.C1m1em12)
            {
                result.W = start.W;
                result.X = start.X;
                result.Y = start.Y;
                result.Z = start.Z;
                return;
            }
            // Calculate temporary values.
            Fix64 halfTheta    = Fix64.Acos(cosHalfTheta);
            Fix64 sinHalfTheta = Fix64.Sqrt(F64.C1 - cosHalfTheta * cosHalfTheta);

            Fix64 aFraction = Fix64.Sin((F64.C1 - interpolationAmount) * halfTheta) / sinHalfTheta;
            Fix64 bFraction = Fix64.Sin(interpolationAmount * halfTheta) / sinHalfTheta;

            //Blend the two quaternions to get the result!
            result.X = (Fix64)(start.X * aFraction + end.X * bFraction);
            result.Y = (Fix64)(start.Y * aFraction + end.Y * bFraction);
            result.Z = (Fix64)(start.Z * aFraction + end.Z * bFraction);
            result.W = (Fix64)(start.W * aFraction + end.W * bFraction);
        }
예제 #12
0
    public static FixQuaternion RotateTowards(FixQuaternion from, FixQuaternion to, Fix64 maxDegreesDelta)
    {
        Fix64 dot = Dot(from, to);

        if (dot < 0.0f)
        {
            to  = Multiply(to, -1);
            dot = -dot;
        }

        Fix64 halfTheta = Fix64.Acos(dot);
        Fix64 theta     = halfTheta * 2;

        maxDegreesDelta *= Fix64.Deg2Rad;

        if (maxDegreesDelta >= theta)
        {
            return(to);
        }

        maxDegreesDelta /= theta;

        return(Multiply(Multiply(from, Fix64.Sin((1 - maxDegreesDelta) * halfTheta)) + Multiply(to, Fix64.Sin(maxDegreesDelta * halfTheta)), 1 / Fix64.Sin(halfTheta)));
    }
예제 #13
0
        protected internal override void UpdateJacobiansAndVelocityBias()
        {
            //This constraint doesn't consider linear motion.
            linearJacobianA = linearJacobianB = new Matrix3x3();

            //Compute the world axes.
            Vector3 axisA, axisB;

            Quaternion.Transform(ref LocalAxisA, ref ConnectionA.Orientation, out axisA);
            Quaternion.Transform(ref LocalAxisB, ref ConnectionB.Orientation, out axisB);

            Vector3 twistMeasureAxisA, twistMeasureAxisB;

            Quaternion.Transform(ref LocalMeasurementAxisA, ref ConnectionA.Orientation, out twistMeasureAxisA);
            Quaternion.Transform(ref LocalMeasurementAxisB, ref ConnectionB.Orientation, out twistMeasureAxisB);

            //Compute the shortest rotation to bring axisB into alignment with axisA.
            Quaternion alignmentRotation;

            Quaternion.GetQuaternionBetweenNormalizedVectors(ref axisB, ref axisA, out alignmentRotation);

            //Transform the measurement axis on B by the alignment quaternion.
            Quaternion.Transform(ref twistMeasureAxisB, ref alignmentRotation, out twistMeasureAxisB);

            //We can now compare the angle between the twist axes.
            Fix64 error;

            Vector3.Dot(ref twistMeasureAxisA, ref twistMeasureAxisB, out error);
            error = Fix64.Acos(MathHelper.Clamp(error, -1, F64.C1));
            Vector3 cross;

            Vector3.Cross(ref twistMeasureAxisA, ref twistMeasureAxisB, out cross);
            Fix64 dot;

            Vector3.Dot(ref cross, ref axisA, out dot);
            if (dot < F64.C0)
            {
                error = -error;
            }

            //Compute the bias based upon the error.
            velocityBias = new Vector3(errorCorrectionFactor * error, F64.C0, F64.C0);

            //We can't just use the axes directly as jacobians. Consider 'cranking' one object around the other.
            Vector3 jacobian;

            Vector3.Add(ref axisA, ref axisB, out jacobian);
            Fix64 lengthSquared = jacobian.LengthSquared();

            if (lengthSquared > Toolbox.Epsilon)
            {
                Vector3.Divide(ref jacobian, Fix64.Sqrt(lengthSquared), out jacobian);
            }
            else
            {
                //The constraint is in an invalid configuration. Just ignore it.
                jacobian = new Vector3();
            }

            angularJacobianA = new Matrix3x3 {
                M11 = jacobian.X, M12 = jacobian.Y, M13 = jacobian.Z
            };
            angularJacobianB = new Matrix3x3 {
                M11 = -jacobian.X, M12 = -jacobian.Y, M13 = -jacobian.Z
            };
        }
예제 #14
0
 public static Fix64 AngleFromTo(SVector3 a, SVector3 b)
 {
     return((Fix64)Fix64.Acos(Dot(a.normalized, b.normalized)));
 }
예제 #15
0
 public static Fix64 Angle(FixVector2 a, FixVector2 b)
 {
     return(Fix64.Acos(a.Normalized * b.Normalized) * Fix64.Rad2Deg);
 }
예제 #16
0
 /// <summary>
 /// Returns the arc cosine of value.
 /// </summary>
 public static Fix64 Acos(Fix64 value)
 {
     return(Fix64.Acos(value));
 }
예제 #17
0
        protected internal override void UpdateJacobiansAndVelocityBias()
        {
            //This constraint doesn't consider linear motion.
            linearJacobianA = linearJacobianB = new Matrix3x3();

            //Compute the world axes.
            Vector3 axisA, axisB;

            Quaternion.Transform(ref LocalAxisA, ref ConnectionA.Orientation, out axisA);
            Quaternion.Transform(ref LocalAxisB, ref ConnectionB.Orientation, out axisB);

            Vector3 twistMeasureAxisA, twistMeasureAxisB;

            Quaternion.Transform(ref LocalMeasurementAxisA, ref ConnectionA.Orientation, out twistMeasureAxisA);
            Quaternion.Transform(ref LocalMeasurementAxisB, ref ConnectionB.Orientation, out twistMeasureAxisB);

            //Compute the shortest rotation to bring axisB into alignment with axisA.
            Quaternion alignmentRotation;

            Quaternion.GetQuaternionBetweenNormalizedVectors(ref axisB, ref axisA, out alignmentRotation);

            //Transform the measurement axis on B by the alignment quaternion.
            Quaternion.Transform(ref twistMeasureAxisB, ref alignmentRotation, out twistMeasureAxisB);

            //We can now compare the angle between the twist axes.
            Fix64 angle;

            Vector3.Dot(ref twistMeasureAxisA, ref twistMeasureAxisB, out angle);
            angle = Fix64.Acos(MathHelper.Clamp(angle, -1, F64.C1));

            //Compute the bias based upon the error.
            if (angle > maximumAngle)
            {
                velocityBias = new Vector3(errorCorrectionFactor * (angle - maximumAngle), F64.C0, F64.C0);
            }
            else //If the constraint isn't violated, set up the velocity bias to allow a 'speculative' limit.
            {
                velocityBias = new Vector3(angle - maximumAngle, F64.C0, F64.C0);
            }

            //We can't just use the axes directly as jacobians. Consider 'cranking' one object around the other.
            Vector3 jacobian;

            Vector3.Add(ref axisA, ref axisB, out jacobian);
            Fix64 lengthSquared = jacobian.LengthSquared();

            if (lengthSquared > Toolbox.Epsilon)
            {
                Vector3.Divide(ref jacobian, Fix64.Sqrt(lengthSquared), out jacobian);
            }
            else
            {
                //The constraint is in an invalid configuration. Just ignore it.
                jacobian = new Vector3();
            }

            //In addition to the absolute angle value, we need to know which side of the limit we're hitting.
            //The jacobian will be negated on one side. This is because limits can only 'push' in one direction;
            //if we didn't flip the direction of the jacobian, it would be trying to push the same direction on both ends of the limit.
            //One side would end up doing nothing!
            Vector3 cross;

            Vector3.Cross(ref twistMeasureAxisA, ref twistMeasureAxisB, out cross);
            Fix64 limitSide;

            Vector3.Dot(ref cross, ref axisA, out limitSide);
            //Negate the jacobian based on what side of the limit we're on.
            if (limitSide < F64.C0)
            {
                Vector3.Negate(ref jacobian, out jacobian);
            }

            angularJacobianA = new Matrix3x3 {
                M11 = jacobian.X, M12 = jacobian.Y, M13 = jacobian.Z
            };
            angularJacobianB = new Matrix3x3 {
                M11 = -jacobian.X, M12 = -jacobian.Y, M13 = -jacobian.Z
            };
        }