public void SamplingKeyFrames()
        {
            var keyFrame0 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(1.0), _random.NextQuaternionF());
            var keyFrame1 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(2.0), _random.NextQuaternionF());
            var keyFrame2 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(3.0), _random.NextQuaternionF());
            var animation = new QuaternionFKeyFrameAnimation();

            animation.KeyFrames.Add(keyFrame0);
            animation.KeyFrames.Add(keyFrame1);
            animation.KeyFrames.Add(keyFrame2);

            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            // Without interpolation
            animation.EnableInterpolation = false;
            Assert.AreEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(1.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame1.Value, animation.GetValue(TimeSpan.FromSeconds(2.0), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame1.Value, animation.GetValue(TimeSpan.FromSeconds(2.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame2.Value, animation.GetValue(TimeSpan.FromSeconds(3.0), defaultSource, defaultTarget));

            // With interpolation
            animation.EnableInterpolation = true;
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget)));
            var expected = InterpolationHelper.Lerp(keyFrame0.Value, keyFrame1.Value, 0.75f);

            Assert.AreEqual(expected, animation.GetValue(TimeSpan.FromSeconds(1.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame1.Value, animation.GetValue(TimeSpan.FromSeconds(2.0), defaultSource, defaultTarget));
            expected = InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.75f);
            Assert.AreEqual(expected, animation.GetValue(TimeSpan.FromSeconds(2.75), defaultSource, defaultTarget));
            Assert.AreEqual(keyFrame2.Value, animation.GetValue(TimeSpan.FromSeconds(3.0), defaultSource, defaultTarget));
        }
        public void CyclicOffsetLoopBehavior()
        {
            var keyFrame0 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(0.0), _random.NextQuaternionF());
            var keyFrame1 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(1.0), _random.NextQuaternionF());
            var keyFrame2 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(2.0), _random.NextQuaternionF());
            var animation = new QuaternionFKeyFrameAnimation();

            animation.KeyFrames.Add(keyFrame0);
            animation.KeyFrames.Add(keyFrame1);
            animation.KeyFrames.Add(keyFrame2);

            var animationClip = new AnimationClip <QuaternionF> {
                Animation = animation
            };

            animationClip.LoopBehavior = LoopBehavior.CycleOffset;
            animationClip.Duration     = TimeSpan.MaxValue;
            animationClip.ClipOffset   = TimeSpan.FromSeconds(-1);

            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            // Pre loop
            var cycleOffset = keyFrame2.Value * keyFrame0.Value.Inverse;
            var expected    = InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.25f);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, cycleOffset * animationClip.GetValue(TimeSpan.FromSeconds(0.25), defaultSource, defaultTarget)));

            // Post loop
            expected = cycleOffset * cycleOffset * InterpolationHelper.Lerp(keyFrame1.Value, keyFrame2.Value, 0.75f);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, animationClip.GetValue(TimeSpan.FromSeconds(6.75), defaultSource, defaultTarget)));
        }
Example #3
0
        public void Power3()
        {
            const float θ = 0.4f;
            Vector3F    v = new Vector3F(2.3f, 1.0f, -2.0f);

            v.Normalize();

            QuaternionF q  = new QuaternionF((float)Math.Cos(θ), (float)Math.Sin(θ) * v);
            QuaternionF q2 = q;

            q2.Power(2);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q * q, q2));
            QuaternionF q3 = q;

            q3.Power(3);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q * q * q, q3));

            q2 = q;
            q2.Power(-2);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q.Inverse * q.Inverse, q2));

            q3 = q;
            q3.Power(-3);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q.Inverse * q.Inverse * q.Inverse, q3));
        }
Example #4
0
        public void InterpolateTest()
        {
            SrtTransform a = new SrtTransform(new Vector3F(1, 2, 3), new QuaternionF(1, 2, 3, 4).Normalized, new Vector3F(4, 5, 6));
            SrtTransform b = a;

            var c = SrtTransform.Interpolate(a, b, 0.5f);

            Assert.AreEqual(a, c);

            b = new SrtTransform(new Vector3F(7, 9, 8), new QuaternionF(6, 6, 4, 2).Normalized, new Vector3F(-2, 4, -9));
            c = SrtTransform.Interpolate(a, b, 0);
            Assert.AreEqual(a, c);

            c = SrtTransform.Interpolate(a, b, 1);
            Assert.AreEqual(b, c);

            c = SrtTransform.Interpolate(a, b, 0.3f);
            Assert.AreEqual(a.Translation * 0.7f + b.Translation * 0.3f, c.Translation);
            Assert.AreEqual(a.Scale * 0.7f + b.Scale * 0.3f, c.Scale);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(
                              new QuaternionF(
                                  a.Rotation.W * 0.7f + b.Rotation.W * 0.3f,
                                  a.Rotation.V * 0.7f + b.Rotation.V * 0.3f).Normalized,
                              c.Rotation));
        }
Example #5
0
        public void CycleOffsetTest()
        {
            // IAnimationValueTraits<T> is used in a cyclic animation to a add the cycle offset in
            // each iteration.

            var traits             = QuaternionTraits.Instance;
            var first              = (Quaternion)_random.NextQuaternionF(); // Animation value of first key frame.
            var last               = (Quaternion)_random.NextQuaternionF(); // Animation value of last key frame.
            var cycleOffset        = traits.Add(traits.Inverse(first), last);
            var cycleOffsetInverse = cycleOffset;

            cycleOffsetInverse.Conjugate();

            // Cycle offset should be the difference between last and first key frame.
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)last, (QuaternionF)traits.Add(first, cycleOffset)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)last, (QuaternionF)(cycleOffset * first)));

            // Check multiple cycles (post-loop).
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)last, (QuaternionF)traits.Add(first, traits.Multiply(cycleOffset, 1))));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)cycleOffset * (QuaternionF)cycleOffset * (QuaternionF)last, (QuaternionF)traits.Add(first, traits.Multiply(cycleOffset, 3))));

            // Check multiple cycles (pre-loop).
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)first, (QuaternionF)traits.Add(last, traits.Multiply(cycleOffset, -1))));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)cycleOffsetInverse * (QuaternionF)cycleOffsetInverse * (QuaternionF)first, (QuaternionF)traits.Add(last, traits.Multiply(cycleOffset, -3))));
        }
Example #6
0
        public void DivisionScalar()
        {
            float       s = 123.456f;
            QuaternionF q = new QuaternionF(1.0f, 2.0f, 3.0f, 4.0f);
            QuaternionF expectedResult = new QuaternionF(1.0f / s, 2.0f / s, 3.0f / s, 4.0f / s);
            QuaternionF result         = QuaternionF.Divide(q, s);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expectedResult, result));
        }
Example #7
0
        public void InterpolationTest()
        {
            var traits = QuaternionTraits.Instance;
            var value0 = (Quaternion)_random.NextQuaternionF();
            var value1 = (Quaternion)_random.NextQuaternionF();

            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)value0, (QuaternionF)traits.Interpolate(value0, value1, 0.0f)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)value1, (QuaternionF)traits.Interpolate(value0, value1, 1.0f)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp((QuaternionF)value0, (QuaternionF)value1, 0.75f), (QuaternionF)traits.Interpolate(value0, value1, 0.75f)));
        }
Example #8
0
        public void FromMatrixWithZeroTrace()
        {
            QuaternionF q;
            Matrix33F   m = new Matrix33F(0, 1, 0,
                                          0, 0, 1,
                                          1, 0, 0);

            q = QuaternionF.CreateRotation(m);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(new QuaternionF(-0.5f, 0.5f, 0.5f, 0.5f), q));
        }
Example #9
0
        public void XnaQuaternionMultiplication()
        {
            QuaternionF q1    = _random.NextQuaternionF();
            QuaternionF q2    = _random.NextQuaternionF();
            var         q1Xna = (Quaternion)q1;
            var         q2Xna = (Quaternion)q2;

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1 * q2, (QuaternionF)(q1Xna * q2Xna)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2 * q1, (QuaternionF)(q2Xna * q1Xna)));
        }
Example #10
0
        public void AreEqualWithEpsilon()
        {
            float       epsilon = 0.001f;
            QuaternionF q1      = new QuaternionF(1.0f, 2.0f, 3.0f, 4.0f);
            QuaternionF q2      = new QuaternionF(1.002f, 2.002f, 3.002f, 4.002f);
            QuaternionF q3      = new QuaternionF(1.0001f, 2.0001f, 3.0001f, 4.0001f);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, q1, epsilon));
            Assert.IsFalse(QuaternionF.AreNumericallyEqual(q1, q2, epsilon));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, q3, epsilon));
        }
Example #11
0
        public void Angle()
        {
            Vector3F    axis = new Vector3F(1.0f, 2.0f, 3.0f);
            QuaternionF q    = QuaternionF.CreateRotation(axis, 0.4f);

            Assert.IsTrue(Numeric.AreEqual(0.4f, q.Angle));
            q.Angle = 0.9f;
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q, QuaternionF.CreateRotation(axis, 0.9f)));

            Assert.AreEqual(0, new QuaternionF(1.000001f, 0, 0, 0).Angle);
        }
        public void MultiplyTest()
        {
            var traits = QuaternionFTraits.Instance;
            var value  = _random.NextQuaternionF();

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(QuaternionF.Identity, traits.Multiply(value, 0)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(value, traits.Multiply(value, 1)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(value * value, traits.Multiply(value, 2)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(value * value * value, traits.Multiply(value, 3)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(value.Inverse, traits.Multiply(value, -1)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(value.Inverse * value.Inverse, traits.Multiply(value, -2)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(value.Inverse * value.Inverse * value.Inverse, traits.Multiply(value, -3)));
        }
Example #13
0
        public void Power()
        {
            const float θ = 0.4f;
            const float t = -1.2f;
            Vector3F    v = new Vector3F(2.3f, 1.0f, -2.0f);

            v.Normalize();

            QuaternionF q        = new QuaternionF((float)Math.Cos(θ), (float)Math.Sin(θ) * v);
            QuaternionF power    = QuaternionF.Power(q, t);
            QuaternionF expected = new QuaternionF((float)Math.Cos(t * θ), (float)Math.Sin(t * θ) * v);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, power));
        }
        public void AnimateUsingDefaults()
        {
            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            var animation = new QuaternionFFromToByAnimation();

            animation.From = null;
            animation.To   = null;
            animation.By   = null;
            Assert.AreEqual(defaultSource, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp(defaultSource, defaultTarget, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
            Assert.AreEqual(defaultTarget, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
        }
Example #15
0
        public void MultiplyTest()
        {
            var        traits       = QuaternionTraits.Instance;
            var        value        = (Quaternion)_random.NextQuaternionF();
            Quaternion valueInverse = value;

            valueInverse.Conjugate();
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)Quaternion.Identity, (QuaternionF)traits.Multiply(value, 0)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)value, (QuaternionF)traits.Multiply(value, 1)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)(value * value), (QuaternionF)traits.Multiply(value, 2)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)(value * value * value), (QuaternionF)traits.Multiply(value, 3)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)valueInverse, (QuaternionF)traits.Multiply(value, -1)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)valueInverse * (QuaternionF)valueInverse, (QuaternionF)traits.Multiply(value, -2)));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)valueInverse * (QuaternionF)valueInverse * (QuaternionF)valueInverse, (QuaternionF)traits.Multiply(value, -3)));
        }
Example #16
0
        public void AreEqual()
        {
            float originalEpsilon = Numeric.EpsilonF;

            Numeric.EpsilonF = 1e-8f;

            QuaternionF q1 = new QuaternionF(1.0f, 2.0f, 3.0f, 4.0f);
            QuaternionF q2 = new QuaternionF(1.000001f, 2.000001f, 3.000001f, 4.000001f);
            QuaternionF q3 = new QuaternionF(1.00000001f, 2.00000001f, 3.00000001f, 4.00000001f);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, q1));
            Assert.IsFalse(QuaternionF.AreNumericallyEqual(q1, q2));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, q3));

            Numeric.EpsilonF = originalEpsilon;
        }
        public void ShouldIgnoreByIfToIsSet()
        {
            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();
            var to            = _random.NextQuaternionF();
            var by            = _random.NextQuaternionF();

            var animation = new QuaternionFFromToByAnimation();

            animation.From = null;
            animation.To   = to;
            animation.By   = by;
            Assert.AreEqual(defaultSource, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp(defaultSource, to, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
            Assert.AreEqual(to, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
        }
Example #18
0
        public void FromByTest()
        {
            // IAnimationValueTraits<T> is used in a from-by animation to a add a relative offset to
            // the start value.

            var traits = QuaternionTraits.Instance;
            var from   = (Quaternion)_random.NextQuaternionF();
            var by     = (Quaternion)_random.NextQuaternionF();

            var to = traits.Add(from, by);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)by * (QuaternionF)from, (QuaternionF)to));

            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)from, (QuaternionF)traits.Add(to, traits.Inverse(by))));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual((QuaternionF)by, (QuaternionF)traits.Add(traits.Inverse(from), to)));
        }
        public void SlerpSinglePrecision()
        {
            // Warning: The not all results are not verified
            QuaternionF q1    = new QuaternionF(1.0f, 2.0f, 3.0f, 4.0f).Normalized;
            QuaternionF q2    = new QuaternionF(2.0f, 4.0f, 6.0f, 8.0f).Normalized;
            QuaternionF slerp = InterpolationHelper.Slerp(q1, q2, 0.75f);

            Assert.IsTrue(slerp.IsNumericallyNormalized);

            slerp = InterpolationHelper.Slerp(q1, q2, 0);
            Assert.IsTrue(slerp.IsNumericallyNormalized);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, slerp));

            slerp = InterpolationHelper.Slerp(q1, q2, 1);
            Assert.IsTrue(slerp.IsNumericallyNormalized);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2, slerp));
        }
Example #20
0
        public void Interpolate()
        {
            Pose p1 = new Pose(new Vector3F(1, 2, 3), QuaternionF.CreateRotationY(0.3f));
            Pose p2 = new Pose(new Vector3F(-4, 5, -6), QuaternionF.CreateRotationZ(-0.1f));

            Assert.IsTrue(Vector3F.AreNumericallyEqual(p1.Position, Pose.Interpolate(p1, p2, 0).Position));
            Assert.IsTrue(Matrix33F.AreNumericallyEqual(p1.Orientation, Pose.Interpolate(p1, p2, 0).Orientation));

            Assert.IsTrue(Vector3F.AreNumericallyEqual(p2.Position, Pose.Interpolate(p1, p2, 1).Position));
            Assert.IsTrue(Matrix33F.AreNumericallyEqual(p2.Orientation, Pose.Interpolate(p1, p2, 1).Orientation));

            Assert.IsTrue(Vector3F.AreNumericallyEqual(InterpolationHelper.Lerp(p1.Position, p2.Position, 0.3f), Pose.Interpolate(p1, p2, 0.3f).Position));
            Assert.IsTrue(
                QuaternionF.AreNumericallyEqual(
                    InterpolationHelper.Lerp(QuaternionF.CreateRotation(p1.Orientation), QuaternionF.CreateRotation(p2.Orientation), 0.3f),
                    QuaternionF.CreateRotation(Pose.Interpolate(p1, p2, 0.3f).Orientation)));
        }
        public void LerpQuaternionF()
        {
            // Warning: The not all results are not verified
            QuaternionF q1   = new QuaternionF(1.0f, 2.0f, 3.0f, 4.0f).Normalized;
            QuaternionF q2   = new QuaternionF(2.0f, 4.0f, 6.0f, 8.0f).Normalized;
            QuaternionF lerp = InterpolationHelper.Lerp(q1, q2, 0.75f);

            Assert.IsTrue(lerp.IsNumericallyNormalized);

            lerp = InterpolationHelper.Lerp(q1, q2, 0);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, lerp));

            lerp = InterpolationHelper.Lerp(q1, q2, 1);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2, lerp));

            q1   = QuaternionF.Identity;
            q2   = QuaternionF.CreateRotation(Vector3F.UnitZ, (float)Math.PI / 2);
            lerp = InterpolationHelper.Lerp(q1, q2, 0.5f);
            Vector3F v      = lerp.Rotate(Vector3F.UnitX);
            Vector3F result = new Vector3F(1.0f, 1.0f, 0.0f).Normalized;

            Assert.IsTrue(Vector3F.AreNumericallyEqual(result, v));

            q1     = QuaternionF.Identity;
            q2     = QuaternionF.CreateRotation(Vector3F.UnitY, (float)Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5f);
            v      = lerp.Rotate(Vector3F.UnitZ);
            result = new Vector3F(1.0f, 0.0f, 1.0f).Normalized;
            Assert.IsTrue(Vector3F.AreNumericallyEqual(result, v));

            q1     = QuaternionF.Identity;
            q2     = QuaternionF.CreateRotation(Vector3F.UnitX, (float)Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5f);
            v      = lerp.Rotate(Vector3F.UnitY);
            result = new Vector3F(0.0f, 1.0f, 1.0f).Normalized;
            Assert.IsTrue(Vector3F.AreNumericallyEqual(result, v));

            q1     = new QuaternionF(-1.0f, 0.0f, 0.0f, 0.0f);
            q2     = QuaternionF.CreateRotation(-Vector3F.UnitZ, (float)-Math.PI / 2);
            lerp   = InterpolationHelper.Lerp(q1, q2, 0.5f);
            v      = lerp.Rotate(Vector3F.UnitX);
            result = new Vector3F(1.0f, 1.0f, 0.0f).Normalized;
            Assert.IsTrue(Vector3F.AreNumericallyEqual(result, v));
        }
Example #22
0
        public void FromToMatrixTest()
        {
            var t = new Vector3F(1, 2, 3);
            var r = new QuaternionF(1, 2, 3, 4).Normalized;
            var s = new Vector3F(2, 7, 9);
            var m = Matrix44F.CreateTranslation(t) * Matrix44F.CreateRotation(r) * Matrix44F.CreateScale(s);

            var srt = SrtTransform.FromMatrix(m);

            Assert.IsTrue(Vector3F.AreNumericallyEqual(t, srt.Translation));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(r, srt.Rotation));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(s, srt.Scale));

            // XNA:
            srt = SrtTransform.FromMatrix((Matrix)m);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(t, srt.Translation));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(r, srt.Rotation));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(s, srt.Scale));

            // With negative scale, the decomposition is not unique (many possible combinations of
            // axis mirroring + rotation).
            t   = new Vector3F(1, 2, 3);
            r   = new QuaternionF(1, 2, 3, 4).Normalized;
            s   = new Vector3F(2, -7, 9);
            m   = Matrix44F.CreateTranslation(t) * Matrix44F.CreateRotation(r) * Matrix44F.CreateScale(s);
            srt = SrtTransform.FromMatrix(m);
            var m2 = (Matrix44F)srt;

            Assert.IsTrue(Matrix44F.AreNumericallyEqual(m, m2));

            m2 = srt.ToMatrix44F();
            Assert.IsTrue(Matrix44F.AreNumericallyEqual(m, m2));

            m2 = srt;
            Assert.IsTrue(Matrix44F.AreNumericallyEqual(m, m2));

            Matrix mXna = srt.ToXna();

            Assert.IsTrue(Matrix44F.AreNumericallyEqual(m, (Matrix44F)mXna));

            mXna = srt;
            Assert.IsTrue(Matrix44F.AreNumericallyEqual(m, (Matrix44F)mXna));
        }
Example #23
0
        public void Inverse()
        {
            QuaternionF identity        = QuaternionF.Identity;
            QuaternionF inverseIdentity = identity.Inverse;

            Assert.AreEqual(inverseIdentity, identity);

            float    angle = 0.4f;
            Vector3F axis  = new Vector3F(1.0f, 1.0f, 1.0f);

            axis.Normalize();
            QuaternionF q       = QuaternionF.CreateRotation(axis, angle);
            QuaternionF inverse = q.Inverse;

            Assert.IsTrue(Vector3F.AreNumericallyEqual(-axis, inverse.Axis));

            q       = new QuaternionF(1, 2, 3, 4);
            inverse = q.Inverse;
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(QuaternionF.Identity, inverse * q));
        }
        public void ShouldReturnTheFirstOrLastKeyFrame()
        {
            var keyFrame0 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(1.0), _random.NextQuaternionF());
            var keyFrame1 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(2.0), _random.NextQuaternionF());
            var keyFrame2 = new KeyFrame <QuaternionF>(TimeSpan.FromSeconds(3.0), _random.NextQuaternionF());
            var animation = new QuaternionFKeyFrameAnimation();

            animation.KeyFrames.Add(keyFrame0);
            animation.KeyFrames.Add(keyFrame1);
            animation.KeyFrames.Add(keyFrame2);

            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();

            // Pre loop
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(keyFrame0.Value, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget)));

            // Post loop
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(keyFrame2.Value, animation.GetValue(TimeSpan.FromSeconds(3.75), defaultSource, defaultTarget)));
        }
        public void AnimateFromBy()
        {
            var defaultSource = _random.NextQuaternionF();
            var defaultTarget = _random.NextQuaternionF();
            var from          = _random.NextQuaternionF();
            var by            = _random.NextQuaternionF();

            var animation = new QuaternionFFromToByAnimation();

            animation.From = from;
            animation.To   = null;
            animation.By   = by;
            Assert.AreEqual(from, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp(from, by * from, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
            Assert.AreEqual(by * from, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));

            animation.By = by.Inverse;
            Assert.AreEqual(from, animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(InterpolationHelper.Lerp(from, by.Inverse * from, 0.75f), animation.GetValue(TimeSpan.FromSeconds(0.75), defaultSource, defaultTarget)));
            Assert.AreEqual(by.Inverse * from, animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));
        }
Example #26
0
        public void ConstructorTest()
        {
            var rotationQ = new QuaternionF(1, 2, 3, 4).Normalized;

            var srt = new SrtTransform(rotationQ.ToRotationMatrix33());

            Assert.AreEqual(Vector3F.One, srt.Scale);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(rotationQ, srt.Rotation));
            Assert.AreEqual(Vector3F.Zero, srt.Translation);

            srt = new SrtTransform(rotationQ);

            Assert.AreEqual(Vector3F.One, srt.Scale);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(rotationQ, srt.Rotation));
            Assert.AreEqual(Vector3F.Zero, srt.Translation);

            srt = new SrtTransform(new Vector3F(-1, 2, -3), rotationQ.ToRotationMatrix33(), new Vector3F(10, 9, -8));
            Assert.AreEqual(new Vector3F(-1, 2, -3), srt.Scale);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(rotationQ, srt.Rotation));
            Assert.AreEqual(new Vector3F(10, 9, -8), srt.Translation);
        }
        public void SquadSinglePrecision()
        {
            QuaternionF q0 = QuaternionF.CreateRotation(new Vector3F(1, 1, 1), 0.3f);
            QuaternionF q1 = QuaternionF.CreateRotation(new Vector3F(1, 0, 1), 0.4f);
            QuaternionF q2 = QuaternionF.CreateRotation(new Vector3F(1, 0, -1), -0.6f);
            QuaternionF q3 = QuaternionF.CreateRotation(new Vector3F(0, 1, 1), 0.2f);

            QuaternionF q, a, b, p;
            QuaternionF expected;

            InterpolationHelper.SquadSetup(q0, q1, q2, q3, out q, out a, out b, out p);

            // t = 0
            QuaternionF result = InterpolationHelper.Squad(q, a, b, p, 0.0f);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q1, result));

            // t = 1.0f
            result = InterpolationHelper.Squad(q, a, b, p, 1.0f);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2, result));

            // Check series (just for debugging)
            QuaternionF r1, r2, r3, r4, r5, r6, r7, r8, r9;

            r1 = InterpolationHelper.Squad(q, a, b, p, 0.1f);
            r2 = InterpolationHelper.Squad(q, a, b, p, 0.2f);
            r3 = InterpolationHelper.Squad(q, a, b, p, 0.3f);
            r4 = InterpolationHelper.Squad(q, a, b, p, 0.4f);
            r5 = InterpolationHelper.Squad(q, a, b, p, 0.5f);
            r6 = InterpolationHelper.Squad(q, a, b, p, 0.6f);
            r7 = InterpolationHelper.Squad(q, a, b, p, 0.7f);
            r8 = InterpolationHelper.Squad(q, a, b, p, 0.8f);
            r9 = InterpolationHelper.Squad(q, a, b, p, 0.9f);

            // q0 = q1, q2 = q3
            InterpolationHelper.SquadSetup(q1, q1, q2, q2, out q, out a, out b, out p);
            result   = InterpolationHelper.Squad(q, a, b, p, 0.5f);
            expected = InterpolationHelper.Slerp(q1, q2, 0.5f);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, result));
        }
        public void BlendTest()
        {
            var traits = SrtTransformTraits.Instance;

            var value0 = NextRandomValue();
            var value1 = NextRandomValue();
            var value2 = NextRandomValue();
            var w0     = 0.3f;
            var w1     = 0.4f;
            var w2     = 1 - w0 - w1;

            SrtTransform result = new SrtTransform();

            traits.BeginBlend(ref result);
            traits.BlendNext(ref result, ref value0, w0);
            traits.BlendNext(ref result, ref value1, w1);
            traits.BlendNext(ref result, ref value2, w2);
            traits.EndBlend(ref result);

            Assert.IsTrue(Vector3F.AreNumericallyEqual(value0.Scale * w0 + value1.Scale * w1 + value2.Scale * w2, result.Scale));
            Assert.IsTrue(Vector3F.AreNumericallyEqual(value0.Translation * w0 + value1.Translation * w1 + value2.Translation * w2, result.Translation));

            QuaternionF expected;

            expected = value0.Rotation * w0;
            // Consider "selective negation" when blending quaternions!
            if (QuaternionF.Dot(expected, value1.Rotation) < 0)
            {
                value1.Rotation = -value1.Rotation;
            }
            expected += value1.Rotation * w1;
            if (QuaternionF.Dot(expected, value2.Rotation) < 0)
            {
                value2.Rotation = -value2.Rotation;
            }
            expected += value2.Rotation * w2;
            expected.Normalize();

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, result.Rotation));
        }
Example #29
0
        public void CreateRotation()
        {
            QuaternionF q;

            // From matrix vs. from angle/axis
            Matrix33F m = Matrix33F.CreateRotation(Vector3F.UnitX, (float)Math.PI / 4);

            q = QuaternionF.CreateRotation(m);
            QuaternionF q2 = QuaternionF.CreateRotation(Vector3F.UnitX, (float)Math.PI / 4);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2, q));
            m  = Matrix33F.CreateRotation(Vector3F.UnitY, (float)Math.PI / 4);
            q  = QuaternionF.CreateRotation(m);
            q2 = QuaternionF.CreateRotation(Vector3F.UnitY, (float)Math.PI / 4);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2, q));
            m  = Matrix33F.CreateRotation(Vector3F.UnitZ, (float)Math.PI / 4);
            q  = QuaternionF.CreateRotation(m);
            q2 = QuaternionF.CreateRotation(Vector3F.UnitZ, (float)Math.PI / 4);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(q2, q));

            // From vector-vector
            Vector3F start, end;

            start = Vector3F.UnitX;
            end   = Vector3F.UnitY;
            q     = QuaternionF.CreateRotation(start, end);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(end, q.ToRotationMatrix33() * start));

            start = Vector3F.UnitY;
            end   = Vector3F.UnitZ;
            q     = QuaternionF.CreateRotation(start, end);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(end, q.ToRotationMatrix33() * start));

            start = Vector3F.UnitZ;
            end   = Vector3F.UnitX;
            q     = QuaternionF.CreateRotation(start, end);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(end, q.ToRotationMatrix33() * start));

            start = new Vector3F(1, 1, 1);
            end   = new Vector3F(1, 1, 1);
            q     = QuaternionF.CreateRotation(start, end);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(end, q.ToRotationMatrix33() * start));

            start = new Vector3F(1.0f, 1.0f, 1.0f);
            end   = new Vector3F(-1.0f, -1.0f, -1.0f);
            q     = QuaternionF.CreateRotation(start, end);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(end, q.ToRotationMatrix33() * start));

            start = new Vector3F(-1.0f, 2.0f, 1.0f);
            end   = new Vector3F(-2.0f, -1.0f, -1.0f);
            q     = QuaternionF.CreateRotation(start, end);
            Assert.IsTrue(Vector3F.AreNumericallyEqual(end, q.ToRotationMatrix33() * start));

            float degree45 = MathHelper.ToRadians(45);

            q = QuaternionF.CreateRotation(degree45, Vector3F.UnitZ, degree45, Vector3F.UnitY, degree45, Vector3F.UnitX, false);
            QuaternionF expected = QuaternionF.CreateRotation(Vector3F.UnitZ, degree45) * QuaternionF.CreateRotation(Vector3F.UnitY, degree45)
                                   * QuaternionF.CreateRotation(Vector3F.UnitX, degree45);

            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, q));

            q        = QuaternionF.CreateRotation(degree45, Vector3F.UnitZ, degree45, Vector3F.UnitY, degree45, Vector3F.UnitX, true);
            expected = QuaternionF.CreateRotation(Vector3F.UnitX, degree45) * QuaternionF.CreateRotation(Vector3F.UnitY, degree45)
                       * QuaternionF.CreateRotation(Vector3F.UnitZ, degree45);
            Assert.IsTrue(QuaternionF.AreNumericallyEqual(expected, q));
        }
Example #30
0
        /// <summary>
        /// Compresses the specified animation using simple lossy compression algorithm.
        /// </summary>
        /// <param name="animation">The animation.</param>
        /// <param name="scaleThreshold">The scale threshold.</param>
        /// <param name="rotationThreshold">The rotation threshold in degrees.</param>
        /// <param name="translationThreshold">The translation threshold.</param>
        /// <returns>
        /// The compressed animation. Or <see langword="null"/> if the animation does contain any
        /// key frames.
        /// </returns>
        /// <remarks>
        /// <para>
        /// This method takes an <see cref="SrtKeyFrameAnimation"/> and removes not needed scale,
        /// rotation or translation channels. It further removes key frames that can be interpolated
        /// from the neighbor key frames. This a lossy compression and the threshold parameters define
        /// the allowed errors. If the thresholds are 0 or negative, this compression is lossless. If
        /// the thresholds are greater than 0 (recommended), the compression is lossy. The best way to
        /// determine optimal thresholds is to compare the compressed animation with the uncompressed
        /// animation visually.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="animation" /> is <see langword="null"/>.
        /// </exception>
        public static SrtAnimation Compress(SrtKeyFrameAnimation animation, float scaleThreshold, float rotationThreshold, float translationThreshold)
        {
            if (animation == null)
            {
                throw new ArgumentNullException("animation");
            }

            var keyFrames = animation.KeyFrames;

            if (keyFrames.Count == 0)
            {
                // Empty animation.
                return(null);
            }

            var animationEx = new SrtAnimation
            {
                FillBehavior   = animation.FillBehavior,
                IsAdditive     = animation.IsAdditive,
                TargetObject   = animation.TargetObject,
                TargetProperty = animation.TargetProperty,
            };

            Vector3FKeyFrameAnimation    scaleAnimation       = null;
            QuaternionFKeyFrameAnimation rotationAnimation    = null;
            Vector3FKeyFrameAnimation    translationAnimation = null;

            // Create Scale channel if required.
            foreach (var keyFrame in keyFrames)
            {
                if (!Vector3F.AreNumericallyEqual(keyFrame.Value.Scale, Vector3F.One))
                {
                    scaleAnimation = new Vector3FKeyFrameAnimation();
                    break;
                }
            }

            // Create Rotation channel if required.
            foreach (var keyFrame in keyFrames)
            {
                if (!QuaternionF.AreNumericallyEqual(keyFrame.Value.Rotation, QuaternionF.Identity))
                {
                    rotationAnimation = new QuaternionFKeyFrameAnimation();
                    break;
                }
            }

            // Create Translation channel if required.
            foreach (var keyFrame in keyFrames)
            {
                if (!keyFrame.Value.Translation.IsNumericallyZero)
                {
                    translationAnimation = new Vector3FKeyFrameAnimation();
                    break;
                }
            }

            if (scaleAnimation == null && rotationAnimation == null && translationAnimation == null)
            {
                // The animation does not contain any transformations. However, the keyframe times (start
                // and end) may be relevant.
                translationAnimation = new Vector3FKeyFrameAnimation();
            }

            if (keyFrames.Count <= 2)
            {
                // Add first keyframe.
                {
                    Debug.Assert(keyFrames.Count > 0);

                    var keyFrame = keyFrames[0];
                    if (scaleAnimation != null)
                    {
                        scaleAnimation.KeyFrames.Add(new KeyFrame <Vector3F>(keyFrame.Time, keyFrame.Value.Scale));
                    }

                    if (rotationAnimation != null)
                    {
                        rotationAnimation.KeyFrames.Add(new KeyFrame <QuaternionF>(keyFrame.Time, keyFrame.Value.Rotation));
                    }

                    if (translationAnimation != null)
                    {
                        translationAnimation.KeyFrames.Add(new KeyFrame <Vector3F>(keyFrame.Time, keyFrame.Value.Translation));
                    }
                }

                // Add second (last) keyframe.
                if (keyFrames.Count > 1)
                {
                    Debug.Assert(keyFrames.Count == 2);

                    var keyFrame = keyFrames[1];
                    if (scaleAnimation != null)
                    {
                        scaleAnimation.KeyFrames.Add(new KeyFrame <Vector3F>(keyFrame.Time, keyFrame.Value.Scale));
                    }

                    if (rotationAnimation != null)
                    {
                        rotationAnimation.KeyFrames.Add(new KeyFrame <QuaternionF>(keyFrame.Time, keyFrame.Value.Rotation));
                    }

                    if (translationAnimation != null)
                    {
                        translationAnimation.KeyFrames.Add(new KeyFrame <Vector3F>(keyFrame.Time, keyFrame.Value.Translation));
                    }
                }
            }
            else
            {
                // Animation has more than 2 keyframes.
                // --> Compress animation.
                if (scaleAnimation != null)
                {
                    Compress(animation, scaleAnimation, scaleThreshold, keyFrame => keyFrame.Value.Scale, ComputeError);
                }

                if (rotationAnimation != null)
                {
                    Compress(animation, rotationAnimation, MathHelper.ToRadians(rotationThreshold), keyFrame => keyFrame.Value.Rotation, ComputeError);
                }

                if (translationAnimation != null)
                {
                    Compress(animation, translationAnimation, translationThreshold, keyFrame => keyFrame.Value.Translation, ComputeError);
                }
            }

            animationEx.Scale       = scaleAnimation;
            animationEx.Rotation    = rotationAnimation;
            animationEx.Translation = translationAnimation;

            return(animationEx);
        }