Example #1
0
        public Quaternion GetRotation()
        {
            // Decompose the transformation to a rotation followed by translation, and return
            //   the rotation.  Throws InvalidOperationException if the matrix is not of that form.
            if (m[3] != 0 || m[7] != 0 || m[11] != 0 || m[15] != 1)
                throw new InvalidOperationException("Not a rotation+translation.");

            // Check for any scale, which we don't decompose (actually TMatrix is never supposed to
            // have a scale)
            for(int i=0; i<3; i++)
                if (Math.Abs(m[0+i]*m[0+i] + m[4+i]*m[4+i] + m[8+i]*m[8+i] - 1.0) > .0001)
                    throw new InvalidOperationException("Not a rotation+translation.");

            // Extract rotation matrix
            double[] r = new double[9];
            for (int i = 0; i < 3; i++)
                for (int j = 0; j < 3; j++)
                    r[i * 3 + j] = m[i * 4 + j];

            // Test that it is (approximately) special orthogonal.  If it isn't, the input matrix didn't meet the desired
            // form.
            double det = r[0] * (r[4] * r[8] - r[7] * r[5]) - r[1] * (r[3] * r[8] - r[6] * r[5]) + r[2] * (r[3] * r[7] - r[6] * r[4]);
            if (det < 0.99999 || det > 1.00001)
                throw new InvalidOperationException("Not a rotation+translation.");

            // Rotation -> quaternion
            var rotation = new Quaternion();

            var T = r[0] + r[3 + 1] + r[6 + 2];
            if (T > 0.0)
            {
                var S = 0.5 / Math.Sqrt(T + 1);
                rotation.w = 0.25 / S;
                rotation.x = (r[6 + 1] - r[3 + 2]) * S;
                rotation.y = (r[0 + 2] - r[6 + 0]) * S;
                rotation.z = (r[3 + 0] - r[0 + 1]) * S;
            }
            else if (r[0] > r[3 + 1] && r[0] > r[6 + 2])
            {
                var S = Math.Sqrt(1.0 + r[0] - r[3 + 1] - r[6 + 2]);
                rotation.x = S * 0.5;
                S = 0.5 / S;
                rotation.w = (r[6 + 1] - r[3 + 2]) * S;
                rotation.y = (r[0 + 1] + r[3 + 0]) * S;
                rotation.z = (r[0 + 2] + r[6 + 0]) * S;
            }
            else if (r[3 + 1] > r[6 + 2])
            {
                var S = Math.Sqrt(1.0 + r[3 + 1] - r[0 + 0] - r[6 + 2]);
                rotation.y = S * 0.5;
                S = 0.5 / S;
                rotation.w = (r[0 + 2] - r[6 + 0]) * S;
                rotation.x = (r[0 + 1] + r[3 + 0]) * S;
                rotation.z = (r[3 + 2] + r[6 + 1]) * S;
            }
            else
            {
                var S = Math.Sqrt(1.0 + r[6 + 2] - r[0 + 0] - r[3 + 1]);
                rotation.z = S * 0.5;
                S = 0.5 / S;
                rotation.w = (r[3 + 0] - r[0 + 1]) * S;
                rotation.x = (r[0 + 2] + r[6 + 0]) * S;
                rotation.y = (r[3 + 2] + r[6 + 1]) * S;
            }
            /*var tr = r[0] + r[4] + r[8];
            if (tr >= 0.0)
            {
                var s = Math.Sqrt(tr + 1.0);
                rotation.w = s * 0.5;
                s = 0.5 / s;
                rotation.x = (r[7] - r[5]) * s;
                rotation.y = (r[2] - r[6]) * s;
                rotation.z = (r[3] - r[1]) * s;
            } else {
                int h = 0;
                if (r[4] > */

            /*
            // Shoemake '85
            var rotation = new Quaternion();
            var w2 = 0.25 * (1 + r[0] + r[4] + r[8]);
            if (w2 > double.Epsilon)
            {
                rotation.w = Math.Sqrt(w2);
                rotation.x = (r[7] - r[5]) / (4 * rotation.w);
                rotation.y = (r[2] - r[6]) / (4 * rotation.w);
                rotation.z = (r[3] - r[1]) / (4 * rotation.w);
            }
            else
            {
                rotation.w = 0;
                var x2 = -0.5 * (r[4] + r[8]);
                if (x2 > double.Epsilon)
                {
                    rotation.x = Math.Sqrt(x2);
                    rotation.y = r[3] / (2 * rotation.x);
                    rotation.z = r[6] / (2 * rotation.x);
                }
                else
                {
                    rotation.x = 0;
                    var y2 = 0.5 * (1 - r[8]);
                    if (y2 > double.Epsilon)
                    {
                        rotation.y = Math.Sqrt(y2);
                        rotation.z = r[7] / (2 * rotation.y);
                    }
                    else
                    {
                        rotation.y = 0;
                        rotation.z = 1;
                    }
                }
            }
            rotation.Renormalize();*/

            var tv = new Vector(1,2,3);
            var tp = rotation.ToMatrix().Inverse() * this * tv;
            if ((tp-tv)*(tp-tv) > .0001)
                Console.WriteLine("GetRotation error.");

            rotation.Renormalize();
            return rotation;

            /*rotation.w = Math.Sqrt(Math.Max(0, 1 + r[0] + r[4] + r[8])) * 0.5;
            rotation.x = Math.Sqrt(Math.Max(0, 1 + r[0] - r[4] - r[8])) * 0.5;
            rotation.y = Math.Sqrt(Math.Max(0, 1 - r[0] + r[4] - r[8])) * 0.5;
            rotation.z = Math.Sqrt(Math.Max(0, 1 - r[0] - r[4] + r[8])) * 0.5;
            if (r[6 + 1] - r[3 + 2] < 0) rotation.x = -rotation.x;
            if (r[0 + 2] - r[6 + 0] < 0) rotation.y = -rotation.y;
            if (r[3 + 0] - r[0 + 1] < 0) rotation.z = -rotation.z;
            rotation.Renormalize();
            return rotation;*/

            /*var T = r[0] + r[3 + 1] + r[6 + 2] + 1;
            var rotation = new Quaternion();
            if (T > 0.00000001)
            {
                var S = 0.5 / Math.Sqrt(T);
                rotation.w = 0.25 / S;
                rotation.x = (r[6 + 1] - r[3 + 2]) * S;
                rotation.y = (r[0 + 2] - r[6 + 0]) * S;
                rotation.z = (r[3 + 0] - r[0 + 1]) * S;
            }
            else if (r[0] > r[3 + 1] && r[0] > r[6 + 2])
            {
                var S = 0.5 / Math.Sqrt(1.0 + r[0] - r[3 + 1] - r[6 + 2]);
                rotation.w = (r[6 + 1] - r[3 + 2]) * S;
                rotation.x = 0.25 / S;
                rotation.y = (r[0 + 1] + r[3 + 0]) * S;
                rotation.z = (r[0 + 2] + r[6 + 0]) * S;
            }
            else if (r[3 + 1] > r[6 + 2])
            {
                var S = 0.5 / Math.Sqrt(1.0 + r[3 + 1] - r[0 + 0] - r[6 + 2]);
                rotation.w = (r[0 + 2] - r[6 + 0]) * S;
                rotation.x = (r[0 + 1] + r[3 + 0]) * S;
                rotation.y = 0.25 * S;
                rotation.z = (r[3 + 2] + r[6 + 1]) * S;
            }
            else
            {
                var S = 0.5 / Math.Sqrt(1.0 + r[6 + 2] - r[0 + 0] - r[3 + 1]);
                rotation.w = (r[3 + 0] - r[0 + 1]) * S;
                rotation.x = (r[0 + 2] + r[6 + 0]) * S;
                rotation.y = (r[3 + 2] + r[6 + 1]) * S;
                rotation.z = 0.25 * S;
            }
            rotation.Renormalize();  // Rounding error can make w>1, yielding NAN for rotation.Angle
            return rotation;*/

            // translation = R^T * (-this.w_column)
            /*for (int i = 0; i < 3; i++)
                translation[i] = -(r[0 + i] * m[12] + r[3 + i] * m[13] + r[6 + i] * m[14]);*/
        }
Example #2
0
        static void TestMath()
        {
            var rand = new Random();

            for (int i = 0; i < 1000; i++)
            {
                var u = new Vector( rand.NextDouble()-0.5, rand.NextDouble()-0.5, rand.NextDouble()-0.5 ).Normalized();
                var t1 = new Vector( rand.NextDouble()-0.5, rand.NextDouble()-0.5, rand.NextDouble()-0.5 ) * 10;
                var t2 = new Vector(rand.NextDouble() - 0.5, rand.NextDouble() - 0.5, rand.NextDouble() - 0.5) * 10;
                var p1 = new Vector(rand.NextDouble() - 0.5, rand.NextDouble() - 0.5, rand.NextDouble() - 0.5) * 10;

                var q = new Quaternion(rand.NextDouble() * Math.PI, u);
                var m = q.ToMatrix();
                var mt = TMatrix.Translation(t1) * m * TMatrix.Translation(t2);
                var q2 = mt.GetRotation();
                var m2 = q2.ToMatrix();

                if (((m * p1) - (m2 * p1)) * (m * p1 - m2 * p1) > .0001)
                    Console.WriteLine("math error.");
            }

            var badq = new Quaternion(3.1414934204542249,
                new Vector(-0.920567453, -0.390583634, -0));
            badq = badq.ToMatrix().GetRotation();
            Console.WriteLine(badq.Angle);
            Console.WriteLine(badq.Axis);
        }