2004-03-25 15:55:25 +01:00
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright ( C ) 2004 \ / ) \ / *
* Visual Computing Lab / \ / | *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved . *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License ( http : //www.gnu.org/licenses/gpl.txt) *
* for more details . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/****************************************************************************
History
$ Log : not supported by cvs2svn $
2006-02-13 14:10:27 +01:00
Revision 1.15 2006 / 01 / 12 15 : 40 : 05 cignoni
Corrected small bugs on rotating after scaling + translating
changed void PlaneMode : : Apply and void SphereMode : : Apply
2006-01-12 16:40:05 +01:00
Revision 1.14 2005 / 07 / 15 16 : 39 : 30 callieri
in SphereMode : : Hit added a check on the sphere intersection , if no intersection , calculating distance could generate a NAN exception
2005-07-15 18:39:30 +02:00
Revision 1.13 2005 / 06 / 29 15 : 22 : 26 callieri
changed the name of some intersection functions to avoid ambiguity
2005-06-29 17:22:26 +02:00
Revision 1.12 2005 / 02 / 11 11 : 44 : 07 tommyfranken
Trackball translation corrected
2005-02-11 12:44:07 +01:00
Revision 1.11 2005 / 02 / 02 16 : 46 : 41 pietroni
some warning corrected
2005-02-02 17:46:41 +01:00
Revision 1.10 2005 / 01 / 14 15 : 44 : 03 ganovelli
PlaneMode completed
2005-01-14 16:44:03 +01:00
Revision 1.9 2004 / 09 / 09 22 : 59 : 21 cignoni
Removed many small warnings
2004-09-10 00:59:21 +02:00
Revision 1.8 2004 / 07 / 18 06 : 54 : 08 cignoni
Added Scaling
2004-07-18 08:54:08 +02:00
Revision 1.7 2004 / 07 / 11 22 : 06 : 56 cignoni
Added scaling by wheel
2004-07-12 00:06:56 +02:00
Revision 1.6 2004 / 06 / 09 14 : 01 : 13 cignoni
Heavily restructured . To be completed only rotation works . . .
2004-06-09 16:01:13 +02:00
Revision 1.5 2004 / 05 / 14 03 : 15 : 09 ponchio
Redesigned partial version .
2004-05-14 05:15:09 +02:00
Revision 1.4 2004 / 05 / 07 12 : 46 : 08 cignoni
Restructured and adapted in a better way to opengl
2004-05-07 14:46:08 +02:00
Revision 1.3 2004 / 04 / 07 10 : 54 : 11 cignoni
Commented out unused parameter names and other minor warning related issues
2004-04-07 12:54:11 +02:00
Revision 1.2 2004 / 03 / 25 14 : 55 : 25 ponchio
Adding copyright .
2004-03-25 15:55:25 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-05-14 05:15:09 +02:00
# include <wrap/gui/trackmode.h>
# include <wrap/gui/trackball.h>
2004-05-07 14:46:08 +02:00
# include <vcg/space/intersection3.h>
2004-03-25 15:50:08 +01:00
# include <vcg/math/similarity.h>
2004-05-14 05:15:09 +02:00
# include <iostream>
2004-03-25 15:50:08 +01:00
2005-06-29 17:22:26 +02:00
2004-07-18 08:54:08 +02:00
using namespace std ;
2004-03-25 15:50:08 +01:00
using namespace vcg ;
2004-07-12 00:06:56 +02:00
void TrackMode : : Apply ( Trackball * trackball , float WheelNotch ) {
trackball - > track . sca * = pow ( 1.2f , WheelNotch ) ;
2004-07-18 08:54:08 +02:00
}
void ScaleMode : : Apply ( Trackball * tb , Point3f new_point ) {
2004-09-10 00:59:21 +02:00
float ScreenHeight = float ( tb - > camera . viewport [ 3 ] - tb - > camera . viewport [ 1 ] ) ;
2004-07-18 08:54:08 +02:00
float dist = ( new_point [ 1 ] - tb - > last_point [ 1 ] ) / ScreenHeight ;
tb - > track . sca = tb - > last_track . sca * pow ( 3.0f , - dist ) ;
}
2004-07-12 00:06:56 +02:00
2004-06-09 16:01:13 +02:00
/// Compute the plane plane perpedicular to view dir and passing through manip center
Plane3f TrackMode : : GetViewPlane ( const View < float > & camera , const Point3f & center ) {
2004-05-14 05:15:09 +02:00
Point3f vp = camera . ViewPoint ( ) ;
2004-06-09 16:01:13 +02:00
Plane3f pl ;
Point3f plnorm = vp - center ;
plnorm . Normalize ( ) ;
pl . Set ( plnorm , plnorm * center ) ;
2004-05-14 05:15:09 +02:00
return pl ;
}
2004-05-07 14:46:08 +02:00
2004-06-09 16:01:13 +02:00
/// Given a point p in window coordinate it compute the point where the lie p
/// over the plane paralell the viewplane and passing through the center of the trackball
2004-05-14 05:15:09 +02:00
Point3f TrackMode : : HitViewPlane ( Trackball * tb , const Point3f & p ) {
// plane perpedicular to view direction and passing through manip center
Plane3f vp = GetViewPlane ( tb - > camera , tb - > center ) ;
2004-05-07 14:46:08 +02:00
2004-05-14 05:15:09 +02:00
Line3fN ln = tb - > camera . ViewLineFromWindow ( Point3f ( p [ 0 ] , p [ 1 ] , 0 ) ) ;
2004-05-07 14:46:08 +02:00
2004-05-14 05:15:09 +02:00
Point3f PonVP ;
2005-06-29 17:22:26 +02:00
/*bool res = */ IntersectionLinePlane < float > ( vp , ln , PonVP ) ;
2004-05-14 05:15:09 +02:00
return PonVP ;
2004-05-07 14:46:08 +02:00
}
2004-06-09 16:01:13 +02:00
// the most important function; given a new point in window coord, it update the transformation computed by the trackball.
// General scheme : the transformation is a function of just the begin and current mouse positions, with greater precision is function of just two 3d points over the manipulator.
2004-05-14 05:15:09 +02:00
void SphereMode : : Apply ( Trackball * tb , Point3f new_point ) {
Point3f hitOld = Hit ( tb , tb - > last_point ) ;
Point3f hitNew = Hit ( tb , new_point ) ;
2006-01-12 16:40:05 +01:00
tb - > Hits . push_back ( hitNew ) ;
2004-05-14 05:15:09 +02:00
2006-01-12 16:40:05 +01:00
// Point3f center = tb->track.tra+tb->center; // original 2006 01 12
Point3f center = tb - > center ;
Point3f axis = ( hitNew - center ) ^ ( hitOld - center ) ;
2004-05-14 05:15:09 +02:00
2004-06-09 16:01:13 +02:00
// Figure out how much to rotate around that axis.
//float phi=Angle((hitNew- tb->center),(hitOld- tb->center));
float phi = Distance ( hitNew , hitOld ) / tb - > radius ;
tb - > track . rot = tb - > last_track . rot * Quaternionf ( phi , axis ) ;
/* Codice Originale Ponchio
2004-05-14 05:15:09 +02:00
2004-06-09 16:01:13 +02:00
Point3f ref = ( tb - > camera . ViewPoint ( ) - tb - > center ) . Normalize ( ) ;
2004-05-14 05:15:09 +02:00
Point3f axis = hitNew ^ ref ;
axis . Normalize ( ) ;
float dist = ( hitNew - ref ) . Norm ( ) / 2 ;
float phi = 2 * math : : Asin ( dist ) ;
Point3f oaxis = hitOld ^ ref ;
oaxis . Normalize ( ) ;
float odist = ( hitOld - ref ) . Norm ( ) / 2 ;
float ophi = 2 * math : : Asin ( odist ) ;
Quaternionf r = tb - > last_track . rot ;
Quaternionf diff = r * Quaternionf ( phi , axis ) *
Quaternionf ( - ophi , oaxis ) * Inverse ( r ) ;
2004-06-09 16:01:13 +02:00
tb - > track = Similarityf ( ) . SetRotate ( diff ) * tb - > last_track ; */
}
/*
dato un punto in coordinate di schermo e . g . in pixel stile opengl
calcola il punto di intersezione tra la viewline che passa per viewpoint e per hitplane e l ' iperboloide .
l ' iperboloide si assume essere quello di rotazione attorno alla retta viewpoint - center e di raggio rad
si assume come sistema di riferimento quello con l ' origine su center ecome x la retta center - viewpoint
eq linea
hitplane . y
y = - - - - - - - - - - - - * x + hitplane . y
viewpoint . x
eq hiperboloide di raggio r ( e . g . che passa per ( r / sqrt2 , r / sqrt2 )
1
y = - - - * ( r ^ 2 / 2.0 )
x
hitplane . y
- - - - - - - - - - - * x ^ 2 - hitplane . y * x + ( r ^ 2 / 2.0 ) = = 0
viewpoint . x
*/
bool SphereMode : : HitHyper ( Point3f center , float radius , Point3f viewpoint , Plane3f vp , Point3f hitplane , Point3f & hit )
{
float hitplaney = Distance ( center , hitplane ) ;
float viewpointx = Distance ( center , viewpoint ) ;
float a = hitplaney / viewpointx ;
float b = - hitplaney ;
float c = radius * radius / 2.0f ;
float delta = b * b - 4 * a * c ;
float x1 , x2 , xval , yval ;
if ( delta > 0 )
{
2004-07-12 00:06:56 +02:00
x1 = ( - b - sqrt ( delta ) ) / ( 2.0f * a ) ;
x2 = ( - b + sqrt ( delta ) ) / ( 2.0f * a ) ;
2004-06-09 16:01:13 +02:00
xval = x1 ; // always take the minimum value solution
yval = c / xval ; // alternatively it also oould be the other part of the equation yval=-(hitplaney/viewpointx)*xval+hitplaney;
}
else
{
return false ;
}
// Computing the result in 3d space;
Point3f dirRadial = hitplane - center ;
dirRadial . Normalize ( ) ;
Point3f dirView = vp . Direction ( ) ;
dirView . Normalize ( ) ;
hit = center + dirRadial * yval + dirView * xval ;
return true ;
2004-05-14 05:15:09 +02:00
}
2004-05-07 14:46:08 +02:00
2004-06-09 16:01:13 +02:00
2004-05-07 14:46:08 +02:00
/* dato un punto in coordinate di schermo e.g. in pixel stile opengl
2004-05-14 05:15:09 +02:00
restituisce un punto in coordinate di mondo sulla superficie
della trackball .
La superficie della trackball e ' data da una sfera + una porzione
di iperboloide di rotazione .
Assumiamo la sfera di raggio unitario e centrata sull ' origine e
di guardare lungo la y negativa .
2004-05-07 14:46:08 +02:00
X 0 sqrt ( 1 / 2 ) 1
eq sfera : y = sqrt ( 1 - x * x ) ; 1 sqrt ( 1 / 2 ) 0
2004-06-09 16:01:13 +02:00
eq iperboloide : y = 1 / 2 * x ; inf sqrt ( 1 / 2 ) 1 / 2
2004-05-14 05:15:09 +02:00
eq cono y = x + sqrt ( 2 ) ;
2004-05-07 14:46:08 +02:00
*/
2004-05-14 05:15:09 +02:00
Point3f SphereMode : : Hit ( Trackball * tb , const Point3f & p ) {
2005-02-02 17:46:41 +01:00
// const float Thr = tb->radius/math::Sqrt(2.0f);
2004-06-09 16:01:13 +02:00
2004-05-14 05:15:09 +02:00
Line3fN vn = tb - > camera . ViewLineFromModel ( tb - > center ) ;
Line3fN ln = tb - > camera . ViewLineFromWindow ( Point3f ( p [ 0 ] , p [ 1 ] , 0 ) ) ;
Point3f viewpoint = tb - > camera . ViewPoint ( ) ;
2005-06-29 17:22:26 +02:00
Plane3f vp = GetViewPlane ( tb - > camera , tb - > center ) ;
2004-06-09 16:01:13 +02:00
Point3f hit , hitPlane , hitSphere , hitSphere1 , hitSphere2 , hitHyper ;
2005-06-29 17:22:26 +02:00
IntersectionLinePlane < float > ( vp , ln , hitPlane ) ;
2004-06-09 16:01:13 +02:00
Sphere3f sphere ( tb - > center , tb - > radius ) ;
2005-06-29 17:22:26 +02:00
bool resSp = IntersectionLineSphere < float > ( sphere , ln , hitSphere1 , hitSphere2 ) ;
2005-07-15 18:39:30 +02:00
if ( resSp = = true )
{
if ( Distance ( viewpoint , hitSphere1 ) < Distance ( viewpoint , hitSphere2 ) )
hitSphere = hitSphere1 ;
else hitSphere = hitSphere2 ;
}
2004-06-09 16:01:13 +02:00
2005-02-02 17:46:41 +01:00
/*float dl=*/ Distance ( ln , tb - > center ) ;
2004-06-09 16:01:13 +02:00
bool resHp = HitHyper ( tb - > center , tb - > radius , viewpoint , vp , hitPlane , hitHyper ) ;
2005-07-15 18:39:30 +02:00
// four cases
// 1) Degenerate line tangent to both sphere and hyperboloid!
2004-06-09 16:01:13 +02:00
if ( ( ! resSp & & ! resHp ) )
{
hit = ClosestPoint ( ln , tb - > center ) ;
//printf("closest point to line %f\n",Distance(hit,tb->center));
return hit ;
2004-05-07 14:46:08 +02:00
}
2004-06-09 16:01:13 +02:00
if ( ( resSp & & ! resHp ) ) return hitSphere ; // 2) line cross only the sphere
if ( ( ! resSp & & resHp ) ) return hitHyper ; // 3) line cross only the hyperboloid
// 4) line cross both sphere and hyperboloid: choose according angle.
float angleDeg = math : : ToDeg ( Angle ( ( viewpoint - tb - > center ) , ( hitSphere - tb - > center ) ) ) ;
//printf("Angle %f (%5.2f %5.2f %5.2f) (%5.2f %5.2f %5.2f)\n",angleDeg,hitSphere[0],hitSphere[1],hitSphere[2],hitHyper[0],hitHyper[1],hitHyper[2]);
if ( angleDeg < 45 ) return hitSphere ;
else return hitHyper ;
2005-07-15 18:39:30 +02:00
//
2004-06-09 16:01:13 +02:00
// Codice ORIGINALE PONCHIO
//vp.SetOffset(vp.Offset() + Thr);
//Point3f hit;
//bool res = Intersection<float>(vp, ln, hit);
//float d = Distance(tb->center - vn.Direction()*Thr, hit);
//if(d < Thr) {
// Point3f hit2;
// Sphere3f sphere(tb->center, tb->radius);
// bool res = Intersection<float>(sphere, ln, hit, hit2);
// //find closest intersection to sphere
// float d = (hit - viewpoint).Norm();
// float d2 = (hit2 - viewpoint).Norm();
// if(d > d2) hit = hit2;
// hit -= tb->center;
//} else {
// if(d > 2.99 * Thr)
// d = 2.99 * Thr;
// Point3f norm = (hit - tb->center)^(viewpoint - tb->center);
// norm.Normalize();
// float phi = -M_PI/4 - 3*M_PI/8 *(d - Thr)/Thr;
// Quaternionf q(phi, norm);
// hit = q.Rotate((viewpoint - tb->center).Normalize() * tb->radius);
//}
// hit.Normalize();
// return hit;
2004-03-25 15:50:08 +01:00
}
2004-05-14 05:15:09 +02:00
void PlaneMode : : Apply ( Trackball * tb , Point3f new_point ) {
2005-02-11 12:44:07 +01:00
Point3f hitOld = HitViewPlane ( tb , tb - > last_point ) ;
Point3f hitNew = HitViewPlane ( tb , new_point ) ;
2006-02-13 14:10:27 +01:00
//Matrix44f m; tb->track.rot.ToMatrix(m);
2006-01-12 16:40:05 +01:00
//tb->track.tra = tb->last_track.tra + Inverse(m)*Point3f(hitNew- hitOld);// orig 2006 01 12
2006-02-13 14:10:27 +01:00
//tb->track.tra = tb->last_track.tra + Inverse(m)*Point3f(hitNew- hitOld)/tb->track.sca;;
tb - > Translate ( hitNew - hitOld ) ;
2004-05-07 14:46:08 +02:00
}
2005-01-14 16:44:03 +01:00
2006-02-13 14:10:27 +01:00
void ZMode : : Apply ( Trackball * tb , Point3f new_point ) {
float ScreenHeight = float ( tb - > camera . viewport [ 3 ] - tb - > camera . viewport [ 1 ] ) ;
float dist = ( new_point [ 1 ] - tb - > last_point [ 1 ] ) / ScreenHeight ;
//Matrix44f m; tb->track.rot.ToMatrix(m);
//tb->track.tra = tb->last_track.tra + Inverse(m)*Point3f(0,0,-2*dist)/tb->track.sca;;
tb - > Translate ( Point3f ( 0 , 0 , - 2 * dist ) ) ;
}
2005-01-14 16:44:03 +01:00