Beispiel #1
0
        private void DecideArrowDrawing(Matrix4F localToWorld, Camera camera,
                                        out bool drawX, out bool drawY, out bool drawZ)
        {
            // Use our axis in world space, so we can prevent picking of lines and squares that
            //  are being viewed edge-on which leads to numerical instability.
            Vec3F xAxis   = localToWorld.XAxis;
            Vec3F yAxis   = localToWorld.YAxis;
            Vec3F zAxis   = localToWorld.ZAxis;
            Vec3F control = localToWorld.Translation;

            Vec3F eyeToControl;

            if (camera.ProjectionType == ProjectionType.Perspective)
            {
                eyeToControl = control - camera.WorldEye;
                eyeToControl.Normalize();
            }
            else
            {
                eyeToControl = camera.WorldLookAt;
            }

            drawX = Math.Abs(Vec3F.Dot(eyeToControl, xAxis)) < 1.0f - EdgeAngle;
            drawY = Math.Abs(Vec3F.Dot(eyeToControl, yAxis)) < 1.0f - EdgeAngle;
            drawZ = Math.Abs(Vec3F.Dot(eyeToControl, zAxis)) < 1.0f - EdgeAngle;
        }
Beispiel #2
0
        /// <summary>
        /// Projects the specified x and y, in normalized window coordinates, onto the grid,
        /// and snaps it to the nearest grid vertex if necessary.
        /// Normalized window coordinates are in the range [-0.5,0.5] with +x pointing to the
        /// right and +y pointing up.</summary>
        /// <param name="x">Window x in normalized window coords</param>
        /// <param name="y">Window y in normalized window coords</param>
        /// <param name="camera">Camera</param>
        /// <returns>Projection of x and y onto the grid, in world space.</returns>
        public Vec3F Project(float x, float y, Camera camera)
        {
            Ray3F ray = camera.CreateRay(x, y);

            Matrix4F V = new Matrix4F(camera.ViewMatrix);
            V.Mul(m_invAxisSystem, V);

            if (camera.Frustum.IsOrtho)
            {
                V = new Matrix4F(m_V);
                V.Translation = camera.ViewMatrix.Translation;
            }

            // origin
            Vec3F delta = new Vec3F(0, Height, 0);
            V.Transform(delta, out delta);
            Vec3F o = delta;

            // Up vec
            Vec3F axis = V.YAxis;
            Vec3F projPt = ray.IntersectPlane(axis, -Vec3F.Dot(o, axis));

            // Transform back into world space
            Matrix4F Inv = new Matrix4F();
            Inv.Invert(camera.ViewMatrix);
            Inv.Transform(projPt, out projPt);

            if (Snap)
            {
                projPt = SnapPoint(projPt);
            }
            return projPt;
        }
Beispiel #3
0
        /// <summary>
        /// Gets the view matrix corresponding to a view direction</summary>
        /// <param name="viewDirection">View direction</param>
        /// <returns>View matrix corresponding to the view direction</returns>
        public static Matrix4F LookAtMatrix(Vec3F viewDirection)
        {
            // check if viewDirection is non-zero length and normalize it if so.
            float length = viewDirection.Length;

            if (length == 0.0f)
            {
                return(new Matrix4F());
            }
            viewDirection = viewDirection * (1.0f / length);

            // find a basis vector (x-axis or y-axis) that is not parallel to viewDirection.
            // give preference to y-axis for historical purposes.
            // Create 's' and 'u' that are orthonormal vectors, relative to viewDirection.
            // 'viewDirection' is like the z-axis. 's' is the x-axis, and 'u' is the y-axis.
            // We want: s X u = viewDir so that resulting coordinate system is right-handed.
            // Otherwise, you get the triangles all flipped.
            Vec3F s;
            Vec3F xAxis = new Vec3F(1, 0, 0);
            Vec3F yAxis = new Vec3F(0, 1, 0);

            if (Math.Abs(Vec3F.Dot(yAxis, viewDirection)) < 0.98)
            {
                s = Vec3F.Cross(yAxis, viewDirection); //x' = y X z
            }
            else
            {
                // viewDirection == yAxis
                s = Vec3F.Cross(viewDirection, xAxis); //x' = y X x
            }
            Vec3F u = Vec3F.Cross(viewDirection, s);   //y' = z X x'

            s = s / s.Length;
            u = u / u.Length;

            Matrix4F T = new Matrix4F
                         (
                s.X, s.Y, s.Z, 0,
                u.X, u.Y, u.Z, 0,
                viewDirection.X, viewDirection.Y, viewDirection.Z, 0,
                0, 0, 0, 1
                         );

            return(T);
        }
        private void Track(Point current)
        {
            if (current.X < 0 || current.X > m_width)
            {
                return;
            }

            if (current.Y < 0 || current.Y > m_height)
            {
                return;
            }

            Vec3F currentPoint = ProjectToArcball(current);
            Vec3F i            = Vec3F.Cross(currentPoint, m_firstPoint);
            float r            = Vec3F.Dot(m_firstPoint, currentPoint);

            m_currentRotation = new QuatF(i.X, i.Y, i.Z, r);
        }
Beispiel #5
0
        private static float CalcAngle(Vec3F v0, Vec3F v1, Vec3F axis, float snapAngle)
        {
            const float twoPi = (float)(2.0 * Math.PI);
            float       angle = Vec3F.Dot(v0, v1);

            if (angle > 1.0f)
            {
                angle = 1.0f;
            }
            else if (angle <= -1.0f)
            {
                angle = 1.0f;
            }
            angle = (float)Math.Acos(angle);

            // Check if v0 is left of v1
            Vec3F cross = Vec3F.Cross(v0, v1);

            if (Vec3F.Dot(cross, axis) < 0)
            {
                angle = twoPi - angle;
            }
            // round to nearest multiple of preference
            if (snapAngle > 0)
            {
                if (angle >= 0)
                {
                    int n = (int)((angle + snapAngle * 0.5f) / snapAngle);
                    angle = n * snapAngle;
                }
                else
                {
                    int n = (int)((angle - snapAngle * 0.5f) / snapAngle);
                    angle = n * snapAngle;
                }
            }
            // const float epsilone = (float)1e-7;
            // if (twoPi - angle <= epsilone) angle = 0.0f;
            return(angle);
        }
Beispiel #6
0
        private static float CalcAngle(Vec3F v0, Vec3F v1, Vec3F axis, float snapAngle)
        {
            float angle = Vec3F.Dot(v0, v1);

            if (angle > 1.0f)
            {
                angle = 1.0f;
            }
            else if (angle < -1.0f)
            {
                angle = 1.0f;
            }
            angle = (float)Math.Acos(angle);

            // Check if v0 is left of v1
            Vec3F cross = Vec3F.Cross(v0, v1);

            if (Vec3F.Dot(cross, axis) < 0)
            {
                angle = -angle;
            }

            // round to nearest multiple of preference
            if (snapAngle > 0)
            {
                if (angle >= 0)
                {
                    int n = (int)((angle + snapAngle * 0.5) / snapAngle);
                    angle = n * snapAngle;
                }
                else
                {
                    int n = (int)((angle - snapAngle * 0.5) / snapAngle);
                    angle = n * snapAngle;
                }
            }

            return(angle);
        }
        public override void OnDragging(ViewControl vc, Point scrPt)
        {
            if (m_hitRegion == HitRegion.None || m_activeOp == null || m_activeOp.NodeList.Count == 0)
            {
                return;
            }

            Matrix4F view = vc.Camera.ViewMatrix;
            // compute world * view
            Matrix4F wv = new Matrix4F();

            wv.Mul(HitMatrix, view);

            // create ray in view space.
            Ray3F rayV = vc.GetRay(scrPt, vc.Camera.ProjectionMatrix);

            Vec3F xAxis  = wv.XAxis;
            Vec3F yAxis  = wv.YAxis;
            Vec3F zAxis  = wv.ZAxis;
            Vec3F origin = wv.Translation;

            m_scale = new Vec3F(1, 1, 1);
            float scale = 1;
            float a1, a2;

            switch (m_hitRegion)
            {
            case HitRegion.XAxis:
            case HitRegion.NegXAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(HitRayV.Direction, yAxis));
                a2 = Math.Abs(Vec3F.Dot(HitRayV.Direction, zAxis));
                Vec3F axis       = (a1 > a2 ? yAxis : zAxis);
                Vec3F p0         = HitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), xAxis);
                if (m_hitRegion == HitRegion.NegXAxis)
                {
                    dragAmount *= -1;
                }
                m_scale.X = 1.0f + dragAmount / m_hitScale;
                scale     = m_scale.X;
            }

            break;

            case HitRegion.YAxis:
            case HitRegion.NegYAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(HitRayV.Direction, zAxis));
                a2 = Math.Abs(Vec3F.Dot(HitRayV.Direction, xAxis));
                Vec3F axis       = (a1 > a2 ? zAxis : xAxis);
                Vec3F p0         = HitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), yAxis);
                if (m_hitRegion == HitRegion.NegYAxis)
                {
                    dragAmount *= -1;
                }
                m_scale.Y = 1.0f + dragAmount / m_hitScale;
                scale     = m_scale.Y;
            }
            break;

            case HitRegion.ZAxis:
            case HitRegion.NegZAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(HitRayV.Direction, xAxis));
                a2 = Math.Abs(Vec3F.Dot(HitRayV.Direction, yAxis));
                Vec3F axis       = (a1 > a2 ? xAxis : yAxis);
                Vec3F p0         = HitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), zAxis);
                if (m_hitRegion == HitRegion.NegZAxis)
                {
                    dragAmount *= -1;
                }
                m_scale.Z = 1.0f + dragAmount / m_hitScale;
                scale     = m_scale.Z;
            }
            break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (m_isUniformScaling)
            {
                m_scale = new Vec3F(scale, scale, scale);
            }


            // scale
            for (int i = 0; i < m_activeOp.NodeList.Count; i++)
            {
                ITransformable node = m_activeOp.NodeList[i];
                node.Scale = Vec3F.Mul(m_originalScales[i], m_scale);

                Matrix4F mtrx = TransformUtils.CalcTransform(
                    Vec3F.ZeroVector,
                    node.Rotation,
                    node.Scale,
                    m_pivotOffset[i]);
                node.Translation = m_originalTranslations[i] + mtrx.Translation;
            }
        }
        public override void OnDragging(ViewControl vc, Point scrPt)
        {
            if (m_hitRegion == HitRegion.None || NodeList.Count == 0)
            {
                return;
            }

            Matrix4F view = vc.Camera.ViewMatrix;
            // compute world * view
            Matrix4F wv = new Matrix4F();

            wv.Mul(HitMatrix, view);

            // create ray in view space.
            Ray3F rayV = vc.GetRay(scrPt, vc.Camera.ProjectionMatrix);


            Vec3F xAxis  = wv.XAxis;
            Vec3F yAxis  = wv.YAxis;
            Vec3F zAxis  = wv.ZAxis;
            Vec3F origin = wv.Translation;

            //Vec3F pos;
            m_scale = new Vec3F(1, 1, 1);
            float scale = 1;
            float a1, a2;

            switch (m_hitRegion)
            {
            case HitRegion.XAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(HitRayV.Direction, yAxis));
                a2 = Math.Abs(Vec3F.Dot(HitRayV.Direction, zAxis));
                Vec3F axis       = (a1 > a2 ? yAxis : zAxis);
                Vec3F p0         = HitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), xAxis);
                m_scale.X = 1.0f + dragAmount / m_hitScale;
                scale     = m_scale.X;
            }

            break;

            case HitRegion.YAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(HitRayV.Direction, zAxis));
                a2 = Math.Abs(Vec3F.Dot(HitRayV.Direction, xAxis));
                Vec3F axis       = (a1 > a2 ? zAxis : xAxis);
                Vec3F p0         = HitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), yAxis);
                m_scale.Y = 1.0f + dragAmount / m_hitScale;
                scale     = m_scale.Y;
            }
            break;

            case HitRegion.ZAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(HitRayV.Direction, xAxis));
                a2 = Math.Abs(Vec3F.Dot(HitRayV.Direction, yAxis));
                Vec3F axis       = (a1 > a2 ? xAxis : yAxis);
                Vec3F p0         = HitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), zAxis);
                m_scale.Z = 1.0f + dragAmount / m_hitScale;
                scale     = m_scale.Z;
            }
            break;

            case HitRegion.FreeRect:
            {
                Vec3F axis    = new Vec3F(0, 0, 1);
                Vec3F p0      = HitRayV.IntersectPlane(axis, -origin.Z);
                Vec3F p1      = rayV.IntersectPlane(axis, -origin.Z);
                Vec3F dragVec = p1 - p0;

                float dragAmount = 1.0f + dragVec.X / m_hitScale;
                m_scale.X = dragAmount;
                m_scale.Y = dragAmount;
                m_scale.Z = dragAmount;
                scale     = m_scale.X;
            }
            break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (m_isUniformScaling)
            {
                m_scale = new Vec3F(scale, scale, scale);
            }

            // scale
            for (int i = 0; i < NodeList.Count; i++)
            {
                ITransformable transformable = NodeList[i];
                transformable.Scale = Vec3F.Mul(m_originalValues[i], m_scale);
            }
        }
Beispiel #9
0
        public Vec3F OnDragging(Ray3F rayV)
        {
            if (m_hitRegion == HitRegion.None)
            {
                return(Vec3F.ZeroVector);
            }


            Vec3F xLocal = m_hitMatrix.XAxis;
            Vec3F yLocal = m_hitMatrix.YAxis;
            Vec3F zLocal = m_hitMatrix.ZAxis;

            Vec3F xAxis  = m_hitWorldView.XAxis;
            Vec3F yAxis  = m_hitWorldView.YAxis;
            Vec3F zAxis  = m_hitWorldView.ZAxis;
            Vec3F origin = m_hitWorldView.Translation;

            Vec3F translate;
            float a1, a2;

            switch (m_hitRegion)
            {
            case HitRegion.XAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, yAxis));
                a2 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, zAxis));
                Vec3F axis       = (a1 > a2 ? yAxis : zAxis);
                Vec3F p0         = m_hitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), xAxis);
                translate = dragAmount * xLocal;
            }

            break;

            case HitRegion.YAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, zAxis));
                a2 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, xAxis));
                Vec3F axis       = (a1 > a2 ? zAxis : xAxis);
                Vec3F p0         = m_hitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), yAxis);
                translate = dragAmount * yLocal;
            }
            break;

            case HitRegion.ZAxis:
            {
                a1 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, xAxis));
                a2 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, yAxis));
                Vec3F axis       = (a1 > a2 ? xAxis : yAxis);
                Vec3F p0         = m_hitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot((p1 - p0), zAxis);
                translate = dragAmount * zLocal;
            }
            break;

            case HitRegion.XYSquare:
            {
                Vec3F p0         = m_hitRayV.IntersectPlane(zAxis, -Vec3F.Dot(zAxis, origin));
                Vec3F p1         = rayV.IntersectPlane(zAxis, -Vec3F.Dot(zAxis, origin));
                Vec3F deltaLocal = p1 - p0;
                float dragX      = Vec3F.Dot(xAxis, deltaLocal);
                float dragY      = Vec3F.Dot(yAxis, deltaLocal);
                translate = dragX * xLocal + dragY * yLocal;
            }
            break;

            case HitRegion.YZSquare:
            {
                Vec3F p0         = m_hitRayV.IntersectPlane(xAxis, -Vec3F.Dot(xAxis, origin));
                Vec3F p1         = rayV.IntersectPlane(xAxis, -Vec3F.Dot(xAxis, origin));
                Vec3F deltaLocal = p1 - p0;
                float dragY      = Vec3F.Dot(yAxis, deltaLocal);
                float dragZ      = Vec3F.Dot(zAxis, deltaLocal);
                translate = dragY * yLocal + dragZ * zLocal;
            }
            break;

            case HitRegion.XZSquare:
            {
                Vec3F p0         = m_hitRayV.IntersectPlane(yAxis, -Vec3F.Dot(yAxis, origin));
                Vec3F p1         = rayV.IntersectPlane(yAxis, -Vec3F.Dot(yAxis, origin));
                Vec3F deltaLocal = p1 - p0;
                float dragX      = Vec3F.Dot(xAxis, deltaLocal);
                float dragZ      = Vec3F.Dot(zAxis, deltaLocal);
                translate = dragX * xLocal + dragZ * zLocal;
            }
            break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(translate);
        }
Beispiel #10
0
        /// <summary>
        /// Given an object's current Euler angles and a surface normal, will calculate
        ///  the Euler angles necessary to rotate the object so that it's up-vector is
        ///  aligned with the surface normal.
        /// </summary>
        /// <param name="originalEulers">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">y or z is up?</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 which 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);
        }
Beispiel #11
0
        /// <summary>
        /// Performs actions during control drag</summary>
        /// <param name="hit">Hit record</param>
        /// <param name="x">Mouse x position</param>
        /// <param name="y">Mouse y position</param>
        /// <param name="action">Render action</param>
        /// <param name="camera">Camera</param>
        /// <param name="transform">Transform</param>
        /// <returns>Translation, in world coordinates</returns>
        public Vec3F OnDrag(HitRecord hit, float x, float y, IRenderAction action, Camera camera, Matrix4F transform)
        {
            float    a1, a2;
            Matrix4F W = new Matrix4F();

            W.Mul(transform, camera.ViewMatrix);

            // Setup rays, in view space. (-z goes into the screen.)
            Ray3F ray0 = camera.CreateRay(m_iX, m_iY);
            Ray3F ray  = camera.CreateRay(x, y);

            // Build axis and origin in view space
            Vec3F xAxis  = W.XAxis;
            Vec3F yAxis  = W.YAxis;
            Vec3F zAxis  = W.ZAxis;
            Vec3F origin = W.Translation;

            Vec3F trans = new Vec3F();

            // Choose the best projection plane according to the projection angle
            switch ((HitElement)hit.RenderObjectData[1])
            {
            case HitElement.X_ARROW:
            {
                a1 = Math.Abs(Vec3F.Dot(ray0.Direction, yAxis));
                a2 = Math.Abs(Vec3F.Dot(ray0.Direction, zAxis));
                Vec3F axis       = (a1 > a2 ? yAxis : zAxis);
                Vec3F p0         = ray0.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = ray.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot(xAxis, p1 - p0);
                Vec3F xLocal     = transform.XAxis;
                trans = dragAmount * xLocal;
            }
            break;

            case HitElement.Y_ARROW:
            {
                a1 = Math.Abs(Vec3F.Dot(ray0.Direction, zAxis));
                a2 = Math.Abs(Vec3F.Dot(ray0.Direction, xAxis));
                Vec3F axis       = (a1 > a2 ? zAxis : xAxis);
                Vec3F p0         = ray0.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = ray.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot(yAxis, p1 - p0);
                Vec3F yLocal     = transform.YAxis;
                trans = dragAmount * yLocal;
            }
            break;

            case HitElement.Z_ARROW:
            {
                a1 = Math.Abs(Vec3F.Dot(ray0.Direction, xAxis));
                a2 = Math.Abs(Vec3F.Dot(ray0.Direction, yAxis));
                Vec3F axis       = (a1 > a2 ? xAxis : yAxis);
                Vec3F p0         = ray0.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                Vec3F p1         = ray.IntersectPlane(axis, -Vec3F.Dot(axis, origin));
                float dragAmount = Vec3F.Dot(zAxis, p1 - p0);
                Vec3F zLocal     = transform.ZAxis;
                trans = dragAmount * zLocal;
            }
            break;

            case HitElement.XY_SQUARE:
            {
                Vec3F p0         = ray0.IntersectPlane(zAxis, -Vec3F.Dot(zAxis, origin));
                Vec3F p1         = ray.IntersectPlane(zAxis, -Vec3F.Dot(zAxis, origin));
                Vec3F deltaLocal = p1 - p0;
                float dragX      = Vec3F.Dot(xAxis, deltaLocal);
                float dragY      = Vec3F.Dot(yAxis, deltaLocal);
                Vec3F xLocal     = transform.XAxis;
                Vec3F yLocal     = transform.YAxis;
                trans = dragX * xLocal + dragY * yLocal;
            }
            break;

            case HitElement.YZ_SQUARE:
            {
                Vec3F p0         = ray0.IntersectPlane(xAxis, -Vec3F.Dot(xAxis, origin));
                Vec3F p1         = ray.IntersectPlane(xAxis, -Vec3F.Dot(xAxis, origin));
                Vec3F deltaLocal = p1 - p0;
                float dragY      = Vec3F.Dot(yAxis, deltaLocal);
                float dragZ      = Vec3F.Dot(zAxis, deltaLocal);
                Vec3F yLocal     = transform.YAxis;
                Vec3F zLocal     = transform.ZAxis;
                trans = dragY * yLocal + dragZ * zLocal;
            }
            break;

            case HitElement.XZ_SQUARE:
            {
                Vec3F p0         = ray0.IntersectPlane(yAxis, -Vec3F.Dot(yAxis, origin));
                Vec3F p1         = ray.IntersectPlane(yAxis, -Vec3F.Dot(yAxis, origin));
                Vec3F deltaLocal = p1 - p0;
                float dragX      = Vec3F.Dot(xAxis, deltaLocal);
                float dragZ      = Vec3F.Dot(zAxis, deltaLocal);
                Vec3F xLocal     = transform.XAxis;
                Vec3F zLocal     = transform.ZAxis;
                trans = dragX * xLocal + dragZ * zLocal;
            }
            break;
            }
            return(trans);
        }