예제 #1
1
        /// <summary>
        /// Handles key-down events</summary>
        /// <param name="sender">Control that raised original event</param>
        /// <param name="e">Event args</param>
        /// <returns>true, if controller handled the event</returns>
        public override bool KeyDown(object sender, KeyEventArgs e)
        {
            m_keyMap[e.KeyValue] = true;

            ControlScheme controlSchm = InputScheme.ActiveControlScheme;
            // W A S D for forward, strafe left, backward, strafe right, is the default
            Vec3F dir = new Vec3F();
            if (m_keyMap[(int)controlSchm.Left1] ||
                m_keyMap[(int)controlSchm.Left2])
                dir = dir - Camera.Right;
            if (m_keyMap[(int)controlSchm.Right1] ||
                m_keyMap[(int)controlSchm.Right2])
                dir = dir + Camera.Right;
            if (m_keyMap[(int)controlSchm.Forward1] ||
                m_keyMap[(int)controlSchm.Forward2])
                dir = dir + Camera.LookAt;
            if (m_keyMap[(int)controlSchm.Back1] ||
                m_keyMap[(int)controlSchm.Back2])
                dir = dir - Camera.LookAt;

            bool handled = controlSchm.IsControllingCamera(Control.ModifierKeys, e);
            

            if (handled)
            {
                dir.Normalize();
                Camera.Set(Camera.Eye + dir * m_scale);
            }

            return handled;
        }
        private Vec3F ProjectToArcball(Point point)
        {
            float x = (float)point.X / (m_width / 2);    // Scale so bounds map to [0,0] - [2,2]
            float y = (float)point.Y / (m_height / 2);

            x = x - 1;                           // Translate 0,0 to the center
            y = 1 - y;                           // Flip so +Y is up
            if (x < -1)
            {
                x = -1;
            }
            else if (x > 1)
            {
                x = 1;
            }
            if (y < -1)
            {
                y = -1;
            }
            else if (y > 1)
            {
                y = 1;
            }

            float z2 = 1 - x * x - y * y;       // z^2 = 1 - x^2 - y^2
            float z  = z2 > 0 ? (float)Math.Sqrt(z2) : 0;

            Vec3F p = new Vec3F(x, y, z);

            p.Normalize();

            return(p);
        }
예제 #3
0
        /// <summary>
        /// Gets the view matrix corresponding to a "look at" point</summary>
        /// <param name="azimuth">Camera pan, in radians</param>
        /// <param name="elevation">Camera tilt, in radians</param>
        /// <param name="lookAt">"Look at" direction</param>
        /// <returns>View matrix corresponding to the "look at" point</returns>
        public static Matrix4F LookAtRotationMatrix(float azimuth, float elevation, Vec3F lookAt)
        {
            double sy = Math.Sin(azimuth);
            double cy = Math.Cos(azimuth);
            double sx = Math.Sin(elevation);
            double cx = Math.Cos(elevation);

            // Calc eye vector as the rotation matrix * (0,0,1)
            Vec3F eye = new Vec3F((float)sy, (float)(-cy * sx), (float)(cy * cx));

            eye = eye + lookAt;

            // Calc up vector as the rotation matrix * (0,1,0)
            Vec3F up = new Vec3F(0, (float)cx, (float)sx);

            Vec3F fvec = lookAt - eye;
            Vec3F f    = Vec3F.Normalize(fvec);
            Vec3F s    = Vec3F.Cross(f, up);
            Vec3F u    = Vec3F.Cross(s, f);

            return(new Matrix4F
                   (
                       s.X, s.Y, s.Z, 0,
                       u.X, u.Y, u.Z, 0,
                       -f.X, -f.Y, -f.Z, 0,
                       0, 0, 0, 1
                   ));
        }
예제 #4
0
        private void TestToStringWithCulture(CultureInfo culture)
        {
            CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture;

            Thread.CurrentThread.CurrentCulture = culture;
            try
            {
                string listSeparator    = culture.TextInfo.ListSeparator;
                string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator;
                var    normal           = new Vec3F(1.1f, 2.2f, 3.3f);
                normal.Normalize();
                var o = new Plane3F(normal, 4.4f);

                string s = o.ToString(null, null);
                TestToStringResults(o, s, listSeparator, decimalSeparator);

                string s2 = o.ToString();
                Assert.AreEqual(s, s2);

                s = o.ToString("G", culture);
                TestToStringResults(o, s, listSeparator, decimalSeparator);

                s = o.ToString("R", culture);
                TestToStringResults(o, s, listSeparator, decimalSeparator);
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = originalCulture;
            }
        }
예제 #5
0
        /// <summary>
        /// Handles key-down events</summary>
        /// <param name="sender">Control that raised original event</param>
        /// <param name="e">Event args</param>
        /// <returns>True if controller handled the event</returns>
        public override bool KeyDown(object sender, KeyEventArgs e)
        {
            m_keyMap[e.KeyValue] = true;

            // W A S D for forward, strafe left, backward, strafe right, is the default
            Vec3F dir = new Vec3F();
            if (m_keyMap[(int)CanvasControl3D.ControlScheme.Left1] ||
                m_keyMap[(int)CanvasControl3D.ControlScheme.Left2])
                dir = dir - Camera.Right;
            if (m_keyMap[(int)CanvasControl3D.ControlScheme.Right1] ||
                m_keyMap[(int)CanvasControl3D.ControlScheme.Right2]) 
                dir = dir + Camera.Right;
            if (m_keyMap[(int)CanvasControl3D.ControlScheme.Forward1] ||
                m_keyMap[(int)CanvasControl3D.ControlScheme.Forward2])
                dir = dir + Camera.LookAt;
            if (m_keyMap[(int)CanvasControl3D.ControlScheme.Back1] ||
                m_keyMap[(int)CanvasControl3D.ControlScheme.Back2])
                dir = dir - Camera.LookAt;

            bool handled = CanvasControl3D.ControlScheme.IsControllingCamera(Control.ModifierKeys, e);

            if (handled)
            {
                dir.Normalize();
                Vec3F p = Camera.Eye;
                float y = p.Y;
                p += dir * m_scale;
                p.Y = y;
                Camera.Set(p);
            }

            return handled;
        }
예제 #6
0
파일: TestPlane3F.cs 프로젝트: Joxx0r/ATF
        private void TestToStringWithCulture(CultureInfo culture)
        {
            CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = culture;
            try
            {
                string listSeparator = culture.TextInfo.ListSeparator;
                string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator;
                var normal = new Vec3F(1.1f, 2.2f, 3.3f);
                normal.Normalize();
                var o = new Plane3F(normal, 4.4f);

                string s = o.ToString(null, null);
                TestToStringResults(o, s, listSeparator, decimalSeparator);

                string s2 = o.ToString();
                Assert.AreEqual(s, s2);

                s = o.ToString("G", culture);
                TestToStringResults(o, s, listSeparator, decimalSeparator);

                s = o.ToString("R", culture);
                TestToStringResults(o, s, listSeparator, decimalSeparator);
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = originalCulture;
            }
        }
예제 #7
0
        /// <summary>
        /// compute ray in  given space starting from
        /// screen space x,y.
        /// The space of the computed ray depends on the value of mtrx:
        ///               world * view * projection // ray in local space (object space).
        ///               view * projection  // ray in world space.
        ///               projection   // ray in view space.
        /// </summary>
        public Ray3F GetRay(Point scrPt, Matrix4F mtrx)
        {
            Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), mtrx);
            Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), mtrx);
            Vec3F dir = Vec3F.Normalize(max - min);
            Ray3F ray = new Ray3F(min, dir);

            return(ray);
        }
예제 #8
0
        public static Ray3F GetRay(this Point scrPt, Matrix4F mtrx, Size controlSize)
        {
            Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), mtrx, controlSize);
            Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), mtrx, controlSize);
            Vec3F dir = Vec3F.Normalize(max - min);
            Ray3F ray = new Ray3F(min, dir);

            return(ray);
        }
예제 #9
0
        /// <summary>
        /// compute ray in world space starting from
        /// screen space x,y.
        /// </summary>
        public Ray3F GetWorldRay(Point scrPt)
        {
            Matrix4F vp  = Camera.ViewMatrix * Camera.ProjectionMatrix;
            Vec3F    min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), vp);
            Vec3F    max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), vp);
            Vec3F    dir = Vec3F.Normalize(max - min);
            Ray3F    ray = new Ray3F(min, dir);

            return(ray);
        }
예제 #10
0
        public override bool MouseMove(object sender, MouseEventArgs e)
        {
            if (m_dragging &&
                InputScheme.ActiveControlScheme.IsControllingCamera(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e)))
            {
                Control c  = sender as Control;
                float   dx = e.X - m_lastMousePointX;
                float   dy = e.Y - m_lastMousePointY;

                if (InputScheme.ActiveControlScheme.IsRotating(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e)) &&
                    (Camera.ViewType == ViewTypes.Perspective || LockOrthographic == false))
                {
                    var orbitRotationSpeed = .0005f * (float)Math.PI;

                    // just do this orbitting calculation in spherical coords...
                    // it's much easier than any other method
                    var orbitCenter = Camera.LookAtPoint;
                    var spherical   = CartesianToSphericalYUp(orbitCenter - Camera.Eye);
                    spherical[0] += dy * orbitRotationSpeed;
                    spherical[0]  = Clamp(spherical[0], (float)Math.PI * 0.02f, (float)Math.PI * 0.98f);
                    spherical[1] += dx * orbitRotationSpeed;

                    var defaultUp = new Vec3F(0.0f, 1.0f, 0.0f);    // (geometry gets hopelessly unnormalized if we don't reset default-up here)
                    Camera.Set(orbitCenter - SphericalToCartesianYUp(spherical), orbitCenter, defaultUp);
                    if (Camera.ViewType != ViewTypes.Perspective)
                    {
                        Camera.ViewType = ViewTypes.Perspective;
                    }
                }
                else if (InputScheme.ActiveControlScheme.IsZooming(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e)))
                {
                    float zoom = (-dy - dx);

                    float adj       = Camera.DistanceFromLookAt;
                    var   zoomSpeed = 0.01f * adj;
                    var   lookAtDir = Vec3F.Normalize(Camera.LookAt);
                    var   movement  = Math.Min(zoom * zoomSpeed, Camera.DistanceFromLookAt - 0.1f);
                    Camera.Set(Camera.Eye + lookAtDir * movement, Camera.LookAtPoint, Camera.Up);
                }
                else if (InputScheme.ActiveControlScheme.IsPanning(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e)))
                {
                    float adj         = Camera.DistanceFromLookAt;
                    var   panSpeed    = 0.001f * adj;
                    var   lookAtPoint = Camera.LookAtPoint;
                    var   translation = (Camera.Up * dy * panSpeed) + (Camera.Right * -dx * panSpeed);
                    Camera.Set(Camera.Eye + translation, lookAtPoint + translation, Camera.Up);
                }

                m_lastMousePointX = e.Location.X;
                m_lastMousePointY = e.Location.Y;
                return(true);
            }

            return(base.MouseMove(sender, e));
        }
예제 #11
0
        private static float CalcAngle(Vec3F origin, Plane3F plane, Ray3F ray0, Ray3F ray1, float snapAngle)
        {
            float theta = 0;
            Vec3F p0;
            Vec3F p1;

            if (ray0.IntersectPlane(plane, out p0) &&
                ray1.IntersectPlane(plane, out p1))
            {
                Vec3F v0 = Vec3F.Normalize(p0 - origin);
                Vec3F v1 = Vec3F.Normalize(p1 - origin);
                theta = CalcAngle(v0, v1, plane.Normal, snapAngle);
            }
            return(theta);
        }
예제 #12
0
        public override bool MouseWheel(object sender, MouseEventArgs e)
        {
            if (!InputScheme.ActiveControlScheme.IsZooming(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e)))
            {
                return(true);
            }

            float adj       = Camera.DistanceFromLookAt;
            var   zoomSpeed = .1f / 120.0f * adj;
            var   lookAtDir = Vec3F.Normalize(Camera.LookAt);
            var   movement  = Math.Min(e.Delta * zoomSpeed, Camera.DistanceFromLookAt - 0.1f);

            Camera.Set(Camera.Eye + lookAtDir * movement, Camera.LookAtPoint, Camera.Up);
            return(true);
        }
        /// <summary>
        /// Handles key-down events</summary>
        /// <param name="sender">Control that raised original event</param>
        /// <param name="e">Event args</param>
        /// <returns>true, if controller handled the event</returns>
        public override bool KeyDown(object sender, KeyEventArgs e)
        {
            m_keyMap[e.KeyValue] = true;

            // W A S D for forward, strafe left, backward, strafe right, is the default
            Vec3F dir = new Vec3F();

            if (m_keyMap[(int)InputScheme.ActiveControlScheme.Left1] ||
                m_keyMap[(int)InputScheme.ActiveControlScheme.Left2])
            {
                dir = dir - Camera.Right;
            }
            if (m_keyMap[(int)InputScheme.ActiveControlScheme.Right1] ||
                m_keyMap[(int)InputScheme.ActiveControlScheme.Right2])
            {
                dir = dir + Camera.Right;
            }
            if (m_keyMap[(int)InputScheme.ActiveControlScheme.Forward1] ||
                m_keyMap[(int)InputScheme.ActiveControlScheme.Forward2])
            {
                dir = dir + Camera.LookAt;
            }
            if (m_keyMap[(int)InputScheme.ActiveControlScheme.Back1] ||
                m_keyMap[(int)InputScheme.ActiveControlScheme.Back2])
            {
                dir = dir - Camera.LookAt;
            }

            bool handled = InputScheme.ActiveControlScheme.IsControllingCamera(Control.ModifierKeys, e);

            if (handled)
            {
                dir.Normalize();
                Vec3F p = Camera.Eye;
                float y = p.Y;
                p  += dir * m_scale;
                p.Y = y;
                Camera.Set(p);
            }

            return(handled);
        }
        private Vec3F ProjectToArcball(Point point)
        {
            float x = (float)point.X / (m_width / 2);    // Scale so bounds map to [0,0] - [2,2]
            float y = (float)point.Y / (m_height / 2);

            x = x - 1;                           // Translate 0,0 to the center
            y = 1 - y;                           // Flip so +Y is up
            if (x < -1)
                x = -1;
            else if (x > 1)
                x = 1;
            if (y < -1)
                y = -1;
            else if (y > 1)
                y = 1;

            float z2 = 1 - x * x - y * y;       // z^2 = 1 - x^2 - y^2
            float z = z2 > 0 ? (float)Math.Sqrt(z2) : 0;

            Vec3F p = new Vec3F(x, y, z);
            p.Normalize();

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

            bool hitAxis = m_hitRegion == HitRegion.XAxis ||
                           m_hitRegion == HitRegion.YAxis ||
                           m_hitRegion == HitRegion.ZAxis;


            Matrix4F view = vc.Camera.ViewMatrix;
            Matrix4F proj = vc.Camera.ProjectionMatrix;
            Matrix4F vp   = view * proj;

            // create ray in world space.
            Ray3F rayW = vc.GetRay(scrPt, vp);

            // create ray in view space.
            Ray3F rayV      = vc.GetRay(scrPt, proj);
            Vec3F translate = m_translatorControl.OnDragging(rayV);

            ISnapSettings snapSettings = (ISnapSettings)DesignView;
            bool          snapToGeom   = Control.ModifierKeys == m_snapGeometryKey;

            if (snapToGeom)
            {
                Vec3F manipPos = HitMatrix.Translation;
                Vec3F manipMove;
                if (hitAxis)
                {
                    //Make rayw to point toward moving axis and starting
                    // from manipulator’s world position.
                    rayW.Direction = Vec3F.Normalize(translate);
                    rayW.Origin    = manipPos;
                    manipMove      = Vec3F.ZeroVector;
                    m_cancelDrag   = true; //stop further snap-to's
                }
                else
                {
                    manipMove = rayW.ProjectPoint(manipPos) - manipPos;
                }

                for (int i = 0; i < NodeList.Count; i++)
                {
                    ITransformable node               = NodeList[i];
                    Vec3F          snapOffset         = TransformUtils.CalcSnapFromOffset(node, snapSettings.SnapFrom);
                    Path <DomNode> path               = new Path <DomNode>(Adapters.Cast <DomNode>(node).GetPath());
                    Matrix4F       parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                    Vec3F          orgPosW;
                    parentLocalToWorld.Transform(m_originalValues[i], out orgPosW);

                    Matrix4F parentWorldToLocal = new Matrix4F();
                    parentWorldToLocal.Invert(parentLocalToWorld);

                    rayW.MoveToIncludePoint(orgPosW + snapOffset + manipMove);

                    HitRecord[] hits    = GameEngine.RayPick(view, proj, rayW, true);
                    bool        cansnap = false;
                    HitRecord   target  = new HitRecord();
                    if (hits.Length > 0)
                    {
                        // find hit record.
                        foreach (var hit in hits)
                        {
                            if (m_snapFilter.CanSnapTo(node, GameEngine.GetAdapterFromId(hit.instanceId)))
                            {
                                target  = hit;
                                cansnap = true;
                                break;
                            }
                        }
                    }

                    if (cansnap)
                    {
                        Vec3F pos;
                        if (target.hasNearestVert && snapSettings.SnapVertex)
                        {
                            pos = target.nearestVertex;
                        }
                        else
                        {
                            pos = target.hitPt;
                        }

                        pos -= snapOffset;
                        parentWorldToLocal.Transform(ref pos);
                        Vec3F diff = pos - node.Transform.Translation;
                        node.Translation += diff;
                        bool rotateOnSnap = snapSettings.RotateOnSnap &&
                                            target.hasNormal &&
                                            (node.TransformationType & TransformationTypes.Rotation) != 0;
                        if (rotateOnSnap)
                        {
                            Vec3F localSurfaceNormal;
                            parentWorldToLocal.TransformNormal(target.normal, out localSurfaceNormal);
                            node.Rotation = TransformUtils.RotateToVector(
                                m_originalRotations[i],
                                localSurfaceNormal,
                                AxisSystemType.YIsUp);
                        }
                    }
                }
            }
            else
            {
                IGrid grid       = DesignView.Context.Cast <IGame>().Grid;
                bool  snapToGrid = Control.ModifierKeys == m_snapGridKey &&
                                   grid.Visible &&
                                   vc.Camera.ViewType == ViewTypes.Perspective;
                float gridHeight = grid.Height;
                // translate.
                for (int i = 0; i < NodeList.Count; i++)
                {
                    ITransformable node = NodeList[i];
                    Path <DomNode> path = new Path <DomNode>(Adapters.Cast <DomNode>(node).GetPath());
                    Matrix4F       parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                    Matrix4F       parentWorldToLocal = new Matrix4F();
                    parentWorldToLocal.Invert(parentLocalToWorld);
                    Vec3F localTranslation;
                    parentWorldToLocal.TransformVector(translate, out localTranslation);
                    Vec3F trans = m_originalValues[i] + localTranslation;

                    if (snapToGrid)
                    {
                        if (grid.Snap)
                        {
                            trans = grid.SnapPoint(trans);
                        }
                        else
                        {
                            trans.Y = gridHeight;
                        }
                    }

                    node.Translation = trans;
                }
            }
        }
예제 #16
0
        public bool Intersect(Ray3F r,
                              out float out_tmin,
                              out float out_tmax,
                              out Vec3F out_pos,
                              out Vec3F out_nor)
        {
            out_pos  = Vec3F.ZeroVector;
            out_nor  = Vec3F.ZeroVector;
            out_tmin = 0.0f;
            out_tmax = 0.0f;

            Vec3F p    = r.Origin;
            Vec3F d    = r.Direction;
            float tmin = float.MinValue;
            float tmax = float.MaxValue;


            // check vs. all three 'slabs' of the aabb
            for (int i = 0; i < 3; ++i)
            {
                if (Math.Abs(d[i]) < float.Epsilon)
                {   // ray is parallel to slab, no hit if origin not within slab
                    if (p[i] < Min[i] || p[i] > Max[i])
                    {
                        return(false);
                    }
                }
                else
                {
                    // compute intersection t values of ray with near and far plane of slab
                    float ood = 1.0f / d[i];
                    float t1  = (Min[i] - p[i]) * ood;
                    float t2  = (Max[i] - p[i]) * ood;
                    tmin = Math.Max(tmin, Math.Min(t1, t2));
                    tmax = Math.Min(tmax, Math.Max(t1, t2));

                    // exit with no collision as soon as slab intersection becomes empty
                    if (tmin > tmax)
                    {
                        return(false);
                    }
                }
            }

            if (tmax < 0.0f)
            {
                // entire bounding box is behind us
                return(false);
            }
            else if (tmin < 0.0f)
            {
                // we are inside the bounding box
                out_tmin = 0.0f;
                out_tmax = tmax;
                out_pos  = p + d * tmax;
                out_nor  = Vec3F.Normalize(Center - out_pos); // use 'sphere' type normal calculation to approximate.
                return(true);
            }
            else
            {
                // ray intersects all 3 slabs. return point and normal of intersection
                out_tmin = tmin;
                out_pos  = p + d * tmin;
                out_nor  = Vec3F.Normalize(Center - out_pos); // use 'sphere' type normal calculation to approximate.
                return(true);
            }
        }
예제 #17
0
        public override void OnDragging(ViewControl vc, Point scrPt)
        {
            if (m_hitRegion == HitRegion.None || NodeList.Count == 0)
            {
                return;
            }
            Camera cam = vc.Camera;

            Matrix4F view = cam.ViewMatrix;
            Matrix4F proj = cam.ProjectionMatrix;

            Matrix4F axisMtrx = HitMatrix * view;
            Ray3F    hitRay   = HitRayV;
            Ray3F    dragRay  = vc.GetRay(scrPt, proj);

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

            Vec3F rotAxis = new Vec3F();
            float theta   = 0;

            float snapAngle = ((ISnapSettings)DesignView).SnapAngle;

            switch (m_hitRegion)
            {
            case HitRegion.XAxis:
            {
                Plane3F xplane = new Plane3F(xAxis, origin);
                theta   = CalcAngle(origin, xplane, hitRay, dragRay, snapAngle);
                rotAxis = HitMatrix.XAxis;
            }
            break;

            case HitRegion.YAxis:
            {
                Plane3F yplane = new Plane3F(yAxis, origin);
                theta   = CalcAngle(origin, yplane, hitRay, dragRay, snapAngle);
                rotAxis = HitMatrix.YAxis;
            }
            break;

            case HitRegion.ZAxis:
            {
                Plane3F zplane = new Plane3F(zAxis, origin);
                theta   = CalcAngle(origin, zplane, hitRay, dragRay, snapAngle);
                rotAxis = HitMatrix.ZAxis;
            }
            break;

            case HitRegion.LookAxis:
            {
                // for billboard objects the look vector is object's negative position in viewspace.
                Vec3F   lookAxis = Vec3F.Normalize(-origin);
                Plane3F plane    = new Plane3F(lookAxis, origin);
                theta   = CalcAngle(origin, plane, hitRay, dragRay, snapAngle);
                rotAxis = m_lookAxisHitMtrx.ZAxis;
            }
            break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            AngleAxisF axf       = new AngleAxisF(-theta, rotAxis);
            Matrix4F   deltaMtrx = new Matrix4F(axf);
            Matrix4F   rotMtrx   = new Matrix4F();

            for (int i = 0; i < NodeList.Count; i++)
            {
                ITransformable node = NodeList[i];
                rotMtrx.Mul(m_rotations[i], deltaMtrx);
                float ax, ay, az;
                rotMtrx.GetEulerAngles(out ax, out ay, out az);
                node.Rotation = new Vec3F(ax, ay, az);
            }
        }