private void SetupFlowTrackball()
        {
            // Major arrow along x
            ModelVisual3D visual = new ModelVisual3D();
            visual.Content = TrackballGrabber.GetMajorArrow(Axis.X, false, _colors.TrackballAxisMajor, _colors.TrackballAxisSpecular);

            _viewportFlowRotate.Children.Add(visual);
            _flowOrientationVisuals.Add(visual);

            // Create the trackball
            _flowOrientationTrackball = new TrackballGrabber(grdFlowRotateViewport, _viewportFlowRotate, 1d, _colors.TrackballGrabberHoverLight);
            _flowOrientationTrackball.SyncedLights.Add(_lightFlow1);
            _flowOrientationTrackball.RotationChanged += new EventHandler(FlowOrientationTrackball_RotationChanged);

            // Faint lines
            _flowOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLine(Axis.X, true, _colors.TrackballAxisLine));
            _flowOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLineDouble(Axis.Y, _colors.TrackballAxisLine));
            _flowOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLineDouble(Axis.Z, _colors.TrackballAxisLine));
        }
        private void SetupModelTrackball()
        {
            Model3DGroup model = new Model3DGroup();

            // major arrow along x
            model.Children.Add(TrackballGrabber.GetMajorArrow(Axis.X, true, _colors.TrackballAxisMajor, _colors.TrackballAxisSpecular));

            // Minor arrow along z
            model.Children.Add(TrackballGrabber.GetMinorArrow(Axis.Z, true, _colors.TrackballAxisMinor, _colors.TrackballAxisSpecular));

            ModelVisual3D visual = new ModelVisual3D();
            visual.Content = model;

            _viewportModelRotate.Children.Add(visual);
            _modelOrientationVisuals.Add(visual);

            // Create the trackball
            _modelOrientationTrackball = new TrackballGrabber(grdModelRotateViewport, _viewportModelRotate, 1d, _colors.TrackballGrabberHoverLight);
            _modelOrientationTrackball.SyncedLights.Add(_lightModel1);
            _modelOrientationTrackball.RotationChanged += new EventHandler(ModelOrientationTrackball_RotationChanged);

            // Faint lines
            _modelOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLine(Axis.X, false, _colors.TrackballAxisLine));
            _modelOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLineDouble(Axis.Y, _colors.TrackballAxisLine));
            _modelOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLine(Axis.Z, false, _colors.TrackballAxisLine));
        }
        private void SetupToTrackball()
        {
            Model3DGroup model = new Model3DGroup();

            // Major arrow along x
            model.Children.Add(TrackballGrabber.GetMajorArrow(Axis.X, true, _colors.TrackballAxisMajor_To, _colors.TrackballAxisSpecular));

            // Minor arrow along z
            model.Children.Add(TrackballGrabber.GetMinorArrow(Axis.Z, true, _colors.TrackballAxisMinor_To, _colors.TrackballAxisSpecular));

            ModelVisual3D visual = new ModelVisual3D();
            visual.Content = model;

            _viewportTo.Children.Add(visual);
            _orientationVisualsTo.Add(visual);

            // Create the trackball
            _orientationTrackballTo = new TrackballGrabber(grdTo, _viewportTo, 1d, _colors.TrackballGrabberHoverLight);
            _orientationTrackballTo.SyncedLights.Add(_cameraToLight);
            _orientationTrackballTo.RotationChanged += new EventHandler(OrientationTrackballTo_RotationChanged);

            // Faint lines
            _orientationTrackballTo.HoverVisuals.Add(TrackballGrabber.GetGuideLine(Axis.X, false, _colors.TrackballAxisLine_To));
            _orientationTrackballTo.HoverVisuals.Add(TrackballGrabber.GetGuideLineDouble(Axis.Y, _colors.TrackballAxisLine_To));
            _orientationTrackballTo.HoverVisuals.Add(TrackballGrabber.GetGuideLine(Axis.Z, false, _colors.TrackballAxisLine_To));
        }
        private void SetupGravityTrackball()
        {
            // major arrow along x
            ModelVisual3D visual = new ModelVisual3D();
            visual.Content = TrackballGrabber.GetMajorArrow(Axis.X, true, _colors.TrackballAxisMajor, _colors.TrackballAxisSpecular);

            _viewportGravityRotate.Children.Add(visual);
            _gravityOrientationVisuals.Add(visual);

            // Create the trackball
            _gravityOrientationTrackball = new TrackballGrabber(grdGravityRotateViewport, _viewportGravityRotate, 1d, _colors.TrackballGrabberHoverLight);
            _gravityOrientationTrackball.SyncedLights.Add(_lightGravity1);
            _gravityOrientationTrackball.RotationChanged += new EventHandler(GravityOrientationTrackball_RotationChanged);

            // Faint lines
            _gravityOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLine(Axis.X, false, _colors.TrackballAxisLine));
            _gravityOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLineDouble(Axis.Y, _colors.TrackballAxisLine));
            _gravityOrientationTrackball.HoverVisuals.Add(TrackballGrabber.GetGuideLineDouble(Axis.Z, _colors.TrackballAxisLine));

            // The trackball's axis that is showing is X, but I want gravity to start out down
            _gravityOrientationTrackball.Transform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), -90));
        }
        private static void EnsureSnapped45(TrackballGrabber trackball)
        {
            //TODO:  I think this is invalid thinking.  Instead?:
            //		Use the quaternion to project a vector
            //		Snap that projected vector to the nearest aligned vector
            //		Get a new quaternion that describes how to rotate to that snapped vector

            //TODO:  When the trackball's transform is set, the lights get screwed up

            Quaternion currentOrientation = trackball.Transform.ToQuaternion();

            // Snap the axis to nearest 45
            Vector3D snappedAxis = currentOrientation.Axis;

            // Snap the angle to nearest 45
            double snappedAngle = GetSnappedAngle(currentOrientation.Angle, 45d);

            trackball.Transform = new RotateTransform3D(new AxisAngleRotation3D(snappedAxis, snappedAngle));
        }