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

View File

@ -20,51 +20,7 @@
* for more details. * * 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 #ifndef TRACKUTILS_H
#define TRACKUTILS_H #define TRACKUTILS_H
@ -144,24 +100,24 @@ Point3f HitViewPlane (Trackball * tb, const Point3f & p)
<br>The original documentation (in italian) follows: <br>The original documentation (in italian) follows:
<pre> <pre>
dato un punto in coordinate di schermo e.g. in pixel stile opengl dato un punto in coordinate di schermo e.g. in pixel stile opengl
calcola il punto di intersezione tra la viewline che passa per calcola il punto di intersezione tra la viewline che passa per
viewpoint e per hitplane e l'iperboloide. 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 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 su center ecome x la retta center-viewpoint
eq linea eq linea
hitplane.y hitplane.y
y = - ----------- * x + hitplane.y y = - ----------- * x + hitplane.y
viewpoint.x 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 1
y = --- * (r^2 /2.0) y = --- * (r^2 /2.0)
x x
hitplane.y hitplane.y
----------- * x^2 - hitplane.y *x + (r^2/2.0) == 0 ----------- * 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: <br>The original documentation (in italian) follows:
<pre> <pre>
dato un punto in coordinate di schermo e.g. in pixel stile opengl dato un punto in coordinate di schermo e.g. in pixel stile opengl
restituisce un punto in coordinate di mondo sulla superficie restituisce un punto in coordinate di mondo sulla superficie
della trackball. 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. 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. di guardare lungo la y negativa.
X 0 sqrt(1/2) 1 X 0 sqrt(1/2) 1
eq sfera: y=sqrt(1-x*x); 1 sqrt(1/2) 0 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 iperboloide : y=1/2*x; inf sqrt(1/2) 1/2
eq cono y=x+sqrt(2); eq cono y=x+sqrt(2);
</pre> </pre>
@ -235,12 +191,12 @@ eq cono y=x+sqrt(2);
Point3f HitSphere (Trackball * tb, const Point3f & p) Point3f HitSphere (Trackball * tb, const Point3f & p)
{ {
Point3f center = tb->center; 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); Plane3f vp = GetViewPlane (tb->camera, center);
Point3f hitPlane(0,0,0), //intersection view plane with point touched Point3f hitPlane(0,0,0), //intersection view plane with point touched
hitSphere(0,0,0), hitSphere(0,0,0),
hitSphere1(0,0,0), hitSphere1(0,0,0),
hitSphere2(0,0,0), hitSphere2(0,0,0),
hitHyper(0,0,0); hitHyper(0,0,0);
IntersectionPlaneLine < float >(vp, ln, hitPlane); IntersectionPlaneLine < float >(vp, ln, hitPlane);
@ -297,7 +253,7 @@ Point3f HitSphere (Trackball * tb, const Point3f & p)
// if(d > d2) hit = hit2; // if(d > d2) hit = hit2;
// hit -= tb->center; // hit -= tb->center;
//} else { //} else {
// if(d > 2.99 * Thr) // if(d > 2.99 * Thr)
// d = 2.99 * Thr; // d = 2.99 * Thr;
// Point3f norm = (hit - tb->center)^(viewpoint - tb->center); // Point3f norm = (hit - tb->center)^(viewpoint - tb->center);
// norm.Normalize(); // 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 det = ( VPVP * VQVQ ) - ( VPVQ * VPVQ );
const float EPSILON = 0.00001f; const float EPSILON = 0.00001f;
if ( fabs(det) < EPSILON ) { 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 b1= (q0 - p0).dot(Vp);
float b2= (p0 - q0).dot(Vq); 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. @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. the ray and the line.
it's returned the distance from R_s and Q_t, and a boolean value which is true 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 det = ( VRVR * VQVQ ) - ( VRVQ * VRVQ );
const float EPSILON = 0.00001f; const float EPSILON = 0.00001f;
if ( ( det >= 0.0f ? det : -det) < EPSILON ) { 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 b1= (q0 - r0).dot(Vr);
float b2= (r0 - q0).dot(Vq); 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; float t = ( (VRVQ * b1) + (VRVR * b2) ) / det;
if(s<0){ if(s<0){
R_s = r0; R_s = r0;
Q_t = ClosestPoint(Q,R_s); Q_t = ClosestPoint(Q,R_s);
}else { }else {
R_s = r0 + (Vr * s); R_s = r0 + (Vr * s);
Q_t = q0 + (Vq * t); 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. // @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. // the segments.
// //
// it's returned the distance from R_s and Q_t, and a boolean value which is true // 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 R_len=Distance(R.P0(),R.P1());
// float Q_len=Distance(Q.P0(),Q.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){ // if(R_len < EPSILON_LENGTH){
// R_s=R.P0(); // R_s=R.P0();
// Q_t=ClosestPoint(Q,R_s); // 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(); // Q_t=Q.P0();
// R_s=ClosestPoint(R,Q_t); // R_s=ClosestPoint(R,Q_t);
// return std::make_pair(Distance(R_s,Q_t),true); // return std::make_pair(Distance(R_s,Q_t),true);
// } // }
// Point3f r0 = R.P0(), Vr = (R.P1()-R.P0()).normalized(); // Point3f r0 = R.P0(), Vr = (R.P1()-R.P0()).normalized();
// Point3f q0 = Q.P0(), Vq = (Q.P1()-Q.P0()).normalized(); // Point3f q0 = Q.P0(), Vq = (Q.P1()-Q.P0()).normalized();
// float VRVR = Vr.dot(Vr); // float VRVR = Vr.dot(Vr);
@ -450,7 +406,7 @@ std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3
// assert(0); // assert(0);
// } // }
// } // }
// } // }
// return std::make_pair(Distance(R_s,Q_t),true); // return std::make_pair(Distance(R_s,Q_t),true);
// } // }
// float b1= (q0 - r0).dot(Vr); // 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); // R_s = r0 + (Vr * s);
// } // }
// if( t < 0){ // if( t < 0){
// Q_t = Q.P0(); // Q_t = Q.P0();
// }else if ( t > Q_len ){ // }else if ( t > Q_len ){
// Q_t = Q.P1(); // Q_t = Q.P1();
// }else{ // }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. @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() 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. 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) @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) std::pair< Point3f,bool > HitNearestPointOnAxis (Trackball * tb,Line3f axis, Point3f point)
{ {
Ray3fN ray = line2ray(tb->camera.ViewLineFromWindow (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); std::pair< float, bool > resp=RayLineDistance(ray,axis,ray_p,axis_p);
if(resp.second || (ray_p == ray.Origin())){ 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); return std::make_pair(axis_p,true);
} }
@ -570,7 +526,7 @@ template<class T>
/*! /*!
@brief Project a window coordinate point on a plane. @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() camera eye and passing through the point's projection on the viewplane, then uses IntersectionRayPlane()
to get the ray intersection with a given plane. 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. @param active boolean to be set to true if the icon is active.
*/ */
void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false) 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); glPushAttrib(GL_TRANSFORM_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix (); 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); Point3f center = tb->center + tb->track.InverseMatrix()*Point3f(0, 0, 0);
glTranslate(center); glTranslate(center);
glScale (tb->radius/tb->track.sca); glScale (tb->radius/tb->track.sca);
float amb[4] = { .35f, .35f, .35f, 1.0f }; float amb[4] = { .35f, .35f, .35f, 1.0f };
float col[4] = { .5f, .5f, .8f, 1.0f }; float col[4] = { .5f, .5f, .8f, 1.0f };
glEnable (GL_LINE_SMOOTH); 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); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor (DH.color); glColor (DH.color);
glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, amb); glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, amb);
col[0] = .40f; col[1] = .40f; col[2] = .85f; col[0] = .40f; col[1] = .40f; col[2] = .85f;
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col); glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
DrawCircle(planeshandle); DrawCircle(planeshandle);
glRotatef (90, 1, 0, 0); glRotatef (90, 1, 0, 0);
col[0] = .40f; col[1] = .85f; col[2] = .40f; 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); glRotatef (90, 0, 1, 0);
col[0] = .85f; col[1] = .40f; col[2] = .40f; col[0] = .85f; col[1] = .40f; col[2] = .40f;
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col); glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
DrawCircle(planeshandle); DrawCircle(planeshandle);
glPopMatrix (); glPopMatrix ();
glPopAttrib (); glPopAttrib ();
} }
// TEMPORARY drawing section // TEMPORARY drawing section
@ -762,7 +718,7 @@ void prepare_attrib()
void DrawUglyLetter(Trackball * tb,std::vector<Point3f> ugly_letter) void DrawUglyLetter(Trackball * tb,std::vector<Point3f> ugly_letter)
{ {
Point3f center=tb->camera.Project(tb->center); 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(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,1,0) * tb->radius))));
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(0,0,1) * 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(); prepare_attrib();
glColor3f(1,1,1); glColor3f(1,1,1);
glLineWidth(4.0); glLineWidth(4.0);
glBegin(GL_LINE_STRIP); glBegin(GL_LINE_STRIP);
for(unsigned int i=0;i<ugly_letter.size();i++){ for(unsigned int i=0;i<ugly_letter.size();i++){
glVertex(tb->camera.UnProject(center+(ugly_letter[i] * offset * 0.25) glVertex(tb->camera.UnProject(center+(ugly_letter[i] * offset * 0.25)
+Point3f(-offset,-offset,0))); +Point3f(-offset,-offset,0)));
} }
glEnd(); glEnd();
glPopAttrib (); glPopAttrib ();
glPopMatrix(); 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,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); DrawUglyLetter(tb,ugly_p);
} }
@ -915,7 +871,7 @@ void DrawUglyPlaneMode(Trackball * tb,Plane3f plane)
glVertex(p0+(d1*f0)+(d2*f1)); glVertex(p0+(d1*f0)+(d2*f1));
} }
glEnd(); glEnd();
} }
glColor3f(0.9f, 0.9f, 0.2f); glColor3f(0.9f, 0.9f, 0.2f);
glPointSize(8.0f); glPointSize(8.0f);
glBegin(GL_POINTS); glBegin(GL_POINTS);
@ -968,7 +924,7 @@ void DrawUglyCylinderMode(Trackball * tb,Line3f axis)
glVertex(axis.Origin()+p0+(norm*float(i))+(d1*f0)+(d2*f1)); glVertex(axis.Origin()+p0+(norm*float(i))+(d1*f0)+(d2*f1));
} }
glEnd(); glEnd();
} }
glLineWidth(3.0); glLineWidth(3.0);
glColor3f(0.2f, 0.2f, 0.9f); glColor3f(0.2f, 0.2f, 0.9f);
glBegin(GL_LINES); glBegin(GL_LINES);
@ -1126,15 +1082,15 @@ void DrawUglyAreaMode(Trackball * tb,const std::vector < Point3f > &points,
glVertex(p0+(d1*f0)+(d2*f1)); glVertex(p0+(d1*f0)+(d2*f1));
} }
glEnd(); glEnd();
} }
glPopAttrib (); glPopAttrib ();
glPopMatrix(); glPopMatrix();
} }
} //end namespace trackutils } //end namespace trackutils
} //end namespace vcg } //end namespace vcg
#endif //TRACKUTILS_H #endif //TRACKUTILS_H

View File

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