示例#1
0
        private static void ValidateGeometryUtilities()
        {
            for (int i = 0; i < 10; i++)
            {
                // Check the proper quaternion is generated to go 'from'->'to'
                Random  r      = new Random();
                Vector3 v1     = Vector3.Normalize(new Vector3(r.Next(), r.Next(), r.Next()));
                Vector3 v2     = Vector3.Normalize(new Vector3(r.Next(), r.Next(), r.Next()));
                float   angle1 = r.Next() % 360;
                float   angle2 = r.Next() % 360;

                if (angle1 == 0 || angle2 == 0)
                {
                    continue;
                }

                Quaternion from          = Quaternion.CreateFromAxisAngle(v1, (float)VectorMath.DegreesToRad(angle1));
                Quaternion to            = Quaternion.CreateFromAxisAngle(v2, (float)VectorMath.DegreesToRad(angle2));
                Quaternion transformQuat = VectorMath.GetLocalRotation(from, to);

                Quaternion fromTo = from * transformQuat;
                //Quaternion fromTo = from;
                float newAngleBetween = VectorMath.GetAngleDegrees(to, fromTo);
                Debug.Assert(Math.Abs(newAngleBetween) < 5);

                float   verifyAngle1;
                Vector3 verifyAxis1;
                VectorMath.GetRotationVectorAndAngleDegrees(from, out verifyAxis1, out verifyAngle1);
                Debug.Assert(Vector3.Dot(verifyAxis1, v1) > 0.99 && Math.Abs(verifyAngle1 - angle1) < 1 || Vector3.Dot(verifyAxis1, v1) < -0.99 && Math.Abs(360 - verifyAngle1 - angle1) < 1);
                //Debug.Assert( <= 2);

                Quaternion verifyFrom = VectorMath.GetLocalRotation(Quaternion.Identity, from);
                VectorMath.GetRotationVectorAndAngleDegrees(verifyFrom, out verifyAxis1, out verifyAngle1);
                Debug.Assert(Vector3.Dot(verifyAxis1, v1) > 0.99 && Math.Abs(verifyAngle1 - angle1) < 1 || Vector3.Dot(verifyAxis1, v1) < -0.99 && Math.Abs(360 - verifyAngle1 - angle1) < 1);
            }

            {
                Quaternion       rotation1 = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, (float)Math.PI / 2);
                CoordinateSystem cs        = new CoordinateSystem();
                cs.Translation = new Vector3(1, 2, 3);
                Console.WriteLine("PRE  = " + cs.Translation.ToString());
                cs.RotateLocal(new Vector3(-1, -2, -3), rotation1);
                Console.WriteLine("POST = " + cs.Translation.ToString());
            }

            {
                for (int i = 0; i < 10; i++)
                {
                    Random     r    = new Random();
                    Vector3    v1   = Vector3.Normalize(new Vector3(r.Next(), r.Next(), r.Next()));
                    Vector3    v2   = Vector3.Normalize(new Vector3(r.Next(), r.Next(), r.Next()));
                    Quaternion quat = VectorMath.GetRotationQuaternion(v1, v2);
                    Debug.Assert(Vector3.Dot(Vector3.Transform(v1, quat), v2) > 0.99);
                }
            }
        }
示例#2
0
        public bool GetGlobalRealignmentToZ(CoordinateSystem cs1, CoordinateSystem cs2, out Matrix matrix)
        {
            Vector3 axis;
            float   angleDegrees;
            //Quaternion rotation = VectorMath.GetLocalRotation(cs1.Rotation, cs2.Rotation);
            Quaternion rotation = VectorMath.GetGlobalRotation(cs1.Rotation, cs2.Rotation);

            VectorMath.GetRotationVectorAndAngleDegrees(rotation, out axis, out angleDegrees);

            Vector3 v12            = cs2.Translation - cs1.Translation;
            Vector3 u12            = Vector3.Normalize(v12);
            Vector3 xMidpoint      = (cs1.Translation + cs2.Translation) / 2;
            float   midpointOffset = (float)(v12.Length() / 2 / Math.Tan(VectorMath.DegreesToRad(Angle) / 2));
            Vector3 center         = Vector3.Normalize(Vector3.Cross(axis, u12)) * midpointOffset + xMidpoint;

            LineTrackingCoordinateSystem line = LineTrackingCoordinateSystem.CreateFromPointDirection(center, axis);

            line.ApplyTranslation(-center);

            Debug.Assert(Math.Abs(Vector3.Dot(cs2.Translation, axis) - Vector3.Dot(cs1.Translation, axis)) < 0.1);

            //float rad = (float) VectorMath.GetAngleRadians(line.Direction, Vector3.UnitZ);
            //Vector3 rotationAxis = Vector3.Cross(line.Direction, Vector3.UnitZ);
            //line.Rotate(Vector3.Zero, Quaternion.CreateFromAxisAngle(rotationAxis, -rad));


            line.ApplyRotation(VectorMath.GetRotationQuaternion(axis, Vector3.UnitZ));

            matrix = line.Transform;

            Debug.Assert(Math.Abs(angleDegrees - Angle) < 0.1);
            Debug.Assert(Math.Abs(Vector3.Transform(cs1.Translation, matrix).Length() - Vector3.Transform(cs2.Translation, matrix).Length()) < 0.1);
            //Debug.Assert((Vector3.Transform(cs2.Translation, matrix) - Vector3.Transform(cs1.Translation, matrix)).Length() < 0.1);


            return(true);
        }
示例#3
0
        public static bool GetCoordinateSystemsAfterAlignmentToAngleDegrees2(CoordinateSystem unalignedSystem1, Vector3 rotationCenter1, CoordinateSystem unalignedSystem2, Vector3 rotationCenter2, float degrees, out CoordinateSystem alignedSystem1, out CoordinateSystem alignedSystem2, out float errorDegrees)
        {
#if DEBUG
            //ValidateGeometryUtilities();
#endif

            // Copy the original coordinate systems as a starting point for the aligned systems
            alignedSystem1 = new CoordinateSystem(unalignedSystem1);
            alignedSystem2 = new CoordinateSystem(unalignedSystem2);


            // Track the lever lengths throughout to ensure coordinate system origin w.r.t. rotation coordinates remains the same
            float lengthORC1 = (rotationCenter1 - alignedSystem1.Translation).Length();
            float lengthORC2 = (rotationCenter2 - alignedSystem2.Translation).Length();

            // Fix the rotation angle
            {
                Quaternion localRotation = VectorMath.GetLocalRotation(alignedSystem1.Rotation, alignedSystem2.Rotation);
                float      desiredRad    = (float)VectorMath.DegreesToRad(degrees);
                float      currentRad;
                Vector3    uaxis = VectorMath.GetRotationVector(localRotation); // axis of rotation unit vector
                Vector3    uAxis;
                VectorMath.GetRotationVectorAndAngleRadians(localRotation, out uAxis, out currentRad);
                //uAxis = Vector3.Transform(localRotation, alignedSystem1.Rotation);
                float delta = (desiredRad - currentRad) / 2; // divide by two because both systems will have the same rotation applied


                Quaternion fix1 = Quaternion.CreateFromAxisAngle(uAxis, -delta);
                Quaternion fix2 = Quaternion.CreateFromAxisAngle(uAxis, delta);

                alignedSystem1.RotateLocal(rotationCenter1, fix1);
                alignedSystem2.RotateLocal(rotationCenter2, fix2);

                //Debug.Assert(Vector3.Dot(uAxis, VectorMath.GetRotationVector(Quaternion.Normalize(VectorMath.GetQuaternion(alignedSystem1.Rotation, alignedSystem2.Rotation)))) > 0.99);
                Debug.Assert(Math.Abs(Vector3.Dot(uAxis, VectorMath.GetRotationVector(Quaternion.Normalize(VectorMath.GetLocalRotation(alignedSystem1.Rotation, alignedSystem2.Rotation))))) > 0.99);


                Debug.Assert(Math.Abs(lengthORC1 - (rotationCenter1 - alignedSystem1.Translation).Length()) < 0.1);
                Debug.Assert(Math.Abs(lengthORC2 - (rotationCenter2 - alignedSystem2.Translation).Length()) < 0.1);

#if DEBUG
                float newDegrees = (float)VectorMath.GetRotationAngleDegrees(alignedSystem1.Rotation, alignedSystem2.Rotation);
                Debug.Assert(float.IsNaN(newDegrees) || Math.Abs(newDegrees - degrees) < 1 || Math.Abs(360 - newDegrees - degrees) < 1);
                float deltaDegrees = (float)VectorMath.RadToDegrees(delta);
#endif
            }

            // Apply a second rotation - **the same rotation** - to both coordinate systems s.t. their origins project onto the same
            // point on the new axis. This eliminates translation and allows a straight up measurement of rotation angle delta and also eliminates
            // the need for moving the spacer via RMSD-minimization alignment with the moved other two systems.
            {
                Quaternion rotation = VectorMath.GetLocalRotation(alignedSystem1.Rotation, alignedSystem2.Rotation);
                Vector3    uAxis;
                float      rad;
                VectorMath.GetRotationVectorAndAngleRadians(rotation, out uAxis, out rad);
                Vector3 vX12  = alignedSystem2.Translation - alignedSystem1.Translation;
                Vector3 vRC12 = rotationCenter2 - rotationCenter1;
                Vector3 uRC12 = Vector3.Normalize(vRC12);
                float   lRC12 = vRC12.Length();

                float xHeightAlongAxis     = Vector3.Dot(vX12, uAxis);
                float rcHeightAlongAxis    = Vector3.Dot(vRC12, uAxis);
                float leverHeightAlongAxis = xHeightAlongAxis - rcHeightAlongAxis;

                Debug.Assert(Math.Abs(Vector3.Dot((alignedSystem2.Translation - rotationCenter2) - (alignedSystem1.Translation - rotationCenter1), uAxis) - leverHeightAlongAxis) < 0.1);
                Debug.Assert(VectorMath.GetRotationVector(VectorMath.GetLocalRotation(alignedSystem1.Rotation, alignedSystem2.Rotation)) == uAxis);

                if (lRC12 < Math.Abs(leverHeightAlongAxis))
                {
                    // No change in direction of the rotation axis can place the two aligned systems at the same height, because one lever arm
                    // is so much longer than the other
                    errorDegrees = -1;
                    return(false);
                }

                // Figure out the angle between axis and rc1->rc2 that will make the rc1->rc2 projection cancel out the lever arm projection
                float      desiredRcHeightAlongAxis = -leverHeightAlongAxis;
                float      radDesired      = (float)Math.Acos(desiredRcHeightAlongAxis / lRC12);
                Quaternion rotationOption1 = Quaternion.CreateFromAxisAngle(Vector3.Normalize(Vector3.Cross(uRC12, uAxis)), radDesired);
                Quaternion rotationOption2 = Quaternion.CreateFromAxisAngle(Vector3.Normalize(Vector3.Cross(uRC12, uAxis)), -radDesired);
                Vector3    axisOption1     = Vector3.Transform(uRC12, rotationOption1);
                Vector3    axisOption2     = Vector3.Transform(uRC12, rotationOption2);
                Vector3    uAxisFinal      = Vector3.Distance(uAxis, axisOption1) < Vector3.Distance(uAxis, axisOption2)? axisOption1 : axisOption2;

                float      angle = (float)VectorMath.GetAngleRadians(uAxis, uAxisFinal);
                Quaternion quat  = Quaternion.CreateFromAxisAngle(Vector3.Normalize(Vector3.Cross(uAxis, uAxisFinal)), angle);
                if (Vector3.Dot(Vector3.Transform(uAxis, quat), uAxisFinal) < 0.99)
                {
                    throw new Exception();
                }

                //Quaternion alternateRotation = Quaternion.CreateFromAxisAngle(Vector3.Normalize(Vector3.Cross(uAxis, uRC12)), angle);
                Quaternion rotationToMakePlanar = quat; // VectorMath.GetRotationQuaternion(uAxis, uAxisFinal);
                if (Vector3.Dot(Vector3.Transform(uAxis, rotationToMakePlanar), uAxisFinal) < 0.99)
                {
                    throw new Exception();
                }



                Vector3 rotationVector = VectorMath.GetRotationVector(rotationToMakePlanar);
                if (Math.Abs(VectorMath.GetRotationAngleDegrees(rotationToMakePlanar)) < 0.1)
                {
                    errorDegrees = (float)Math.Max(VectorMath.GetRotationAngleDegrees(unalignedSystem1.Rotation, alignedSystem1.Rotation), VectorMath.GetRotationAngleDegrees(unalignedSystem2.Rotation, alignedSystem2.Rotation));
                    Debug.Assert(Math.Abs(Vector3.Dot((alignedSystem2.Translation - rotationCenter2) - (alignedSystem1.Translation - rotationCenter1), uAxis) - leverHeightAlongAxis) < 0.5); // any rotation should preserve lever height along the axis
                    return(true);
                }

                // Do it
                Debug.Assert(Vector3.Cross(rotationVector, uAxis).Length() > 0.99);
                Debug.Assert(Math.Abs(Vector3.Dot(uAxis, VectorMath.GetRotationVector(Quaternion.Normalize(VectorMath.GetLocalRotation(alignedSystem1.Rotation, alignedSystem2.Rotation))))) > 0.99);
                rotationToMakePlanar.W = -rotationToMakePlanar.W;
                alignedSystem1.RotateLocal(rotationCenter1, rotationToMakePlanar);
                alignedSystem2.RotateLocal(rotationCenter2, rotationToMakePlanar);

                Vector3 uAxisQuat = Vector3.Transform(uAxis, rotationToMakePlanar);
                uAxis = VectorMath.GetRotationVector(VectorMath.GetLocalRotation(alignedSystem1.Rotation, alignedSystem2.Rotation));

                float newRadAxisRC12 = (float)VectorMath.GetAngleRadians(uRC12, uAxis);
                //Debug.Assert(Math.Abs(newRadAxisRC12 - radDesired2) < 0.001);
                //Debug.Assert(Math.Abs(Vector3.Dot((alignedSystem2.Translation - rotationCenter2) - (alignedSystem1.Translation - rotationCenter1), uAxis) - leverHeightAlongAxis) < 0.1); // any rotation should preserve lever height along the axis


#if DEBUG && BROKEN
                uAxis = new Vector3(1, 2, 3);
                uAxis.Normalize();
                Quaternion testRotation = Quaternion.CreateFromAxisAngle(Vector3.Normalize(uAxis), (float)Math.PI / 4);
                Console.WriteLine("PRE  rc1->x1 dot uaxis = " + Vector3.Dot((alignedSystem1.Translation - rotationCenter1), uAxis));
                Console.WriteLine("PRE  rc2->x2 dot uaxis = " + Vector3.Dot((alignedSystem2.Translation - rotationCenter2), uAxis));
                Console.WriteLine("PRE  rc1->x1 distance = " + (alignedSystem1.Translation - rotationCenter1).Length());
                Console.WriteLine("PRE  rc2->x2 distance = " + (alignedSystem2.Translation - rotationCenter2).Length());

                alignedSystem1.RotateRadians(rotationCenter1, uAxis, (float)Math.PI / 4);
                alignedSystem2.RotateRadians(rotationCenter2, uAxis, (float)Math.PI / 4);
                //alignedSystem1.Rotate(rotationCenter1, testRotation);
                //alignedSystem2.Rotate(rotationCenter2, testRotation);
                //uAxis = Vector3.Transform(uAxis, testRotation);

                Console.WriteLine("POST rc1->x1 dot uaxis = " + Vector3.Dot((alignedSystem1.Translation - rotationCenter1), uAxis));
                Console.WriteLine("POST rc2->x2 dot uaxis = " + Vector3.Dot((alignedSystem2.Translation - rotationCenter2), uAxis));
                Console.WriteLine("POST rc1->x1 distance = " + (alignedSystem1.Translation - rotationCenter1).Length());
                Console.WriteLine("POST rc2->x2 distance = " + (alignedSystem2.Translation - rotationCenter2).Length());
#endif

#if DEBUG
                float newDegrees = (float)VectorMath.GetRotationAngleDegrees(alignedSystem1.Rotation, alignedSystem2.Rotation);
                Debug.Assert(float.IsNaN(newDegrees) || Math.Abs(newDegrees - degrees) < 1 || Math.Abs(360 - newDegrees - degrees) < 1);
                //float deltaDegrees = (float)VectorMath.RadToDegrees(delta);
#endif


                Debug.Assert(Math.Abs(uAxis.Length() - 1) < 0.001);
                Debug.Assert(Math.Abs(lengthORC1 - (rotationCenter1 - alignedSystem1.Translation).Length()) < 0.1);
                Debug.Assert(Math.Abs(lengthORC2 - (rotationCenter2 - alignedSystem2.Translation).Length()) < 0.1);
                //Debug.Assert(Math.Abs(Vector3.Dot((alignedSystem2.Translation - rotationCenter2) - (alignedSystem1.Translation - rotationCenter1), uAxis) - leverHeightAlongAxis) < 0.1); // any rotation should preserve lever height along the axis

                if (Vector3.Dot(uAxis, uAxisFinal) < 0.99)
                {
                    errorDegrees = -1;
                    return(false);
                }

                if (Math.Abs(Vector3.Dot(uAxis, alignedSystem2.Translation - alignedSystem1.Translation)) > 0.1)
                {
                    errorDegrees = -1;
                    return(false);
                }
                Debug.Assert(Math.Abs(Vector3.Dot(uAxis, alignedSystem2.Translation) - Vector3.Dot(uAxis, alignedSystem1.Translation)) < 0.1);

                errorDegrees = (float)Math.Max(VectorMath.GetRotationAngleDegrees(unalignedSystem1.Rotation, alignedSystem1.Rotation), VectorMath.GetRotationAngleDegrees(unalignedSystem2.Rotation, alignedSystem2.Rotation));
                if (errorDegrees < 5)
                {
                    return(true);
                }
            }

            errorDegrees = (float)Math.Max(VectorMath.GetRotationAngleDegrees(unalignedSystem1.Rotation, alignedSystem1.Rotation), VectorMath.GetRotationAngleDegrees(unalignedSystem2.Rotation, alignedSystem2.Rotation));
            return(true);
        }
示例#4
0
 public void RotateDegrees(Vector3 origin, Vector3 axis, float radians)
 {
     RotateRadians(origin, axis, (float)VectorMath.DegreesToRad(radians));
 }