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

@ -42,7 +42,7 @@ void TrackMode::SetAction (){}
void TrackMode::Reset (){}
bool TrackMode::IsAnimating(const Trackball *){
return false;
return false;
}
void TrackMode::Animate(unsigned int, Trackball *){
@ -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;
}
@ -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);
}
}
@ -242,21 +246,21 @@ Point3f PathMode::SetStartNear(Point3f 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);
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;
@ -283,17 +287,17 @@ void PathMode::GetPoints(float state, Point3f & point, Point3f & prev_point, Poi
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,24 +307,24 @@ 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;
@ -412,14 +416,14 @@ float PathMode::HitPoint(float state, Ray3fN ray, Point3f &hit_point)
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);
}
@ -471,14 +475,14 @@ 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);
@ -498,11 +502,11 @@ void AreaMode::Init(const std::vector < Point3f > &pts)
}
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;
}
@ -528,7 +532,7 @@ void AreaMode::Apply (Trackball * tb, Point3f new_point)
}
std::pair< Point3f, bool > hitNew = HitPlane(tb,new_point+delta_mouse,plane);
if(! hitNew.second){
return;
return;
}
Point3f hit_point=hitNew.first;
Point3f delta_status=Move(status,hit_point);
@ -555,7 +559,7 @@ 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;
@ -568,25 +572,25 @@ Point3f AreaMode::Move(Point3f start,Point3f end)
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)
@ -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;
}
@ -647,9 +651,9 @@ Point3f AreaMode::SetStartNear(Point3f point)
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;
@ -721,17 +725,17 @@ void PolarMode::Draw(Trackball * tb){
NavigatorWasdMode::NavigatorWasdMode() {
_flipH=1; _flipV=1;
SetTopSpeedsAndAcc(1,1,4);
step_height = step_length = 0;
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(){
@ -748,51 +752,51 @@ 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);
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 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;
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) {
// 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.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;
}
@ -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
@ -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);
@ -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);
@ -492,7 +448,7 @@ std::pair< Point3f,bool > HitNearestPointOnAxis (Trackball * tb,Line3f axis, Poi
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);
}
@ -712,7 +668,7 @@ void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
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);
DrawCircle(planeshandle);
glPopMatrix ();
glPopAttrib ();
glPopMatrix ();
glPopAttrib ();
}
// TEMPORARY drawing section
@ -778,8 +734,8 @@ void DrawUglyLetter(Trackball * tb,std::vector<Point3f> ugly_letter)
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 ();

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 {