TArcBall.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TArcBall.cxx 21453 2007-12-18 15:18:30Z matevz $
00002 // Author:  Timur Pocheptsov  03/08/2004
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TArcBall.h"
00013 #include "TPoint.h"
00014 #include "TMath.h"
00015 
00016 const Double_t Epsilon = 1.0e-5;
00017 
00018 //______________________________________________________________________________
00019 //
00020 // Implements the arc-ball rotation manipulator.
00021 // Used by plot-painters.
00022 
00023 ClassImp(TArcBall)
00024 
00025 //Arcball sphere constants:
00026 //Diameter is       2.0f
00027 //Radius is         1.0f
00028 
00029 //______________________________________________________________________________
00030 inline void Vector3dCross(Double_t *NewObj, const Double_t * v1, const Double_t *v2)
00031 {
00032    NewObj[0] = v1[1] * v2[2] - v1[2] * v2[1];
00033    NewObj[1] = v1[2] * v2[0] - v1[0] * v2[2];
00034    NewObj[2] = v1[0] * v2[1] - v1[1] * v2[0];
00035 }
00036 
00037 //______________________________________________________________________________
00038 inline Double_t Vector3dDot(const Double_t *NewObj, const Double_t *v1)
00039 {
00040    return  NewObj[0] * v1[0] + NewObj[1] * v1[1] + NewObj[2] * v1[2];
00041 }
00042 
00043 //______________________________________________________________________________
00044 inline Double_t Vector3dLengthSquared(const Double_t *NewObj)
00045 {
00046    return  NewObj[0] * NewObj[0] + NewObj[1] * NewObj[1] + NewObj[2] * NewObj[2];
00047 }
00048 
00049 //______________________________________________________________________________
00050 inline Double_t Vector3dLength(const Double_t *NewObj)
00051 {
00052    return TMath::Sqrt(Vector3dLengthSquared(NewObj));
00053 }
00054 
00055 //______________________________________________________________________________
00056 inline void Matrix3dSetZero(Double_t * NewObj)
00057 {
00058    for (Int_t i = 0; i < 9; ++i)
00059       NewObj[i] = 0.;
00060 }
00061 
00062 //______________________________________________________________________________
00063 inline void Matrix3dSetIdentity(Double_t *NewObj)
00064 {
00065    Matrix3dSetZero(NewObj);
00066    //then set diagonal as 1
00067    NewObj[0] = NewObj[4] = NewObj[8] = 1.;
00068 }
00069 
00070 //______________________________________________________________________________
00071 void Matrix3dSetRotationFromQuat4d(Double_t *NewObj, const Double_t *q1)
00072 {
00073    Double_t n = (q1[0] * q1[0]) + (q1[1] * q1[1]) + (q1[2] * q1[2]) + (q1[3] * q1[3]);
00074    Double_t s = (n > 0.0f) ? (2.0f / n) : 0.0f;
00075    Double_t xs = q1[0] * s,  ys = q1[1] * s,  zs = q1[2] * s;
00076    Double_t wx = q1[3] * xs, wy = q1[3] * ys, wz = q1[3] * zs;
00077    Double_t xx = q1[0] * xs, xy = q1[0] * ys, xz = q1[0] * zs;
00078    Double_t yy = q1[1] * ys, yz = q1[1] * zs, zz = q1[2] * zs;
00079 
00080    NewObj[0] = 1.0f - (yy + zz); NewObj[3] = xy - wz;          NewObj[6] = xz + wy;
00081    NewObj[1] = xy + wz;          NewObj[4] = 1.0f - (xx + zz); NewObj[7] = yz - wx;
00082    NewObj[2] = xz - wy;          NewObj[5] = yz + wx;          NewObj[8] = 1.0f - (xx + yy);
00083 }
00084 
00085 //______________________________________________________________________________
00086 void Matrix3dMulMatrix3d(Double_t *NewObj, const Double_t *m1)
00087 {
00088    Double_t result[9];
00089 
00090    result[0] = (NewObj[0] * m1[0]) + (NewObj[3] * m1[1]) + (NewObj[6] * m1[2]);
00091    result[3] = (NewObj[0] * m1[3]) + (NewObj[3] * m1[4]) + (NewObj[6] * m1[5]);
00092    result[6] = (NewObj[0] * m1[6]) + (NewObj[3] * m1[7]) + (NewObj[6] * m1[8]);
00093 
00094    result[1] = (NewObj[1] * m1[0]) + (NewObj[4] * m1[1]) + (NewObj[7] * m1[2]);
00095    result[4] = (NewObj[1] * m1[3]) + (NewObj[4] * m1[4]) + (NewObj[7] * m1[5]);
00096    result[7] = (NewObj[1] * m1[6]) + (NewObj[4] * m1[7]) + (NewObj[7] * m1[8]);
00097 
00098    result[2] = (NewObj[2] * m1[0]) + (NewObj[5] * m1[1]) + (NewObj[8] * m1[2]);
00099    result[5] = (NewObj[2] * m1[3]) + (NewObj[5] * m1[4]) + (NewObj[8] * m1[5]);
00100    result[8] = (NewObj[2] * m1[6]) + (NewObj[5] * m1[7]) + (NewObj[8] * m1[8]);
00101 
00102    for (Int_t i = 0; i < 9; ++i)
00103       NewObj[i] = result[i];
00104 }
00105 
00106 //______________________________________________________________________________
00107 inline void Matrix4dSetRotationScaleFromMatrix4d(Double_t *NewObj, const Double_t *m1)
00108 {
00109    NewObj[0] = m1[0]; NewObj[4] = m1[4]; NewObj[8] = m1[8];
00110    NewObj[1] = m1[1]; NewObj[5] = m1[5]; NewObj[9] = m1[9];
00111    NewObj[2] = m1[2]; NewObj[6] = m1[6]; NewObj[10] = m1[10];
00112 }
00113 
00114 //______________________________________________________________________________
00115 inline Double_t Matrix4fSVD(const Double_t *NewObj, Double_t *rot3, Double_t *rot4)
00116 {
00117    Double_t s = TMath::Sqrt(
00118                 ( (NewObj[0] * NewObj[0]) + (NewObj[1] * NewObj[1]) + (NewObj[2] * NewObj[2]) +
00119                   (NewObj[4] * NewObj[4]) + (NewObj[5] * NewObj[5]) + (NewObj[6] * NewObj[6]) +
00120                   (NewObj[8] * NewObj[8]) + (NewObj[9] * NewObj[9]) + (NewObj[10] * NewObj[10]) ) / 3.0f );
00121 
00122    if (rot3) {
00123       rot3[0] = NewObj[0]; rot3[1] = NewObj[1]; rot3[2] = NewObj[2];
00124       rot3[3] = NewObj[4]; rot3[4] = NewObj[5]; rot3[5] = NewObj[6];
00125       rot3[6] = NewObj[8]; rot3[7] = NewObj[9]; rot3[8] = NewObj[10];
00126 
00127       Double_t n = 1. / TMath::Sqrt(NewObj[0] * NewObj[0] + NewObj[1] * NewObj[1] + NewObj[2] * NewObj[2] + 0.0001);
00128 
00129       rot3[0] *= n;
00130       rot3[1] *= n;
00131       rot3[2] *= n;
00132 
00133       n = 1. / TMath::Sqrt(NewObj[4] * NewObj[4] + NewObj[5] * NewObj[5] + NewObj[6] * NewObj[6] + 0.0001);
00134       rot3[3] *= n;
00135       rot3[4] *= n;
00136       rot3[5] *= n;
00137 
00138       n = 1.0f / TMath::Sqrt(NewObj[8] * NewObj[8] + NewObj[9] * NewObj[9] + NewObj[10] * NewObj[10] + 0.0001);
00139       rot3[6] *= n;
00140       rot3[7] *= n;
00141       rot3[8] *= n;
00142    }
00143 
00144    if (rot4) {
00145       if (rot4 != NewObj)
00146          Matrix4dSetRotationScaleFromMatrix4d(rot4, NewObj);
00147 
00148       Double_t n = 1. / TMath::Sqrt(NewObj[0] * NewObj[0] + NewObj[1] * NewObj[1] + NewObj[2] * NewObj[2] + 0.0001);
00149 
00150       rot4[0] *= n;
00151       rot4[1] *= n;
00152       rot4[2] *= n;
00153 
00154       n = 1. / TMath::Sqrt(NewObj[4] * NewObj[4] + NewObj[5] * NewObj[5] + NewObj[6] * NewObj[6] + 0.0001);
00155       rot4[4] *= n;
00156       rot4[5] *= n;
00157       rot4[6] *= n;
00158 
00159       n = 1. / TMath::Sqrt(NewObj[8] * NewObj[8] + NewObj[9] * NewObj[9] + NewObj[10] * NewObj[10] + 0.0001);
00160       rot4[8] *= n;
00161       rot4[9] *= n;
00162       rot4[10] *= n;
00163    }
00164 
00165    return s;
00166 }
00167 
00168 //______________________________________________________________________________
00169 inline void Matrix4dSetRotationScaleFromMatrix3d(Double_t *NewObj, const Double_t *m1)
00170 {
00171    NewObj[0] = m1[0]; NewObj[4] = m1[3]; NewObj[8] = m1[6];
00172    NewObj[1] = m1[1]; NewObj[5] = m1[4]; NewObj[9] = m1[7];
00173    NewObj[2] = m1[2]; NewObj[6] = m1[5]; NewObj[10] = m1[8];
00174 }
00175 
00176 //______________________________________________________________________________
00177 inline void Matrix4dMulRotationScale(Double_t *NewObj, Double_t scale)
00178 {
00179    NewObj[0] *= scale; NewObj[4] *= scale; NewObj[8] *= scale;
00180    NewObj[1] *= scale; NewObj[5] *= scale; NewObj[9] *= scale;
00181    NewObj[2] *= scale; NewObj[6] *= scale; NewObj[10] *= scale;
00182 }
00183 
00184 //______________________________________________________________________________
00185 void Matrix4dSetRotationFromMatrix3d(Double_t *NewObj, const Double_t *m1)
00186 {
00187    Double_t scale = Matrix4fSVD(NewObj, 0, 0);
00188    Matrix4dSetRotationScaleFromMatrix3d(NewObj, m1);
00189    Matrix4dMulRotationScale(NewObj, scale);
00190 }
00191 
00192 //______________________________________________________________________________
00193 inline void TArcBall::MapToSphere(const TPoint &NewPt, Double_t *NewVec) const
00194 {
00195    //map to sphere
00196    Double_t tempPt[] = {NewPt.fX, NewPt.fY};
00197    //Adjust point coords and scale down to range of [-1 ... 1]
00198    tempPt[0]  = tempPt[0] * fAdjustWidth  - 1.;
00199    tempPt[1]  = 1. - tempPt[1] * fAdjustHeight;
00200    //Compute the square of the length of the vector to the point from the center
00201    Double_t length = tempPt[0] * tempPt[0] + tempPt[1] * tempPt[1];
00202    //If the point is mapped outside of the sphere... (length > radius squared)
00203    if (length > 1.) {
00204       Double_t norm = 1.0f / TMath::Sqrt(length);
00205       //Return the "normalized" vector, a point on the sphere
00206       NewVec[0] = tempPt[0] * norm;
00207       NewVec[1] = tempPt[1] * norm;
00208       NewVec[2] = 0.;
00209    } else {   //Else it's on the inside
00210     //Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
00211       NewVec[0] = tempPt[0];
00212       NewVec[1] = tempPt[1];
00213       NewVec[2] = TMath::Sqrt(1. - length);
00214    }
00215 }
00216 
00217 //______________________________________________________________________________
00218 TArcBall::TArcBall(UInt_t Width, UInt_t Height)
00219          :fThisRot(), fLastRot(),
00220          fTransform(), fStVec(),
00221          fEnVec(), fAdjustWidth(0.),
00222          fAdjustHeight(0.)
00223 {
00224    // constructor
00225    SetBounds(Width, Height);
00226    ResetMatrices();
00227 }
00228 
00229 //______________________________________________________________________________
00230 void TArcBall::Click(const TPoint &NewPt)
00231 {
00232    //Mouse down
00233    MapToSphere(NewPt, fStVec);
00234 
00235    for (Int_t i = 0; i < 9; ++i)
00236       fLastRot[i] = fThisRot[i];
00237 }
00238 
00239 //______________________________________________________________________________
00240 void TArcBall::Drag(const TPoint &NewPt)
00241 {
00242    //Mouse drag, calculate rotation
00243    MapToSphere(NewPt, fEnVec);
00244    //Return the quaternion equivalent to the rotation
00245    Double_t newRot[4] = {0.};
00246    Double_t perp[3] = {0.};
00247 
00248    Vector3dCross(perp, fStVec, fEnVec);
00249    //Compute the length of the perpendicular vector
00250    if (Vector3dLength(perp) > Epsilon) {
00251    //We're ok, so return the perpendicular vector as the transform after all
00252       newRot[0] = perp[0];
00253       newRot[1] = perp[1];
00254       newRot[2] = perp[2];
00255       //In the quaternion values, w is cosine (theta / 2), where theta is rotation angle
00256       newRot[3]= Vector3dDot(fStVec, fEnVec);
00257    } else  //if it's zero
00258       newRot[0] = newRot[1] = newRot[2] = newRot[3] = 0.;
00259 
00260    Matrix3dSetRotationFromQuat4d(fThisRot, newRot);
00261    Matrix3dMulMatrix3d(fThisRot, fLastRot);
00262    Matrix4dSetRotationFromMatrix3d(fTransform, fThisRot);
00263 }
00264 
00265 //______________________________________________________________________________
00266 void TArcBall::ResetMatrices()
00267 {
00268    //Set rotation matrix as union
00269    fTransform[0] = 1.f, fTransform[1] = fTransform[2] = fTransform[3] =
00270    fTransform[4] = 0.f, fTransform[5] = 1.f, fTransform[6] = fTransform[7] =
00271    fTransform[8] = fTransform[9] = 0.f, fTransform[10] = 1.f, fTransform[11] =
00272    fTransform[12] = fTransform[13] = fTransform[14] = 0.f, fTransform[15] = 1.f;
00273    Matrix3dSetIdentity(fLastRot);
00274    Matrix3dSetIdentity(fThisRot);
00275 }
00276 

Generated on Tue Jul 5 14:18:05 2011 for ROOT_528-00b_version by  doxygen 1.5.1