示例#1
0
        /// <summary>
        /// Decomposes a transformation into a scale, rotation and translation component.
        /// NOTE: The input is assumed to be a valid affine transformation.
        ///       The rotation output is in Euler-Angles (yaw, pitch, roll).
        /// </summary>
        public static void Decompose(this Trafo3d trafo, out V3d scale, out V3d rotation, out V3d translation)
        {
            translation = trafo.GetModelOrigin();

            var rt = trafo.GetOrthoNormalOrientation();

            if (rt.Forward.Det.IsTiny())
            {
                rotation = V3d.Zero;
            }
            else
            {
                var rot = Rot3d.FromFrame(rt.Forward.C0.XYZ, rt.Forward.C1.XYZ, rt.Forward.C2.XYZ);
                rotation = rot.GetEulerAngles();
            }

            scale = trafo.GetScaleVector();

            // if matrix is left-handed there must be some negative scale
            // since rotation remains the x-axis, the y-axis must be flipped
            if (trafo.Forward.Det < 0)
            {
                scale.Y = -scale.Y;
            }
        }
示例#2
0
        void TestDecompose(Trafo3d trafo, Rot3d jitter)
        {
            var x = (M44d)jitter;

            trafo = trafo * new Trafo3d(x, x.Inverse);

            V3d r_d, s_d, t_d;

            trafo.Decompose(out s_d, out r_d, out t_d);

            var recomposed = Trafo3d.FromComponents(s_d, r_d, t_d);

            Assert.IsFalse(s_d.AnyNaN || r_d.AnyNaN || t_d.AnyNaN, "something NaN");

            var dt = trafo.Forward - recomposed.Forward;
            var e  = dt.NormMax.Abs();

            Assert.IsTrue(e < 1e-9, "DIFF");

            var eq = CheckForwardBackwardConsistency(new Trafo3d(trafo.Forward, recomposed.Backward)) &&
                     CheckForwardBackwardConsistency(new Trafo3d(recomposed.Forward, trafo.Backward));



            Assert.True(eq, "trafo not consistent");
        }
示例#3
0
        public static void FromInto()
        {
            TrafoTesting.GenericTest(rnd =>
            {
                var dir   = rnd.UniformV3d().Normalized;
                var rotId = Rot3d.RotateInto(dir, dir);
                var matId = (M33d)rotId;

                Assert.IsTrue(matId.IsIdentity(0));

                var rot    = Rot3d.RotateInto(dir, -dir);
                var invDir = rot.Transform(dir);

                Assert.IsTrue(invDir.ApproximateEquals(-dir, 1e-14));

                var dirF   = rnd.UniformV3f().Normalized;
                var rotIdF = Rot3f.RotateInto(dirF, dirF);
                var matIdF = (M33f)rotIdF;

                Assert.IsTrue(matIdF.IsIdentity(0));

                var rotF    = Rot3f.RotateInto(dirF, -dirF);
                var invDirF = rotF.Transform(dirF);

                Assert.IsTrue(invDirF.ApproximateEquals(-dirF, 1e-6f));
            });
        }
示例#4
0
        public static void FromEuler()
        {
            TrafoTesting.GenericTest(rnd =>
            {
                var euler = rnd.UniformV3dFull() * Constant.PiTimesFour - Constant.PiTimesTwo;

                var rot = Rot3d.RotationEuler(euler);

                var qx   = Rot3d.RotationX(euler.X);
                var qy   = Rot3d.RotationY(euler.Y);
                var qz   = Rot3d.RotationZ(euler.Z);
                var test = qz * qy * qx;

                TrafoTesting.AreEqual(rot, test);

                var euler2 = rot.GetEulerAngles();
                var rot2   = Rot3d.RotationEuler(euler2);

                var rot2M = (M33d)rot2;
                var rotM  = (M33d)rot;

                if (!Fun.ApproximateEquals(rot2M, rotM, 1e-6))
                {
                    Report.Line("FA");
                }

                Assert.IsTrue(Fun.ApproximateEquals(rot2M, rotM, 1e-6));
            });
        }
        static V3d InvTransformUsingQuaternionOpt(Rot3d rot, V3d v)
        {
            // TODO
            // Multiply(a, b)
            //return new Rot3d(
            //    a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z,
            //    a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y,
            //    a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z,
            //    a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X
            //    );

            // rot.Conungated * Rot3d(0, v)
            var q = new QuaternionD(
                +rot.X * v.X + rot.Y * v.Y + rot.Z * v.Z,
                rot.W * v.X - rot.Y * v.Z + rot.Z * v.Y,
                rot.W * v.Y - rot.Z * v.X + rot.X * v.Z,
                rot.W * v.Z - rot.X * v.Y + rot.Y * v.X);

            // q * rot

            return(new V3d(
                       q.W * rot.X + q.X * rot.W + q.Y * rot.Z - q.Z * rot.Y,
                       q.W * rot.Y + q.Y * rot.W + q.Z * rot.X - q.X * rot.Z,
                       q.W * rot.Z + q.Z * rot.W + q.X * rot.Y - q.Y * rot.X
                       ));
        }
示例#6
0
        public static Trafo3d RotateInto(V3d from, V3d into)
        {
            var rot = new Rot3d(from, into);
            var inv = rot.Inverse;

            return(new Trafo3d((M44d)rot, (M44d)inv));
        }
示例#7
0
 /// <summary>
 /// Multiplies 2 Similarity transformations.
 /// This concatenates the two similarity transformations into a single one, first b is applied, then a.
 /// Attention: Multiplication is NOT commutative!
 /// </summary>
 public static Similarity3d Multiply(Similarity3d a, Similarity3d b)
 {
     //a.Scale * b.Scale, a.Rot * b.Rot, a.Trans + a.Rot * a.Scale * b.Trans
     return(new Similarity3d(a.Scale * b.Scale, new Euclidean3d(
                                 Rot3d.Multiply(a.Rot, b.Rot),
                                 a.Trans + a.Rot.TransformDir(a.Scale * b.Trans))
                             ));
 }
示例#8
0
        /// <summary>
        /// Spherical linear interpolation.
        ///
        /// Assumes q1 and q2 are normalized and that t in [0,1].
        ///
        /// This method does interpolate along the shortest arc
        /// between q1 and q2.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="t">[0,1]</param>
        /// <returns>Interpolant</returns>
        public static Rot3d SlerpShortest(
            Rot3d a, Rot3d b, double t
            )
        {
            Rot3d  q3       = b;
            double cosomega = Rot3d.Dot(a, q3);

            if (cosomega < 0.0)
            {
                cosomega = -cosomega;
                q3       = -q3;
            }

            if (cosomega >= 1.0)
            {
                // Special case: q1 and q2 are the same, so just return one of them.
                // This also catches the case where cosomega is very slightly > 1.0

                return(a);
            }

            double sinomega = (1 - cosomega * cosomega).Sqrt();

            Rot3d result;

            if (sinomega * double.MaxValue > 1)
            {
                double omega = cosomega.Acos();
                double s1    = ((1.0 - t) * omega).Sin() / sinomega;
                double s2    = (t * omega).Sin() / sinomega;

                result = s1 * a + s2 * q3;
            }
            else if (cosomega > 0)
            {
                // omega == 0

                double s1 = 1.0 - t;
                double s2 = t;

                result = s1 * a + s2 * q3;
            }
            else
            {
                // omega == -pi

                result = new Rot3d(a.Z, -a.Y, a.X, -a.W);

                double s1 = ((0.5 - t) * Constant.Pi).Sin();
                double s2 = (t * Constant.Pi).Sin();

                result = s1 * a + s2 * result;
            }

            return(result);
        }
        static V3d TransformUsingQuaternionOpt2(Rot3d rot, V3d v)
        {
            // rot * Rot3d(0, v)
            var W = -rot.X * v.X - rot.Y * v.Y - rot.Z * v.Z;
            var X = rot.W * v.X + rot.Y * v.Z - rot.Z * v.Y;
            var Y = rot.W * v.Y + rot.Z * v.X - rot.X * v.Z;
            var Z = rot.W * v.Z + rot.X * v.Y - rot.Y * v.X;

            // q * Rot3d(rot.W, -rot.V) (rot.Conungated)
            return(new V3d(
                       -W * rot.X + X * rot.W - Y * rot.Z + Z * rot.Y,
                       -W * rot.Y + Y * rot.W - Z * rot.X + X * rot.Z,
                       -W * rot.Z + Z * rot.W - X * rot.Y + Y * rot.X
                       ));
        }
示例#10
0
        public static void RotIntoCornerCase()
        {
            TrafoTesting.GenericTest(rnd =>
            {
                // some vectors will not normalize to 1.0 -> provoke numerical issues in Rot3d
                var vecd  = new V3d(0, 0, -rnd.UniformDouble());
                var rotd  = Rot3d.RotateInto(V3d.OOI, vecd.Normalized);
                var testd = rotd.Transform(V3d.OOI);
                Assert.True((testd + V3d.OOI).Length < 1e-8);

                var vecf  = new V3f(0, 0, -rnd.UniformDouble());
                var rotf  = Rot3f.RotateInto(V3f.OOI, vecf.Normalized);
                var testf = rotf.Transform(V3f.OOI);
                Assert.True((testf + V3f.OOI).Length < 1e-5);
            });
        }
示例#11
0
        public static void ConsistentWithMatrixRotationAndShiftTest()
        => TrafoTesting.GenericTest(rnd =>
        {
            var trans = rnd.UniformV3d() * 10;

            var axis  = rnd.UniformV3dDirection();
            var angle = rnd.UniformDouble() * Constant.PiTimesTwo;

            var m = M44d.Translation(trans) * M44d.Rotation(axis, angle);
            var e = new Euclidean3d(Rot3d.Rotation(axis, angle), trans);

            var p    = rnd.UniformV3d() * rnd.UniformInt(1000);
            var res  = m.TransformPos(p);
            var res2 = e.TransformPos(p);

            TrafoTesting.AreEqual(res, res2);
        });
示例#12
0
        public static void FromM33d()
        {
            TrafoTesting.GenericTest(rnd =>
            {
                var rot = rnd.UniformV3dFull() * Constant.PiTimesFour - Constant.PiTimesTwo;

                var mat  = M44d.RotationEuler(rot);
                var mat2 = (M44d)Rot3d.FromM33d((M33d)mat);

                Assert.IsFalse(mat.Elements.Any(x => x.IsNaN()), "NaN");

                if (!Fun.ApproximateEquals(mat, mat2, 1e-9))
                {
                    Assert.Fail("FAIL");
                }
            });
        }
示例#13
0
        public void TrafoRotIntoCornerCase()
        {
            var rnd = new Random();

            for (int i = 0; i < 1000; i++)
            {
                // some vectors will not normalize to 1.0 -> provoke numerical issues in Rot3d
                var vecd  = new V3d(0, 0, -rnd.NextDouble());
                var rotd  = new Rot3d(V3d.OOI, vecd);
                var testd = rotd.TransformDir(V3d.OOI);
                Assert.True((testd + V3d.OOI).Length < 1e-7);

                var vecf  = new V3f(0, 0, -rnd.NextDouble());
                var rotf  = new Rot3f(V3f.OOI, vecf);
                var testf = rotf.TransformDir(V3f.OOI);
                Assert.True((testf + V3f.OOI).Length < 1e-3);
            }
        }
示例#14
0
        public static void FromIntoEpislon()
        {
            TrafoTesting.GenericTest((rnd, i) =>
            {
                var dir   = rnd.UniformV3d().Normalized;
                var eps   = rnd.UniformV3d() * (i / 100) * 1e-22;
                var rotId = Rot3d.RotateInto(dir, (dir + eps).Normalized);
                var matId = (M33d)rotId;

                Assert.IsTrue(matId.IsIdentity(1e-10));

                var dirF   = rnd.UniformV3f().Normalized;
                var epsF   = rnd.UniformV3f() * (i / 100) * 1e-12f;
                var rotIdF = Rot3f.RotateInto(dirF, (dirF + epsF).Normalized);
                var matIdF = (M33f)rotIdF;

                Assert.IsTrue(matIdF.IsIdentity(1e-7f));
            });
        }
示例#15
0
        public static void YawPitchRoll()
        {
            TrafoTesting.GenericTest(rnd =>
            {
                var yaw   = rnd.UniformDouble() * Constant.PiTimesFour - Constant.PiTimesTwo;
                var pitch = rnd.UniformDouble() * Constant.PiTimesFour - Constant.PiTimesTwo;
                var roll  = rnd.UniformDouble() * Constant.PiTimesFour - Constant.PiTimesTwo;

                // Aardvark euler angles: roll (X), pitch (Y), yaw (Z). Ther are applied in reversed order.
                var mat  = (M33d)(M44d.RotationZ(yaw) * M44d.RotationY(pitch) * M44d.RotationX(roll));
                var mat2 = (M33d)M44d.RotationEuler(roll, pitch, yaw);
                var mat3 = (M33d)(Rot3d.RotationZ(yaw) * Rot3d.RotationY(pitch) * Rot3d.RotationX(roll));
                var mat4 = (M33d)Rot3d.RotationEuler(roll, pitch, yaw);

                Assert.IsTrue(Fun.ApproximateEquals(mat, mat2, 1e-7));
                Assert.IsTrue(Fun.ApproximateEquals(mat, mat3, 1e-7));
                Assert.IsTrue(Fun.ApproximateEquals(mat, mat4, 1e-7));
            });
        }
示例#16
0
        public static void Rot3dInvTransformTest()
        {
            var rnd = new RandomSystem(1);

            for (int i = 0; i < 10000; i++)
            {
                var v    = rnd.UniformV3d();
                var axis = rnd.UniformV3dDirection();
                var ang  = rnd.UniformDouble();
                var rot  = Rot3d.Rotation(axis, ang);

                var test1 = InvTransformUsingM33d(rot, v);
                var test2 = rot.InvTransform(v);
                var test3 = InvTransformUsingQuaternion(rot, v);
                var test4 = InvTransformUsingQuaternionOpt(rot, v);

                Assert.IsTrue(test1.ApproximateEquals(test2, 1e-5));
                Assert.IsTrue(test1.ApproximateEquals(test3, 1e-5));
                Assert.IsTrue(test1.ApproximateEquals(test4, 1e-5));
            }
        }
示例#17
0
        public static void RotationXYZ()
        {
            TrafoTesting.GenericTest(rnd =>
            {
                var angle = rnd.UniformDouble() * Constant.PiTimesFour - Constant.PiTimesTwo;

                var rotX1 = Rot3d.RotationX(angle);
                var rotX2 = Rot3d.Rotation(V3d.XAxis, angle);

                TrafoTesting.AreEqual(rotX1, rotX2);

                var rotY1 = Rot3d.RotationY(angle);
                var rotY2 = Rot3d.Rotation(V3d.YAxis, angle);

                TrafoTesting.AreEqual(rotY1, rotY2);

                var rotZ1 = Rot3d.RotationZ(angle);
                var rotZ2 = Rot3d.Rotation(V3d.ZAxis, angle);

                TrafoTesting.AreEqual(rotZ1, rotZ2);
            });
        }
示例#18
0
        public DistanceRot3d()
        {
            var rnd = new RandomSystem(1);

            A.SetByIndex(i => RndRot(rnd));
            angles.SetByIndex(i =>
            {
                double a = 0;
                do
                {
                    a = RndAngle(rnd);
                }while (a == 0);

                return(a);
            });

            B.SetByIndex(i =>
            {
                var r = Rot3d.Rotation(RndAxis(rnd), angles[i]);
                return(r * A[i]);
            });
        }
示例#19
0
        static V3d TransformUsingQuaternionOpt1(Rot3d rot, V3d v)
        {
            // Multiply(a, b)
            //return new Rot3d(
            //    a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z,
            //    a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y,
            //    a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z,
            //    a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X
            //    );

            // rot * Rot3d(0, v)
            var q = new QuaternionD(
                -rot.X * v.X - rot.Y * v.Y - rot.Z * v.Z,
                rot.W * v.X + rot.Y * v.Z - rot.Z * v.Y,
                rot.W * v.Y + rot.Z * v.X - rot.X * v.Z,
                rot.W * v.Z + rot.X * v.Y - rot.Y * v.X);

            // q * Rot3d(rot.W, -rot.V) (rot.Conungated)
            return(new V3d(
                       -q.W * rot.X + q.X * rot.W - q.Y * rot.Z + q.Z * rot.Y,
                       -q.W * rot.Y + q.Y * rot.W - q.Z * rot.X + q.X * rot.Z,
                       -q.W * rot.Z + q.Z * rot.W - q.X * rot.Y + q.Y * rot.X
                       ));
        }
示例#20
0
 public OrientedBox3d(Box3d box, Rot3d rot, V3d trans)
 {
     Box   = box;
     Trafo = new Euclidean3d(rot, trans);
 }
示例#21
0
 public Trafo3d(Rot3d trafo)
 {
     Forward  = (M44d)trafo;
     Backward = (M44d)trafo.Inverse;
 }
示例#22
0
 public static M33d Multiply(Scale3d scale, Rot3d rot)
 {
     return(Scale3d.Multiply(scale, (M33d)rot));
 }
示例#23
0
 public static Rot3d GetRandomRot3(RandomSystem rnd)
 => Rot3d.Rotation(rnd.UniformV3dDirection(), rnd.UniformDouble() * Constant.PiTimesTwo);
示例#24
0
 public static CameraExtrinsics FromWorld2Camera(V3d angleAxis, V3d translation)
 => FromWorld2Camera((M33d)Rot3d.FromAngleAxis(angleAxis), translation);
示例#25
0
 /// <summary>
 /// Creates rotational matrix from quaternion.
 /// </summary>
 /// <returns>Rotational matrix.</returns>
 public static M44d Rotation(Rot3d r)
 {
     return((M44d)r);
 }
示例#26
0
        static V3d TransformUsingQuaternion(Rot3d q, V3d v)
        {
            var r = q * new QuaternionD(0, v) * q.Inverse;

            return(new V3d(r.X, r.Y, r.Z));
        }
示例#27
0
 static V3d TransformUsingM33d(Rot3d rot, V3d v)
 {
     return(((M33d)rot).Transform(v));
 }
示例#28
0
 public void Write(Rot3d t)
 {
     Write(t.W); Write(t.V);
 }
示例#29
0
 public static M34d Rotation(Rot3d q)
 {
     return((M34d)q);
 }
示例#30
0
        static V3d InvTransformUsingQuaternion(Rot3d rot, V3d v)
        {
            var r = rot.Inverse * new QuaternionD(0, v) * rot;

            return(new V3d(r.X, r.Y, r.Z));
        }