Пример #1
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as a string. See SnapFromModes property.
        /// Pass in 'null' to get the default which is the offset to the pivot point.</param>
        /// <param name="axisType">Whether the Y axis is up or down</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            string snapFromMode,
            AxisSystemType axisType)
        {
            SnapFromMode mode = GetSnapFromMode(snapFromMode);

            return(CalcSnapFromOffset(node, mode, axisType));
        }
Пример #2
0
 /// <summary>
 /// Gets the vector in world space that points "up"</summary>
 /// <param name="axis">The axis system indicating which axis is up</param>
 /// <returns>The vector that points up</returns>
 public static Vec3F GetUpVector(AxisSystemType axis)
 {
     if (axis == AxisSystemType.YIsUp)
     {
         return(new Vec3F(0, 1, 0));
     }
     else
     {
         return(new Vec3F(0, 0, 1));
     }
 }
Пример #3
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as an enum</param>
        /// <param name="axisType">Axis system type (y or z is up)</param>
        /// <param name="pivot">Pass in either node.RotatePivot or node.ScalePivot</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            SnapFromMode snapFromMode,
            AxisSystemType axisType, Vec3F pivot)
        {
            switch (snapFromMode)
            {
            case SnapFromMode.Pivot:
            {
                Vec3F          offset;
                Path <DomNode> path          = new Path <DomNode>(node.Cast <DomNode>().Ancestry);
                Matrix4F       parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                node.Transform.TransformVector(pivot, out offset); //local-to-parent
                parentToWorld.TransformVector(offset, out offset); //parent-to-world
                return(offset);                                    //world
            }

            case SnapFromMode.Origin:
                return(new Vec3F(0, 0, 0));

            case SnapFromMode.BottomCenter:
            {
                Box   box = node.BoundingBox;
                Vec3F btmWorld;
                if (axisType == AxisSystemType.YIsUp)
                {
                    btmWorld = new Vec3F(
                        (box.Min.X + box.Max.X) * 0.5f,
                        box.Min.Y,
                        (box.Min.Z + box.Max.Z) * 0.5f);
                }
                else
                {
                    btmWorld = new Vec3F(
                        (box.Min.X + box.Max.X) * 0.5f,
                        (box.Min.Y + box.Max.Y) * 0.5f,
                        box.Min.Z);
                }
                Vec3F origin = node.Transform.Translation;
                Vec3F offset = btmWorld - origin;         //local space offset

                Path <DomNode> path          = new Path <DomNode>(node.Cast <DomNode>().GetPath());
                Matrix4F       parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                parentToWorld.TransformVector(offset, out offset);

                return(offset);
            }

            default:
                throw new ArgumentException("Invalid snap-from node");
            }
        }
Пример #4
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as an enum</param>
        /// <param name="axisType">Whether the Y axis is up or down</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            SnapFromMode snapFromMode,
            AxisSystemType axisType)
        {
            Vec3F rotatePivot = new Vec3F();

            if ((node.TransformationType & TransformationTypes.RotatePivot) != 0)
            {
                rotatePivot = node.RotatePivot;
            }

            return(CalcSnapFromOffset(node, snapFromMode, axisType, rotatePivot));
        }
Пример #5
0
 /// <summary>
 /// Gets the vector in world space that points "up"</summary>
 /// <param name="axis">The axis system indicating which axis is up</param>
 /// <returns>The vector that points up</returns>
 public static Vec3F GetUpVector(AxisSystemType axis)
 {
     if (axis == AxisSystemType.YIsUp)
         return new Vec3F(0, 1, 0);
     else
         return new Vec3F(0, 0, 1);
 }
Пример #6
0
        /// <summary>
        /// Given an object's current Euler angles and a surface normal, calculates
        /// the Euler angles necessary to rotate the object so that its up-vector is
        /// aligned with the surface normal</summary>
        /// <param name="originalEulers">Original Euler angles, from an IRenderableNode.Rotation, for example</param>
        /// <param name="surfaceNormal">A unit vector that the object should be rotate-snapped to</param>
        /// <param name="upAxis">Whether the Y axis is up or down</param>
        /// <returns>The resulting angles to be assigned to IRenderableNode.Rotation</returns>
        /// <remarks>
        /// Note that QuatF was attempted to be used, but I could not get it to work reliably
        /// with the Matrix3F.GetEulerAngles(). Numerical instability? The basis vector
        /// method below works well, except for when the target surface is 90 degrees different
        /// than the starting up vector. In this case, the rotation around the up vector is lost
        /// (gimbal lock), but the results are always valid in the sense that the up vector
        /// is aligned with the surface normal. --Ron Little</remarks>
        public static Vec3F RotateToVector(Vec3F originalEulers, Vec3F surfaceNormal, AxisSystemType upAxis)
        {
            // get basis vectors for the current rotation
            Matrix3F rotMat = new Matrix3F();
            rotMat.Rotation(originalEulers);
            Vec3F a1 = rotMat.XAxis;
            Vec3F a2 = rotMat.YAxis;
            Vec3F a3 = rotMat.ZAxis;

            // calculate destination basis vectors
            Vec3F b1, b2, b3;
            if (upAxis == AxisSystemType.YIsUp)
            {
                // a2 is the current up vector. b2 is the final up vector.
                // now, find either a1 or a3, whichever is most orthogonal to surface
                b2 = new Vec3F(surfaceNormal);
                float a1DotS = Vec3F.Dot(a1, surfaceNormal);
                float a3DotS = Vec3F.Dot(a3, surfaceNormal);
                if (Math.Abs(a1DotS) < Math.Abs(a3DotS))
                {
                    b1 = new Vec3F(a1);
                    b3 = Vec3F.Cross(b1, b2);
                    b1 = Vec3F.Cross(b2, b3);
                }
                else
                {
                    b3 = new Vec3F(a3);
                    b1 = Vec3F.Cross(b2, b3);
                    b3 = Vec3F.Cross(b1, b2);
                }
            }
            else
            {
                // a3 is the current up vector. b3 is the final up vector.
                // now, find either a1 or a2, whichever is most orthogonal to surface
                b3 = new Vec3F(surfaceNormal);
                float a1DotS = Vec3F.Dot(a1, surfaceNormal);
                float a2DotS = Vec3F.Dot(a2, surfaceNormal);
                if (Math.Abs(a1DotS) < Math.Abs(a2DotS))
                {
                    b1 = new Vec3F(a1);
                    b2 = Vec3F.Cross(b3, b1);
                    b1 = Vec3F.Cross(b2, b3);
                }
                else
                {
                    b2 = new Vec3F(a2);
                    b1 = Vec3F.Cross(b2, b3);
                    b2 = Vec3F.Cross(b3, b1);
                }
            }

            // in theory, this isn't necessary, but in practice...
            b1.Normalize();
            b2.Normalize();
            b3.Normalize();

            // construct new rotation matrix and extract euler angles
            rotMat.XAxis = b1;
            rotMat.YAxis = b2;
            rotMat.ZAxis = b3;

            Vec3F newEulers = new Vec3F();
            rotMat.GetEulerAngles(out newEulers.X, out newEulers.Y, out newEulers.Z);
            return newEulers;
        }
Пример #7
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as an enum</param>
        /// <param name="axisType">Whether the Y axis is up or down</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            SnapFromMode snapFromMode,
            AxisSystemType axisType)
        {
            Vec3F rotatePivot = new Vec3F();
            if ((node.TransformationType & TransformationTypes.RotatePivot) != 0)
                rotatePivot = node.RotatePivot;

            return CalcSnapFromOffset(node, snapFromMode, axisType, rotatePivot);
        }
Пример #8
0
 /// <summary>
 /// For an object 'node' that is being manipulated, this function returns
 /// the offset (in world space) from the object's origin to to the point that is being
 /// "snapped from". This calculation is determined by the snapping modes.</summary>
 /// <param name="node">The object that is being snapped-to some other object</param>
 /// <param name="snapFromMode">The "snap from" mode, as a string. See SnapFromModes property.
 /// Pass in 'null' to get the default which is the offset to the pivot point.</param>
 /// <param name="axisType">Whether the Y axis is up or down</param>
 /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
 /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
 public static Vec3F CalcSnapFromOffset(
     ITransformable node,
     string snapFromMode,
     AxisSystemType axisType)
 {
     SnapFromMode mode = GetSnapFromMode(snapFromMode);
     return CalcSnapFromOffset(node, mode, axisType);
 }
Пример #9
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as an enum</param>
        /// <param name="axisType">Axis system type (y or z is up)</param>
        /// <param name="pivot">Pass in either node.RotatePivot or node.ScalePivot</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            SnapFromMode snapFromMode,
            AxisSystemType axisType, Vec3F pivot)
        {
            switch (snapFromMode)
            {
                case SnapFromMode.Pivot:
                    {
                        Vec3F offset;
                        Path<DomNode> path = new Path<DomNode>(node.Cast<DomNode>().Ancestry);
                        Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                        node.Transform.TransformVector(pivot, out offset); //local-to-parent
                        parentToWorld.TransformVector(offset, out offset); //parent-to-world
                        return offset; //world
                    }
                case SnapFromMode.Origin:
                    return new Vec3F(0, 0, 0);
                case SnapFromMode.BottomCenter:
                    {
                        Box box = node.BoundingBox;
                        Vec3F btmWorld;
                        if (axisType == AxisSystemType.YIsUp)
                        {
                            btmWorld = new Vec3F(
                                (box.Min.X + box.Max.X) * 0.5f,
                                box.Min.Y,
                                (box.Min.Z + box.Max.Z) * 0.5f);
                        }
                        else
                        {
                            btmWorld = new Vec3F(
                                (box.Min.X + box.Max.X) * 0.5f,
                                (box.Min.Y + box.Max.Y) * 0.5f,
                                box.Min.Z);
                        }
                        Vec3F origin = node.Transform.Translation;
                        Vec3F offset = btmWorld - origin; //local space offset

                        Path<DomNode> path = new Path<DomNode>(node.Cast<DomNode>().GetPath());
                        Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                        parentToWorld.TransformVector(offset, out offset);

                        return offset;
                    }
                default:
                    throw new ArgumentException("Invalid snap-from node");
            }
        }
Пример #10
0
        /// <summary>
        /// Given an object's current Euler angles and a surface normal, calculates
        /// the Euler angles necessary to rotate the object so that its up-vector is
        /// aligned with the surface normal</summary>
        /// <param name="originalEulers">Original Euler angles, from an IRenderableNode.Rotation, for example</param>
        /// <param name="surfaceNormal">A unit vector that the object should be rotate-snapped to</param>
        /// <param name="upAxis">Whether the Y axis is up or down</param>
        /// <returns>The resulting angles to be assigned to IRenderableNode.Rotation</returns>
        /// <remarks>
        /// Note that QuatF was attempted to be used, but I could not get it to work reliably
        /// with the Matrix3F.GetEulerAngles(). Numerical instability? The basis vector
        /// method below works well, except for when the target surface is 90 degrees different
        /// than the starting up vector. In this case, the rotation around the up vector is lost
        /// (gimbal lock), but the results are always valid in the sense that the up vector
        /// is aligned with the surface normal. --Ron Little</remarks>
        public static Vec3F RotateToVector(Vec3F originalEulers, Vec3F surfaceNormal, AxisSystemType upAxis)
        {
            // get basis vectors for the current rotation
            Matrix3F rotMat = new Matrix3F();

            rotMat.Rotation(originalEulers);
            Vec3F a1 = rotMat.XAxis;
            Vec3F a2 = rotMat.YAxis;
            Vec3F a3 = rotMat.ZAxis;

            // calculate destination basis vectors
            Vec3F b1, b2, b3;

            if (upAxis == AxisSystemType.YIsUp)
            {
                // a2 is the current up vector. b2 is the final up vector.
                // now, find either a1 or a3, whichever is most orthogonal to surface
                b2 = new Vec3F(surfaceNormal);
                float a1DotS = Vec3F.Dot(a1, surfaceNormal);
                float a3DotS = Vec3F.Dot(a3, surfaceNormal);
                if (Math.Abs(a1DotS) < Math.Abs(a3DotS))
                {
                    b1 = new Vec3F(a1);
                    b3 = Vec3F.Cross(b1, b2);
                    b1 = Vec3F.Cross(b2, b3);
                }
                else
                {
                    b3 = new Vec3F(a3);
                    b1 = Vec3F.Cross(b2, b3);
                    b3 = Vec3F.Cross(b1, b2);
                }
            }
            else
            {
                // a3 is the current up vector. b3 is the final up vector.
                // now, find either a1 or a2, whichever is most orthogonal to surface
                b3 = new Vec3F(surfaceNormal);
                float a1DotS = Vec3F.Dot(a1, surfaceNormal);
                float a2DotS = Vec3F.Dot(a2, surfaceNormal);
                if (Math.Abs(a1DotS) < Math.Abs(a2DotS))
                {
                    b1 = new Vec3F(a1);
                    b2 = Vec3F.Cross(b3, b1);
                    b1 = Vec3F.Cross(b2, b3);
                }
                else
                {
                    b2 = new Vec3F(a2);
                    b1 = Vec3F.Cross(b2, b3);
                    b2 = Vec3F.Cross(b3, b1);
                }
            }

            // in theory, this isn't necessary, but in practice...
            b1.Normalize();
            b2.Normalize();
            b3.Normalize();

            // construct new rotation matrix and extract euler angles
            rotMat.XAxis = b1;
            rotMat.YAxis = b2;
            rotMat.ZAxis = b3;

            Vec3F newEulers = new Vec3F();

            rotMat.GetEulerAngles(out newEulers.X, out newEulers.Y, out newEulers.Z);
            return(newEulers);
        }