Trackball Improvement. Now it works well also for ortho views

This commit is contained in:
Paolo Cignoni 2014-11-04 23:16:04 +00:00
parent 63046a8bab
commit 1ff3a301ec
3 changed files with 266 additions and 285 deletions

View File

@ -8,7 +8,7 @@
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* 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. *
@ -41,8 +41,8 @@ void TrackMode::SetAction (){}
void TrackMode::Reset (){}
bool TrackMode::IsAnimating(const Trackball *){
return false;
bool TrackMode::IsAnimating(const Trackball *){
return false;
}
void TrackMode::Animate(unsigned int, Trackball *){
@ -58,12 +58,12 @@ void TrackMode::Undo(){}
void InactiveMode::Draw(Trackball * tb){
DrawSphereIcon(tb,false);
}
// Sphere mode implementation.
// 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
// 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.
void SphereMode::Apply (Trackball * tb, Point3f new_point)
{
@ -72,9 +72,13 @@ void SphereMode::Apply (Trackball * tb, Point3f new_point)
tb->Hits.push_back (hitNew);
Point3f center = tb->center;
Point3f axis = (hitNew - center) ^ (hitOld - center);
vcg::Normalize(axis);
// Figure out how much to rotate around that axis.
float phi = Distance (hitNew, hitOld) / tb->radius;
// tb->track.rot = tb->last_track.rot * Quaternionf (-phi, axis);
// float phi = Distance (hitNew, hitOld) / tb->radius;
// float phi = vcg::Angle(hitNew - center,hitOld - center)*(Distance(hitNew,center)/tb->radius);
float phi = max(vcg::Angle(hitNew - center,hitOld - center),(Distance(hitNew,hitOld)/tb->radius)) ;
tb->track.rot = Quaternionf (-phi, axis) * tb->last_track.rot;
}
@ -120,7 +124,7 @@ void ScaleMode::Apply (Trackball * tb, float WheelNotch)
{
tb->track.sca *= pow (1.2f, -WheelNotch);
}
void ScaleMode::Apply (Trackball * tb, Point3f new_point)
{
tb->track.sca = tb->last_track.sca * pow (3.0f, -(getDeltaY(tb,new_point)));
@ -157,7 +161,7 @@ void PlaneMode::Apply (Trackball * tb, Point3f new_point)
std::pair< Point3f, bool > hitOld = HitPlane(tb,tb->last_point,plane);
std::pair< Point3f, bool > hitNew = HitPlane(tb,new_point,plane);
if(hitOld.second && hitNew.second){
tb->Translate (hitNew.first - hitOld.first);
tb->Translate (hitNew.first - hitOld.first);
}
}
@ -170,7 +174,7 @@ void PlaneMode::Draw(Trackball * tb){
void CylinderMode::Apply (Trackball * tb, float WheelNotch)
{
const float PI2=6.283185307179586232f;
float angle= (snap==0.0) ? WheelNotch/(tb->radius * PI2) : WheelNotch * snap;
float angle= (snap==0.0) ? WheelNotch/(tb->radius * PI2) : WheelNotch * snap;
tb->track.rot = tb->last_track.rot * Quaternionf (angle,axis.Direction());
}
@ -182,12 +186,12 @@ void CylinderMode::Apply (Trackball * tb, Point3f new_point)
float angle;
const float EPSILON=0.005f; // this IS scale independent
if(axisproj.Direction().Norm() < EPSILON){
angle=(10.0f * getDeltaY(tb,new_point)) / tb->radius;
angle=(10.0f * getDeltaY(tb,new_point)) / tb->radius;
} else {
Point3f hitOld = HitViewPlane (tb, tb->last_point);
Point3f hitNew = HitViewPlane (tb, new_point);
axisproj.Normalize();
Point3f plusdir= viewplane.Direction() ^ axisproj.Direction();
Point3f plusdir= viewplane.Direction() ^ axisproj.Direction();
float distOld = signedDistance(axisproj,hitOld,plusdir);
float distNew = signedDistance(axisproj,hitNew,plusdir);
angle= (distNew-distOld) / tb->radius;
@ -239,31 +243,31 @@ Point3f PathMode::SetStartNear(Point3f point)
Point3f p0,p1;
float nearest_state=0;
Point3f nearest_point=points[0];
float nearest_distance=Distance(nearest_point,point);
float nearest_distance=Distance(nearest_point,point);
unsigned int npts = int(points.size());
for(unsigned int i = 1;i <= npts;i++){
if( i == npts){
if (wrap){
p0=points[npts-1];
p1=points[0];
} else {
break;
}
} else {
p0=points[i-1];
p1=points[i];
}
if( i == npts){
if (wrap){
p0=points[npts-1];
p1=points[0];
} else {
break;
}
} else {
p0=points[i-1];
p1=points[i];
}
//Point3f segment_point=ClosestPoint(Segment3f(p0,p1),point);
Point3f segment_point;
float distance;
vcg::SegmentPointDistance<float>(Segment3f(p0,p1),point,segment_point,distance);
// float distance=Distance(segment_point,point);
Point3f segment_point;
float distance;
vcg::SegmentPointDistance<float>(Segment3f(p0,p1),point,segment_point,distance);
// float distance=Distance(segment_point,point);
if(distance<nearest_distance){
nearest_point=segment_point;
nearest_distance=distance;
nearest_state=p0_state+(Distance(p0,nearest_point)/path_length);
}
float segment_norm= Distance(p0,p1) / path_length;
}
float segment_norm= Distance(p0,p1) / path_length;
p0_state+=segment_norm;
}
assert( nearest_state >= 0.0 );
@ -278,22 +282,22 @@ Point3f PathMode::SetStartNear(Point3f point)
void PathMode::GetPoints(float state, Point3f & point, Point3f & prev_point, Point3f & next_point)
{
assert(state >= 0.0f);
assert(state <= 1.0f);
float remaining_norm=state;
assert(state <= 1.0f);
float remaining_norm=state;
Point3f p0(0,0,0),p1(0,0,0);
unsigned int npts = int(points.size());
for(unsigned int i = 1;i <= npts;i++){
if( i == npts){
if (wrap){
p0=points[npts-1];
p1=points[0];
} else {
break;
}
} else {
p0=points[i-1];
p1=points[i];
}
if( i == npts){
if (wrap){
p0=points[npts-1];
p1=points[0];
} else {
break;
}
} else {
p0=points[i-1];
p1=points[i];
}
float segment_norm= Distance(p0,p1) / path_length;
if (segment_norm < remaining_norm){
remaining_norm -= segment_norm;
@ -303,28 +307,28 @@ void PathMode::GetPoints(float state, Point3f & point, Point3f & prev_point, Poi
next_point = p1;
float ratio= remaining_norm / segment_norm;
point = prev_point + (( next_point - prev_point ) * ratio);
const float EPSILON=min_seg_length * 0.01f;
const float EPSILON=min_seg_length * 0.01f;
if(Distance(point,prev_point) < EPSILON){
point=prev_point;
if (i > 1){
prev_point=points[i-2];
prev_point=points[i-2];
} else if (wrap){
prev_point=points[npts-1];
}
}
} else if (Distance(point,next_point) < EPSILON){
point=next_point;
if( i < (npts-1)){
next_point=points[i+1];
next_point=points[i+1];
} else {
if (wrap){
next_point=points[1];
} else {
next_point=points[npts-1];
}
}
if (wrap){
next_point=points[1];
} else {
next_point=points[npts-1];
}
}
}
return;
}
}
// rounding errors can lead out of the for..
prev_point = p0;
point = p1;
@ -346,7 +350,7 @@ void PathMode::Apply (Trackball * tb, float WheelNotch)
GetPoints(current_state,old_point,prev_point,next_point);
current_state=Normalize(current_state+delta);
GetPoints(current_state,new_point,prev_point,next_point);
tb->Translate (new_point - old_point);
tb->Translate (new_point - old_point);
}
float PathMode::Normalize(float state)
@ -360,9 +364,9 @@ float PathMode::Normalize(float state)
return fractpart;
}
if ( state < 0.0f )
return 0.0f;
return 0.0f;
if ( state > 1.0f )
return 1.0f;
return 1.0f;
return state;
}
@ -401,7 +405,7 @@ float PathMode::HitPoint(float state, Ray3fN ray, Point3f &hit_point)
{
Point3f current_point, next_point, prev_point;
GetPoints(state,current_point,prev_point,next_point);
Point3f closest_point;
closest_point=ray.ClosestPoint(current_point);
int verse=Verse(closest_point,current_point,prev_point,next_point);
@ -409,26 +413,26 @@ float PathMode::HitPoint(float state, Ray3fN ray, Point3f &hit_point)
hit_point=current_point;
return 0.0f;
}
Segment3f active_segment;
if (verse > 0){
active_segment=Segment3f(current_point,next_point);
active_segment=Segment3f(current_point,next_point);
} else {
active_segment= Segment3f(current_point,prev_point);
}
}
//hit_point=ClosestPoint(active_segment,closest_point);
float dist;
vcg::SegmentPointDistance<float>(active_segment,closest_point,hit_point,dist);
float dist;
vcg::SegmentPointDistance<float>(active_segment,closest_point,hit_point,dist);
return verse * ((hit_point-current_point).Norm() / path_length);
}
}
void PathMode::SetAction (){
Point3f temp1,temp2;
Point3f temp1,temp2;
GetPoints(current_state,old_hitpoint,temp1,temp2);
}
void PathMode::Apply (Trackball * tb, Point3f new_point)
{
undo_current_state=current_state;
@ -462,7 +466,7 @@ void PathMode::Draw(Trackball * tb){
void AreaMode::Init(const std::vector < Point3f > &pts)
{
unsigned int npts = int(pts.size());
assert(npts >= 3);
//get the plane
Point3f p0=pts[0];
@ -471,38 +475,38 @@ void AreaMode::Init(const std::vector < Point3f > &pts)
bool pts_not_in_line=false;
Point3f a,b;
for(unsigned int i=0;i<onethird;i++){
a=(pts[(i+ onethird )%npts] - pts[i%npts]).normalized();
b=(pts[(i+(2*onethird))%npts] - pts[i%npts]).normalized();
a=(pts[(i+ onethird )%npts] - pts[i%npts]).normalized();
b=(pts[(i+(2*onethird))%npts] - pts[i%npts]).normalized();
pts_not_in_line = (a ^ b).Norm() > EPSILON;
if(pts_not_in_line){
plane.Init( pts[i%npts],
pts[(i+(onethird))%npts],
plane.Init( pts[i%npts],
pts[(i+(onethird))%npts],
pts[(i+(2*onethird))%npts]);
break;
break;
}
}
assert(pts_not_in_line);
assert(pts_not_in_line);
float ncx,ncy,ncz;
ncx=fabs(plane.Direction()[0]);
ncy=fabs(plane.Direction()[1]);
ncz=fabs(plane.Direction()[2]);
ncz=fabs(plane.Direction()[2]);
if(( ncx > ncy ) && ( ncx > ncz )){
first_coord_kept=1;
second_coord_kept=2;
} else if(( ncy > ncx ) && ( ncy > ncz)){
first_coord_kept=0;
second_coord_kept=2;
} else {
} else {
first_coord_kept=0;
second_coord_kept=1;
}
points.reserve(npts);
points.reserve(npts);
for(unsigned int i=0;i<npts;i++){
points.push_back(plane.Projection(pts[i]));
points.push_back(plane.Projection(pts[i]));
}
min_side_length=Distance(points[0],points[1]);
for(unsigned int i=1;i<npts;i++){
min_side_length=(std::min)(Distance(points[i-1],points[i]),min_side_length);
min_side_length=(std::min)(Distance(points[i-1],points[i]),min_side_length);
}
rubberband_handle=old_status=status=initial_status=p0;
}
@ -523,26 +527,26 @@ void AreaMode::Apply (Trackball * tb, Point3f new_point)
undo_path_index=path.size();
if(begin_action){
delta_mouse=tb->camera.Project(status)-new_point;
begin_action=false;
}
delta_mouse=tb->camera.Project(status)-new_point;
begin_action=false;
}
std::pair< Point3f, bool > hitNew = HitPlane(tb,new_point+delta_mouse,plane);
if(! hitNew.second){
return;
return;
}
Point3f hit_point=hitNew.first;
Point3f hit_point=hitNew.first;
Point3f delta_status=Move(status,hit_point);
status += delta_status;
tb->Translate (status - old_status);
tb->Translate (status - old_status);
rubberband_handle=hit_point;
}
void AreaMode::SetAction ()
{
begin_action=true;
begin_action=true;
old_status=status;
path.clear();
path.push_back(status);
rubberband_handle=status;
@ -555,44 +559,44 @@ Point3f AreaMode::Move(Point3f start,Point3f end)
bool done=false;
bool end_inside=Inside(end);
while(!done){
path.push_back(pt);
path.push_back(pt);
Segment3f segment(pt,end);
bool p_on_side = false;
bool hit=false;
Point3f pside(0,0,0),phit(0,0,0);
bool slide=false,mid_inside=false;
int np = int(points.size()), i, j;
for (i = 0, j = np-1; i < np; j = i++) {
Segment3f side(points[i],points[j]);
Point3f pseg,psid;
//std::pair<float,bool> res=SegmentSegmentDistance(segment,side,pseg,psid);
std::pair<float,bool> res;
vcg::SegmentSegmentDistance(segment,side,res.first,res.second,pseg,psid);
std::pair<float,bool> res;
vcg::SegmentSegmentDistance(segment,side,res.first,res.second,pseg,psid);
if(res.first < EPSILON && ! res.second){
float dist= Distance(pt,pseg);
if(dist < EPSILON){
float dist= Distance(pt,pseg);
if(dist < EPSILON){
//Point3f pn=ClosestPoint(side,end);
Point3f pn;
float dist;
vcg::SegmentPointDistance<float>(side,end,pn,dist);
Point3f pn;
float dist;
vcg::SegmentPointDistance<float>(side,end,pn,dist);
if(!p_on_side || (Distance(pn,end)<Distance(end,pside))){
pside=pn;
p_on_side=true;
}
} else {
if (!hit || Distance(pt,pseg) < Distance(pt,phit)){
phit=pseg;
hit=true;
}
}
} else {
if (!hit || Distance(pt,pseg) < Distance(pt,phit)){
phit=pseg;
hit=true;
}
}
}
}
if (p_on_side)
slide = Distance(pside,pt) > EPSILON;
if (hit)
if (hit)
mid_inside = Inside( pt + ( ( phit - pt ) / 2) );
if ( !hit && end_inside ){
@ -600,16 +604,16 @@ Point3f AreaMode::Move(Point3f start,Point3f end)
done = true;
} else if ( hit && (!p_on_side || (p_on_side && mid_inside))) {
pt = phit;
} else if ( p_on_side && slide) {
} else if ( p_on_side && slide) {
pt = pside;
} else {
done = true;
}
}
}
path.push_back(pt);
path.push_back(pt);
return pt - start;
}
// adapted from the original C code by W. Randolph Franklin
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
bool AreaMode::Inside(Point3f point)
@ -620,15 +624,15 @@ bool AreaMode::Inside(Point3f point)
float yi, yj, xi, xj;
int i, j, np=int(points.size());
for (i = 0, j = np-1; i < np; j = i++) {
xi=points[i][first_coord_kept];
yi=points[i][second_coord_kept];
xj=points[j][first_coord_kept];
yj=points[j][second_coord_kept];
xi=points[i][first_coord_kept];
yi=points[i][second_coord_kept];
xj=points[j][first_coord_kept];
yj=points[j][second_coord_kept];
if ( ( ( (yi<=y) && (y<yj) ) || ( (yj<=y) && (y<yi) ) ) &&
( x < ( xj - xi ) * ( y - yi ) / ( yj - yi ) + xi ) )
{
inside=!inside;
}
inside=!inside;
}
}
return inside;
}
@ -641,19 +645,19 @@ Point3f AreaMode::SetStartNear(Point3f point)
return initial_status;
}
Point3f nearest_point=initial_status;
float nearest_distance=Distance(nearest_point,candidate);
float nearest_distance=Distance(nearest_point,candidate);
int i, j, np=int(points.size());
for (i = 0, j = np-1; i < np; j = i++) {
Segment3f side(points[i],points[j]);
//Point3f side_point=ClosestPoint(side,candidate);
//float distance=Distance(side_point,candidate);
Point3f side_point;
float distance;
vcg::SegmentPointDistance<float>(side,candidate,side_point,distance);
Point3f side_point;
float distance;
vcg::SegmentPointDistance<float>(side,candidate,side_point,distance);
if( distance < nearest_distance ){
nearest_point=side_point;
nearest_distance=distance;
}
}
}
initial_status=nearest_point;
return initial_status;
@ -696,7 +700,7 @@ void PolarMode::Apply (Trackball * tb, Point3f new_point)
endb = beta + angley;
if(endb > top) endb = top;
if(endb < -top) endb = -top;
tb->track.rot = Quaternionf (endb, Point3f(1,0,0)) *
tb->track.rot = Quaternionf (endb, Point3f(1,0,0)) *
Quaternionf (enda, Point3f(0,1,0)) ;
}
@ -718,20 +722,20 @@ void PolarMode::Draw(Trackball * tb){
// Navigator WASD implementation
NavigatorWasdMode::NavigatorWasdMode() {
NavigatorWasdMode::NavigatorWasdMode() {
_flipH=1; _flipV=1;
SetTopSpeedsAndAcc(1,1,4);
step_height = step_length = 0;
Reset();
step_height = step_length = 0;
Reset();
};
void NavigatorWasdMode::Reset() {
alpha=0;
beta=0;
current_speed.SetZero();
step_x=0.0f;
beta=0;
current_speed.SetZero();
step_x=0.0f;
step_current = step_last = 0.0;
step_current = step_last = 0.0;
}
void NavigatorWasdMode::FlipH(){
@ -744,56 +748,56 @@ void NavigatorWasdMode::FlipV(){
void NavigatorWasdMode::SetAction() {
}
bool NavigatorWasdMode::IsAnimating(const Trackball * tb){
const unsigned int MOVEMENT_KEY_MASK = (const unsigned int)(~Trackball::MODIFIER_MASK);
if (tb->current_button & MOVEMENT_KEY_MASK) return true;
if (current_speed!=Point3f(0,0,0)) return true;
if (step_current>0.0) return true;
return false;
const unsigned int MOVEMENT_KEY_MASK = (const unsigned int)(~Trackball::MODIFIER_MASK);
if (tb->current_button & MOVEMENT_KEY_MASK) return true;
if (current_speed!=Point3f(0,0,0)) return true;
if (step_current>0.0) return true;
return false;
}
void NavigatorWasdMode::Animate(unsigned int msec, Trackball * tb){
vcg::Point3f acc(0,0,0);
float sa = sin(-alpha);
float ca = cos(-alpha);
if (tb->current_button & Trackball::KEY_UP ) acc += vcg::Point3f( sa,0,ca)*(accY*_flipH);
if (tb->current_button & Trackball::KEY_DOWN ) acc -= vcg::Point3f( sa,0,ca)*(accY*_flipH);
if (tb->current_button & Trackball::KEY_LEFT ) acc -= vcg::Point3f(-ca,0,sa)*accX;
if (tb->current_button & Trackball::KEY_RIGHT ) acc += vcg::Point3f(-ca,0,sa)*accX;
if (tb->current_button & Trackball::KEY_PGUP ) acc -= vcg::Point3f( 0,1, 0)*accZ;
if (tb->current_button & Trackball::KEY_PGDOWN) acc += vcg::Point3f( 0,1, 0)*accZ;
float sec = msec/1.0f;
current_speed += acc*sec;
tb->track.tra+=current_speed*sec;
// compute step height.
Point3f current_speed_h = current_speed;
current_speed_h[1]=0;
float vel = current_speed_h.Norm();
if (vel<topSpeedH*0.05) {
vcg::Point3f acc(0,0,0);
float sa = sin(-alpha);
float ca = cos(-alpha);
if (tb->current_button & Trackball::KEY_UP ) acc += vcg::Point3f( sa,0,ca)*(accY*_flipH);
if (tb->current_button & Trackball::KEY_DOWN ) acc -= vcg::Point3f( sa,0,ca)*(accY*_flipH);
if (tb->current_button & Trackball::KEY_LEFT ) acc -= vcg::Point3f(-ca,0,sa)*accX;
if (tb->current_button & Trackball::KEY_RIGHT ) acc += vcg::Point3f(-ca,0,sa)*accX;
if (tb->current_button & Trackball::KEY_PGUP ) acc -= vcg::Point3f( 0,1, 0)*accZ;
if (tb->current_button & Trackball::KEY_PGDOWN) acc += vcg::Point3f( 0,1, 0)*accZ;
float sec = msec/1.0f;
current_speed += acc*sec;
tb->track.tra+=current_speed*sec;
// compute step height.
Point3f current_speed_h = current_speed;
current_speed_h[1]=0;
float vel = current_speed_h.Norm();
if (vel<topSpeedH*0.05) {
// stopped: decrease step heigth to zero
step_current*=pow(dumping,sec);
step_current*=pow(dumping,sec);
if (step_current<step_height*0.06) { step_current=0; step_x=0.0f;}
} else {
// running: rise step heigth
vel = current_speed.Norm();
step_x += vel*sec;
float step_current_min = (float)fabs(sin( step_x*M_PI / step_length ))*step_height;
if (step_current<step_current_min) step_current=step_current_min;
}
step_x += vel*sec;
float step_current_min = (float)fabs(sin( step_x*M_PI / step_length ))*step_height;
if (step_current<step_current_min) step_current=step_current_min;
}
current_speed*=pow(dumping,sec);
if (current_speed.Norm()<topSpeedH*0.005) current_speed.SetZero(); // full stop
current_speed*=pow(dumping,sec);
if (current_speed.Norm()<topSpeedH*0.005) current_speed.SetZero(); // full stop
tb->track.tra[1]+=step_last;
tb->track.tra[1]-=step_current;
step_last=step_current;
step_last=step_current;
//tb->track.tra[1]+=0.01;
}
@ -801,7 +805,7 @@ void NavigatorWasdMode::Apply (Trackball * tb, Point3f new_point)
{
Point3f hitOld = tb->last_point;
Point3f hitNew = new_point;
tb->last_point=new_point;
tb->last_point=new_point;
float dx = (hitNew.X() - hitOld.X());
float dy = (hitNew.Y() - hitOld.Y());
@ -816,15 +820,15 @@ void NavigatorWasdMode::Apply (Trackball * tb, Point3f new_point)
if(beta < -top) beta = -top;
Point3f viewpoint = tb->track.InverseMatrix()*Point3f(0,0,0);
tb->track.tra = tb->track.rot.Inverse().Rotate(tb->track.tra + viewpoint ) ;
tb->track.rot = Quaternionf (beta , Point3f(1,0,0)) *
tb->track.tra = tb->track.rot.Inverse().Rotate(tb->track.tra + viewpoint ) ;
tb->track.rot = Quaternionf (beta , Point3f(1,0,0)) *
Quaternionf (alpha, Point3f(0,1,0)) ;
tb->track.tra = tb->track.rot.Rotate(tb->track.tra) - viewpoint ;
tb->track.tra = tb->track.rot.Rotate(tb->track.tra) - viewpoint ;
tb->track.tra[1]+=step_last;
tb->track.tra[1]+=step_last;
tb->track.tra[1]-=step_current;
step_last=step_current;
step_last=step_current;
}
@ -833,7 +837,7 @@ void NavigatorWasdMode::SetTopSpeedsAndAcc(float hspeed, float vspeed, float acc
hspeed /= 1000;
vspeed /= 1000;
acc /= 1000000;
accX = accY = acc;
dumping = hspeed / ( hspeed + acc );
accZ = ( vspeed / dumping ) - vspeed;
@ -843,11 +847,11 @@ void NavigatorWasdMode::SetTopSpeedsAndAcc(float hspeed, float vspeed, float acc
dumping=0.0;
}
topSpeedH = hspeed; topSpeedV=vspeed;
}
void NavigatorWasdMode::SetStepOnWalk(float width, float height){
step_length = width;
step_length = width;
step_height = height;
}
@ -858,5 +862,5 @@ void NavigatorWasdMode::Apply (Trackball * tb, float WheelNotch)
bool NavigatorWasdMode::isSticky(){
return false;
return false;
}

View File

@ -20,51 +20,7 @@
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.13 2008/02/26 18:46:55 ponchio
Fixed bug in drawing position of the trackball when changin center.
Revision 1.12 2008/02/24 18:10:54 ponchio
Fixed scale behaviour.
Revision 1.11 2008/02/24 18:05:08 ponchio
Should work as before. I didn't test cylinder and other exotic modes.
Revision 1.10 2008/02/24 14:37:00 ponchio
Restored trackball functionality. Not very much tested, and code will need some
cleanup.
Revision 1.9 2008/02/22 18:57:47 benedetti
first attempt to correct after quaternion ToMatrix() inversion (does not work yet)
Revision 1.8 2008/02/15 20:54:45 benedetti
removed some variable initialization related warning
Revision 1.7 2007/10/22 14:39:54 cignoni
corrected bug into the drawsphere (thanks to nico and guido!)
Revision 1.6 2007/08/17 09:19:40 cignoni
glEnable (GL_LINE_SMOOTH) should go before changing the linewidth.
Revision 1.5 2007/07/14 12:44:40 benedetti
Minor edits in Doxygen documentation.
Revision 1.4 2007/07/09 22:41:22 benedetti
Added Doxygen documentation, removed using namespace std, some other minor changes.
Revision 1.3 2007/06/12 08:58:08 benedetti
Minor fix in DrawUglyCylinderMode()
Revision 1.2 2007/05/28 08:10:47 fiorin
Removed type cast warnings
Revision 1.1 2007/05/15 14:57:34 benedetti
Utility functions for the trackmodes, first version
****************************************************************************/
#ifndef TRACKUTILS_H
#define TRACKUTILS_H
@ -144,24 +100,24 @@ Point3f HitViewPlane (Trackball * tb, const Point3f & p)
<br>The original documentation (in italian) follows:
<pre>
dato un punto in coordinate di schermo e.g. in pixel stile opengl
calcola il punto di intersezione tra la viewline che passa per
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
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
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
y = - ----------- * x + hitplane.y
viewpoint.x
eq hiperboloide di raggio r (e.g. che passa per (r/sqrt2,r/sqrt2)
eq hiperboloide di raggio r (e.g. che passa per (r/sqrt2,r/sqrt2)
1
y = --- * (r^2 /2.0)
x
x
hitplane.y
----------- * x^2 - hitplane.y *x + (r^2/2.0) == 0
@ -214,16 +170,16 @@ bool HitHyper (Point3f center, float radius, Point3f viewpoint, Plane3f vp,
<br>The original documentation (in italian) follows:
<pre>
dato un punto in coordinate di schermo e.g. in pixel stile opengl
restituisce un punto in coordinate di mondo sulla superficie
dato un punto in coordinate di schermo e.g. in pixel stile opengl
restituisce un punto in coordinate di mondo sulla superficie
della trackball.
La superficie della trackball e' data da una sfera + una porzione
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
Assumiamo la sfera di raggio unitario e centrata sull'origine e
di guardare lungo la y negativa.
X 0 sqrt(1/2) 1
eq sfera: y=sqrt(1-x*x); 1 sqrt(1/2) 0
X 0 sqrt(1/2) 1
eq sfera: y=sqrt(1-x*x); 1 sqrt(1/2) 0
eq iperboloide : y=1/2*x; inf sqrt(1/2) 1/2
eq cono y=x+sqrt(2);
</pre>
@ -235,12 +191,12 @@ eq cono y=x+sqrt(2);
Point3f HitSphere (Trackball * tb, const Point3f & p)
{
Point3f center = tb->center;
Line3fN ln = tb->camera.ViewLineFromWindow (Point3f (p[0], p[1], 0));
Line3fN ln = tb->camera.ViewLineFromWindow (Point3f (p[0], p[1], 0));
Plane3f vp = GetViewPlane (tb->camera, center);
Point3f hitPlane(0,0,0), //intersection view plane with point touched
hitSphere(0,0,0),
hitSphere1(0,0,0),
hitSphere2(0,0,0),
hitSphere(0,0,0),
hitSphere1(0,0,0),
hitSphere2(0,0,0),
hitHyper(0,0,0);
IntersectionPlaneLine < float >(vp, ln, hitPlane);
@ -297,7 +253,7 @@ Point3f HitSphere (Trackball * tb, const Point3f & p)
// if(d > d2) hit = hit2;
// hit -= tb->center;
//} else {
// if(d > 2.99 * Thr)
// if(d > 2.99 * Thr)
// d = 2.99 * Thr;
// Point3f norm = (hit - tb->center)^(viewpoint - tb->center);
// norm.Normalize();
@ -337,7 +293,7 @@ std::pair< float, bool > LineLineDistance(const Line3f & P,const Line3f & Q,Poin
const float det = ( VPVP * VQVQ ) - ( VPVQ * VPVQ );
const float EPSILON = 0.00001f;
if ( fabs(det) < EPSILON ) {
return std::make_pair(Distance(P,q0), true);
return std::make_pair(Distance(P,q0), true);
}
float b1= (q0 - p0).dot(Vp);
float b2= (p0 - q0).dot(Vq);
@ -351,7 +307,7 @@ std::pair< float, bool > LineLineDistance(const Line3f & P,const Line3f & Q,Poin
/*!
@brief Calculates the minimal distance between a ray and a line.
R is the ray and Q is the line, R_s and Q_t are set to be the closest points on
R is the ray and Q is the line, R_s and Q_t are set to be the closest points on
the ray and the line.
it's returned the distance from R_s and Q_t, and a boolean value which is true
@ -373,7 +329,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
const float det = ( VRVR * VQVQ ) - ( VRVQ * VRVQ );
const float EPSILON = 0.00001f;
if ( ( det >= 0.0f ? det : -det) < EPSILON ) {
return std::make_pair(Distance(Q,r0), true);
return std::make_pair(Distance(Q,r0), true);
}
float b1= (q0 - r0).dot(Vr);
float b2= (r0 - q0).dot(Vq);
@ -381,7 +337,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
float t = ( (VRVQ * b1) + (VRVR * b2) ) / det;
if(s<0){
R_s = r0;
Q_t = ClosestPoint(Q,R_s);
Q_t = ClosestPoint(Q,R_s);
}else {
R_s = r0 + (Vr * s);
Q_t = q0 + (Vq * t);
@ -392,7 +348,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
///*!
// @brief Calculates the minimal distance between 2 segments.
//
// R e Q are the segments, R_s and Q_t are set to be the closest points on
// R e Q are the segments, R_s and Q_t are set to be the closest points on
// the segments.
//
// it's returned the distance from R_s and Q_t, and a boolean value which is true
@ -407,7 +363,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
//{
// float R_len=Distance(R.P0(),R.P1());
// float Q_len=Distance(Q.P0(),Q.P1());
// const float EPSILON_LENGTH = std::max(R_len,Q_len)*0.0001f;
// const float EPSILON_LENGTH = std::max(R_len,Q_len)*0.0001f;
// if(R_len < EPSILON_LENGTH){
// R_s=R.P0();
// Q_t=ClosestPoint(Q,R_s);
@ -417,7 +373,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
// Q_t=Q.P0();
// R_s=ClosestPoint(R,Q_t);
// return std::make_pair(Distance(R_s,Q_t),true);
// }
// }
// Point3f r0 = R.P0(), Vr = (R.P1()-R.P0()).normalized();
// Point3f q0 = Q.P0(), Vq = (Q.P1()-Q.P0()).normalized();
// float VRVR = Vr.dot(Vr);
@ -450,7 +406,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
// assert(0);
// }
// }
// }
// }
// return std::make_pair(Distance(R_s,Q_t),true);
// }
// float b1= (q0 - r0).dot(Vr);
@ -465,7 +421,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
// R_s = r0 + (Vr * s);
// }
// if( t < 0){
// Q_t = Q.P0();
// Q_t = Q.P0();
// }else if ( t > Q_len ){
// Q_t = Q.P1();
// }else{
@ -477,7 +433,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
/*!
@brief Compute the point on a line closest to the ray projection of a window coordinate point.
Given a window coordinate point, computes a ray starting from the manipulator
Given a window coordinate point, computes a ray starting from the manipulator
camera eye and passing through the point's projection on the viewplane, then uses RayLineDistance()
to get the closest point to ray on a given line.
@see RayLineDistance(const Ray3f & R,const Line3f & Q,Point3f & R_s, Point3f & Q_t)
@ -489,10 +445,10 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
std::pair< Point3f,bool > HitNearestPointOnAxis (Trackball * tb,Line3f axis, Point3f point)
{
Ray3fN ray = line2ray(tb->camera.ViewLineFromWindow (point));
Point3f axis_p(0,0,0), ray_p(0,0,0);
Point3f axis_p(0,0,0), ray_p(0,0,0);
std::pair< float, bool > resp=RayLineDistance(ray,axis,ray_p,axis_p);
if(resp.second || (ray_p == ray.Origin())){
return std::make_pair(Point3f(0,0,0),false);
return std::make_pair(Point3f(0,0,0),false);
}
return std::make_pair(axis_p,true);
}
@ -570,7 +526,7 @@ template<class T>
/*!
@brief Project a window coordinate point on a plane.
Given a window coordinate point, computes a ray starting from the manipulator
Given a window coordinate point, computes a ray starting from the manipulator
camera eye and passing through the point's projection on the viewplane, then uses IntersectionRayPlane()
to get the ray intersection with a given plane.
@ -684,7 +640,7 @@ void DrawCircle (bool planehandle=true)
@param active boolean to be set to true if the icon is active.
*/
void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
{
{
glPushAttrib(GL_TRANSFORM_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix ();
@ -693,7 +649,7 @@ void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
Point3f center = tb->center + tb->track.InverseMatrix()*Point3f(0, 0, 0);
glTranslate(center);
glScale (tb->radius/tb->track.sca);
float amb[4] = { .35f, .35f, .35f, 1.0f };
float col[4] = { .5f, .5f, .8f, 1.0f };
glEnable (GL_LINE_SMOOTH);
@ -709,10 +665,10 @@ void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor (DH.color);
glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, amb);
col[0] = .40f; col[1] = .40f; col[2] = .85f;
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
DrawCircle(planeshandle);
DrawCircle(planeshandle);
glRotatef (90, 1, 0, 0);
col[0] = .40f; col[1] = .85f; col[2] = .40f;
@ -722,10 +678,10 @@ void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
glRotatef (90, 0, 1, 0);
col[0] = .85f; col[1] = .40f; col[2] = .40f;
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
DrawCircle(planeshandle);
glPopMatrix ();
glPopAttrib ();
DrawCircle(planeshandle);
glPopMatrix ();
glPopAttrib ();
}
// TEMPORARY drawing section
@ -762,7 +718,7 @@ void prepare_attrib()
void DrawUglyLetter(Trackball * tb,std::vector<Point3f> ugly_letter)
{
Point3f center=tb->camera.Project(tb->center);
float offset=0;
float offset=0;
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(1,0,0) * tb->radius))));
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(0,1,0) * tb->radius))));
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(0,0,1) * tb->radius))));
@ -775,12 +731,12 @@ void DrawUglyLetter(Trackball * tb,std::vector<Point3f> ugly_letter)
prepare_attrib();
glColor3f(1,1,1);
glLineWidth(4.0);
glBegin(GL_LINE_STRIP);
for(unsigned int i=0;i<ugly_letter.size();i++){
glVertex(tb->camera.UnProject(center+(ugly_letter[i] * offset * 0.25)
+Point3f(-offset,-offset,0)));
}
glVertex(tb->camera.UnProject(center+(ugly_letter[i] * offset * 0.25)
+Point3f(-offset,-offset,0)));
}
glEnd();
glPopAttrib ();
glPopMatrix();
@ -800,9 +756,9 @@ void DrawUglyPanMode(Trackball * tb)
ugly_p.push_back(Point3f(-1,-1,0));
ugly_p.push_back(Point3f(-1,1,0));
ugly_p.push_back(Point3f(1,1,0));
ugly_p.push_back(Point3f(1,0,0));
ugly_p.push_back(Point3f(-1,0,0));
ugly_p.push_back(Point3f(1,0,0));
ugly_p.push_back(Point3f(-1,0,0));
DrawUglyLetter(tb,ugly_p);
}
@ -915,7 +871,7 @@ void DrawUglyPlaneMode(Trackball * tb,Plane3f plane)
glVertex(p0+(d1*f0)+(d2*f1));
}
glEnd();
}
}
glColor3f(0.9f, 0.9f, 0.2f);
glPointSize(8.0f);
glBegin(GL_POINTS);
@ -968,7 +924,7 @@ void DrawUglyCylinderMode(Trackball * tb,Line3f axis)
glVertex(axis.Origin()+p0+(norm*float(i))+(d1*f0)+(d2*f1));
}
glEnd();
}
}
glLineWidth(3.0);
glColor3f(0.2f, 0.2f, 0.9f);
glBegin(GL_LINES);
@ -1126,15 +1082,15 @@ void DrawUglyAreaMode(Trackball * tb,const std::vector < Point3f > &points,
glVertex(p0+(d1*f0)+(d2*f1));
}
glEnd();
}
}
glPopAttrib ();
glPopMatrix();
}
} //end namespace trackutils
} //end namespace vcg
#endif //TRACKUTILS_H

View File

@ -108,6 +108,7 @@ Note: mainly it is used only by the TrackBall.
template <class T> class View {
public:
View();
void GetView();
void SetView(const float *_proj, const float *_modelview, const int *_viewport);
Point3<T> Project(const Point3<T> &p) const;
@ -134,15 +135,23 @@ public:
Matrix44<T> matrix;
Matrix44<T> inverse;
int viewport[4];
bool isOrtho;
};
template <class T> void View<T>::GetView() {
glGetv(GL_PROJECTION_MATRIX,proj);
glGetv(GL_MODELVIEW_MATRIX,model);
glGetIntegerv(GL_VIEWPORT, (GLint*)viewport);
template <class T> View<T>::View() {
isOrtho=false;
}
matrix = proj*model;
inverse = vcg::Inverse(matrix);
template <class T> void View<T>::GetView() {
glGetv(GL_PROJECTION_MATRIX,proj);
glGetv(GL_MODELVIEW_MATRIX,model);
glGetIntegerv(GL_VIEWPORT, (GLint*)viewport);
if(proj[3][3]==0) isOrtho = false;
else isOrtho = true;
matrix = proj*model;
inverse = vcg::Inverse(matrix);
}
template <class T> void View<T>::SetView(const float *_proj,
@ -161,6 +170,7 @@ template <class T> void View<T>::SetView(const float *_proj,
}
template <class T> Point3<T> View<T>::ViewPoint() const {
if(isOrtho) return vcg::Inverse(model)* Point3<T>(0, 0, 3);
return vcg::Inverse(model)* Point3<T>(0, 0, 0);
}
// Note that p it is assumed to be in model coordinate.
@ -179,22 +189,33 @@ template <class T> Plane3<T> View<T>::ViewPlaneFromModel(const Point3<T> &p)
// Note that p it is assumed to be in model coordinate.
template <class T> Line3<T> View<T>::ViewLineFromModel(const Point3<T> &p)
{
Point3<T> vp=ViewPoint();
Line3<T> line;
line.SetOrigin(vp);
line.SetDirection(p - vp);
Point3<T> vp=ViewPoint();
if(isOrtho){
line.SetOrigin(p);
line.SetDirection(- vp );
} else {
line.SetOrigin(vp);
line.SetDirection(p - vp);
}
return line;
}
// Note that p it is assumed to be in window coordinate.
template <class T> Line3<T> View<T>::ViewLineFromWindow(const Point3<T> &p)
{
Line3<T> ln; // plane perpedicular to view direction and passing through manip center
Point3<T> vp=ViewPoint();
Point3<T> pp=UnProject(p);
ln.SetOrigin(vp);
ln.SetDirection(pp-vp);
return ln;
Line3<T> line; // plane perpedicular to view direction and passing through manip center
Point3<T> vp=ViewPoint();
Point3<T> pp=UnProject(p);
if(isOrtho){
line.SetOrigin(pp);
line.SetDirection(- vp );
} else {
line.SetOrigin(vp);
line.SetDirection(pp-vp);
}
return line;
}
template <class T> Point3<T> View<T>::Project(const Point3<T> &p) const {