/*=============================================================================
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
}
}