/*============================================================================= Project: SharpImage Module: siTrackBall.cs Language: C# Author: Dan Mueller Date: $Date: 2007-07-06 10:57:00 +1000 (Fri, 06 Jul 2007) $ Revision: $Revision: 2 $ Copyright (c) Queensland University of Technology (QUT) 2007. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =============================================================================*/ using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using Tao.OpenGl; using Tao.FreeGlut; using Tao.Platform.Windows; using TransformType = itk.itkAffineTransform_D3; namespace SharpImage.Rendering { public class siTrackBall { #region Instance Variables //===================================================================== private itk.itkPoint m_LastPosition; private itk.itkVector m_Axis; private double m_Angle; //===================================================================== #endregion #region Construction and Disposal //===================================================================== /// /// Default contructor. /// public siTrackBall() { // Setup member variables this.m_LastPosition = new itk.itkPoint(0.0, 0.0, 0.0); this.m_Axis = new itk.itkVector(0.0, 0.0, 0.0); this.m_IsTrackingMotion = false; this.m_RotationMatrix.SetIdentity(); // Force a reset this.Reset(); } //===================================================================== #endregion #region Properties //===================================================================== #region IsTrackingMotion //===================================================================== private bool m_IsTrackingMotion = false; /// /// Returns if the trackball is tracking the motion (rotation). /// public bool IsTrackingMotion { get { return this.m_IsTrackingMotion; } set { this.m_IsTrackingMotion = value; } } //===================================================================== #endregion #region RotationMatrix //===================================================================== private itk.itkMatrix m_RotationMatrix = new itk.itkMatrix(3, 3); /// /// Get/set the 3x3 matrix representing the rotation described /// by the trackball. /// public itk.itkMatrix RotationMatrix { get { return this.m_RotationMatrix; } set { this.m_RotationMatrix = value; } } //===================================================================== #endregion //===================================================================== #endregion #region Public Methods //===================================================================== /// /// Reset the trackball. /// public void Reset() { this.m_RotationMatrix.SetIdentity(); this.m_Angle = 0.0; } /// /// Start a rotation motion. /// /// /// /// /// public void StartRotation( int x, int y, int w, int h ) { this.m_IsTrackingMotion = true; this.PToV( x, y, w, h, this.m_LastPosition ); } /// /// Stop a rotation motion. /// public void StopRotation() { this.m_IsTrackingMotion = false; this.m_Angle = 0.0; } /// /// Perform a tracking rotate. /// /// /// /// /// public void TrackRotation( int x, int y, int w, int h ) { if (this.IsTrackingMotion) { itk.itkPoint curPos = new itk.itkPoint(0.0, 0.0, 0.0); double dx, dy, dz; this.PToV(x, y, w, h, curPos); dx = curPos[0] - m_LastPosition[0]; dy = curPos[1] - m_LastPosition[1]; dz = curPos[2] - m_LastPosition[2]; m_Angle = (double)(90.0 * Math.Sqrt(dx*dx + dy*dy + dz*dz)); m_Angle *= siMathHelper.DegreesToRadians; m_Axis[0] = m_LastPosition[1]*curPos[2] - m_LastPosition[2]*curPos[1]; m_Axis[1] = m_LastPosition[2]*curPos[0] - m_LastPosition[0]*curPos[2]; m_Axis[2] = m_LastPosition[0]*curPos[1] - m_LastPosition[1]*curPos[0]; m_LastPosition[0] = curPos[0]; m_LastPosition[1] = curPos[1]; m_LastPosition[2] = curPos[2]; if (this.m_Angle > 0.0) { TransformType transform = TransformType.New(); transform.SetIdentity(); transform.Rotate3D(m_Axis, m_Angle); itk.itkMatrix rotationNew = this.m_RotationMatrix * transform.Matrix; this.m_RotationMatrix = rotationNew; } } } /// /// Return the rotation matrix as an array of doubles. /// /// public double[] GetRotationMatrixAsArray() { // Convert this.RotationMatrix to a 4x4 matrix (for homogenious coords) itk.itkMatrix result = new itk.itkMatrix(4, 4); result.SetIdentity(); for (uint r = 0; r < this.RotationMatrix.NumberOfRows; r++) for (uint c = 0; c < this.RotationMatrix.NumberOfCols; c++) result[r, c] = this.RotationMatrix[r, c]; return result.Data; } //===================================================================== #endregion #region Private Methods //===================================================================== /// /// Project x,y onto a hemi-sphere centered within width, height /// /// /// /// /// /// private void PToV(int x, int y, int width, int height, itk.itkPoint v) { double d = 0.0; double a = 0.0; v[0] = ((double)2.0 * x - width) / width; v[1] = (height - (double)2.0 * y) / height; d = (double)Math.Sqrt(v[0] * v[0] + v[1] * v[1]); v[2] = (double)Math.Cos((Math.PI / 2.0) * ((d < 1.0) ? d : 1.0)); a = (double)(1.0 / Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])); v[0] *= a; v[1] *= a; v[2] *= a; } //===================================================================== #endregion } }