diff --git a/wrap/gui/trackmode.cpp b/wrap/gui/trackmode.cpp index 944d45b6..8719532f 100644 --- a/wrap/gui/trackmode.cpp +++ b/wrap/gui/trackmode.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.19 2006/08/30 07:01:54 cignoni +Reverted to version 1.17. Version 1.18 was wrongly done starting from a outdated version. + Revision 1.17 2006/07/26 13:54:45 cignoni Reversed the direction of wheel scaling and added middle mouse panning @@ -79,242 +82,617 @@ Adding copyright. #include #include -#include -#include -#include - +#include + using namespace std; using namespace vcg; +using namespace vcg::trackutils; - -void TrackMode::Apply(Trackball *trackball, float WheelNotch) { - trackball->track.sca*=pow(1.2f,-WheelNotch); - } - -void ScaleMode::Apply(Trackball *tb, Point3f new_point) { - float ScreenHeight= float(tb->camera.viewport[3]-tb->camera.viewport[1]); - float dist=(new_point[1]-tb->last_point[1])/ScreenHeight; - tb->track.sca= tb->last_track.sca*pow(3.0f,-dist); -} - -/// Compute the plane plane perpedicular to view dir and passing through manip center -Plane3f TrackMode::GetViewPlane(const View &camera, const Point3f ¢er) { - Point3f vp = camera.ViewPoint(); - - Plane3f pl; - Point3f plnorm= vp - center; - plnorm.Normalize(); - pl.Set(plnorm, plnorm*center); - return pl; -} - -/// Given a point p in window coordinate it compute the point where the lie p -/// over the plane paralell the viewplane and passing through the center of the trackball - -Point3f TrackMode::HitViewPlane(Trackball *tb, const Point3f &p) { - // plane perpedicular to view direction and passing through manip center - Plane3f vp = GetViewPlane(tb->camera, tb->center); - - Line3fN ln= tb->camera.ViewLineFromWindow(Point3f(p[0],p[1],0)); - - Point3f PonVP; - /*bool res = */IntersectionLinePlane(vp,ln,PonVP); - return PonVP; -} - -// the most important function; given a new point in window coord, it update the transformation computed by the trackball. -// General scheme : the transformation is a function of just the begin and current mouse positions, with greater precision is function of just two 3d points over the manipulator. -void SphereMode::Apply(Trackball *tb, Point3f new_point) { - Point3f hitOld=Hit(tb, tb->last_point); - Point3f hitNew=Hit(tb, new_point); - tb->Hits.push_back(hitNew); - - // Point3f center = tb->track.tra+tb->center; // original 2006 01 12 - Point3f center = tb->center; - Point3f axis = (hitNew - center)^(hitOld- center); - - // Figure out how much to rotate around that axis. - //float phi=Angle((hitNew- tb->center),(hitOld- tb->center)); - float phi = Distance(hitNew,hitOld) / tb->radius; - - tb->track.rot = tb->last_track.rot * Quaternionf(phi,axis); - /* Codice Originale Ponchio - - Point3f ref = (tb->camera.ViewPoint() - tb->center).Normalize(); - Point3f axis = hitNew^ref; - axis.Normalize(); - float dist = (hitNew - ref).Norm()/2; - float phi = 2 * math::Asin(dist); - - Point3f oaxis = hitOld^ref; - oaxis.Normalize(); - float odist = (hitOld - ref).Norm()/2; - float ophi = 2 * math::Asin(odist); - - - Quaternionf r = tb->last_track.rot; - Quaternionf diff = r * Quaternionf(phi, axis) * - Quaternionf(-ophi, oaxis) * Inverse(r); - - tb->track = Similarityf().SetRotate(diff) * tb->last_track;*/ - -} - +// the old implementation is not used anymore, some of the old support functions, +// like HitViewPlane, GetViewPlane, HitHyper and SphereMode::Hit were made +// class-independent and moved to trackutils.h /* -dato un punto in coordinate di schermo e.g. in pixel stile opengl -calcola il punto di intersezione tra la viewline che passa per viewpoint e per hitplane e l'iperboloide. -l'iperboloide si assume essere quello di rotazione attorno alla retta viewpoint-center e di raggio rad -si assume come sistema di riferimento quello con l'origine su center ecome x la retta center-viewpoint - -eq linea - hitplane.y -y = - ----------- * x + hitplane.y - viewpoint.x - -eq hiperboloide di raggio r (e.g. che passa per (r/sqrt2,r/sqrt2) - - 1 -y = --- * (r^2 /2.0) - x - - hitplane.y - ----------- * x^2 - hitplane.y *x + (r^2/2.0) == 0 - viewpoint.x - -*/ +void TrackMode::Apply(Trackball *trackball, float WheelNotch) { +} +void ScaleMode::Apply(Trackball *tb, Point3f new_point) { +} +Plane3f TrackMode::GetViewPlane(const View &camera, const Point3f ¢er) { +} +Point3f TrackMode::HitViewPlane(Trackball *tb, const Point3f &p) { +} +void SphereMode::Apply(Trackball *tb, Point3f new_point) { +} bool SphereMode::HitHyper(Point3f center, float radius, Point3f viewpoint, Plane3f vp, Point3f hitplane, Point3f &hit) { - float hitplaney = Distance(center,hitplane); - float viewpointx= Distance(center,viewpoint); - - float a = hitplaney/viewpointx; - float b = -hitplaney; - float c = radius*radius/2.0f; - float delta = b*b - 4*a*c; - float x1,x2,xval,yval; - if(delta>0) - { - x1= (- b - sqrt(delta))/(2.0f*a); - x2= (- b + sqrt(delta))/(2.0f*a); - - xval=x1; // always take the minimum value solution - yval=c/xval; // alternatively it also oould be the other part of the equation yval=-(hitplaney/viewpointx)*xval+hitplaney; - } - else - { - return false; - } - // Computing the result in 3d space; - Point3f dirRadial=hitplane-center; - dirRadial.Normalize(); - Point3f dirView=vp.Direction(); - dirView.Normalize(); - hit= center +dirRadial*yval+dirView*xval; - return true; } - - - -/* 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 - di iperboloide di rotazione. - 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 - eq iperboloide : y=1/2*x; inf sqrt(1/2) 1/2 - eq cono y=x+sqrt(2); - - */ - Point3f SphereMode::Hit(Trackball *tb, const Point3f &p) { - // const float Thr = tb->radius/math::Sqrt(2.0f); - - Line3fN vn = tb->camera.ViewLineFromModel(tb->center); - Line3fN ln = tb->camera.ViewLineFromWindow(Point3f(p[0],p[1],0)); - Point3f viewpoint = tb->camera.ViewPoint(); - Plane3f vp = GetViewPlane(tb->camera, tb->center); - Point3f hit,hitPlane,hitSphere,hitSphere1,hitSphere2,hitHyper; - IntersectionLinePlane(vp, ln, hitPlane); - Sphere3f sphere(tb->center,tb->radius); - bool resSp = IntersectionLineSphere(sphere, ln, hitSphere1, hitSphere2); - if(resSp == true) - { - if(Distance(viewpoint,hitSphere1)center); - bool resHp = HitHyper(tb->center, tb->radius, viewpoint, vp, hitPlane, hitHyper) ; - - // four cases - - // 1) Degenerate line tangent to both sphere and hyperboloid! - if((!resSp && !resHp) ) - { - hit=ClosestPoint(ln,tb->center); - //printf("closest point to line %f\n",Distance(hit,tb->center)); - return hit; - } - if((resSp && !resHp) ) return hitSphere; // 2) line cross only the sphere - if((!resSp && resHp) ) return hitHyper; // 3) line cross only the hyperboloid - - // 4) line cross both sphere and hyperboloid: choose according angle. - float angleDeg=math::ToDeg(Angle((viewpoint-tb->center),(hitSphere-tb->center))); - //printf("Angle %f (%5.2f %5.2f %5.2f) (%5.2f %5.2f %5.2f)\n",angleDeg,hitSphere[0],hitSphere[1],hitSphere[2],hitHyper[0],hitHyper[1],hitHyper[2]); - if(angleDeg<45) return hitSphere; - else return hitHyper; - - // - // Codice ORIGINALE PONCHIO - //vp.SetOffset(vp.Offset() + Thr); - - //Point3f hit; - //bool res = Intersection(vp, ln, hit); - //float d = Distance(tb->center - vn.Direction()*Thr, hit); - //if(d < Thr) { - // Point3f hit2; - // Sphere3f sphere(tb->center, tb->radius); - // bool res = Intersection(sphere, ln, hit, hit2); - - // //find closest intersection to sphere - // float d = (hit - viewpoint).Norm(); - // float d2 = (hit2 - viewpoint).Norm(); - // if(d > d2) hit = hit2; - // hit -= tb->center; - //} else { - // if(d > 2.99 * Thr) - // d = 2.99 * Thr; - // Point3f norm = (hit - tb->center)^(viewpoint - tb->center); - // norm.Normalize(); - // float phi = -M_PI/4 - 3*M_PI/8 *(d - Thr)/Thr; - - // Quaternionf q(phi, norm); - // hit = q.Rotate((viewpoint - tb->center).Normalize() * tb->radius); - //} - // hit.Normalize(); - // return hit; } - void PlaneMode::Apply(Trackball *tb, Point3f new_point) { - Point3f hitOld = HitViewPlane(tb, tb->last_point); - Point3f hitNew = HitViewPlane(tb, new_point); - //Matrix44f m; tb->track.rot.ToMatrix(m); - //tb->track.tra = tb->last_track.tra + Inverse(m)*Point3f(hitNew- hitOld);// orig 2006 01 12 - //tb->track.tra = tb->last_track.tra + Inverse(m)*Point3f(hitNew- hitOld)/tb->track.sca;; - tb->Translate(hitNew- hitOld); -} +} void ZMode::Apply(Trackball *tb, Point3f new_point) { - float ScreenHeight= float(tb->camera.viewport[3]-tb->camera.viewport[1]); - float dist=(new_point[1]-tb->last_point[1])/ScreenHeight; - //Matrix44f m; tb->track.rot.ToMatrix(m); - //tb->track.tra = tb->last_track.tra + Inverse(m)*Point3f(0,0,-2*dist)/tb->track.sca;; - tb->Translate(Point3f(0,0,-2*dist)); +} +*/ + +// Track mode implementation, dummy. +void TrackMode::Apply (Trackball * , float ){} + +void TrackMode::Apply (Trackball * , Point3f ){} + +void TrackMode::Draw(Trackball * ){} + +void TrackMode::SetAction (){} + +void TrackMode::Reset (){} + +// draw an inactive trackball +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 +// is function of just two 3d points over the manipulator. +void SphereMode::Apply (Trackball * tb, Point3f new_point) +{ + Point3f hitOld = HitSphere (tb, tb->last_point); + Point3f hitNew = HitSphere (tb, new_point); + tb->Hits.push_back (hitNew); + Point3f center = tb->center; + Point3f axis = (hitNew - center) ^ (hitOld - center); + // 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); } +void SphereMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); +} + +// Pan mode implementation. +void PanMode::Apply (Trackball * tb, Point3f new_point) +{ + Point3f hitOld = HitViewPlane (tb, tb->last_point); + Point3f hitNew = HitViewPlane (tb, new_point); + tb->Translate (hitNew - hitOld); +} + +void PanMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + DrawUglyPanMode(tb); +} + +// Z mode implementation. +void ZMode::Apply (Trackball * tb, float WheelNotch) +{ + Point3f dir= (GetViewPlane (tb->camera, tb->center)).Direction(); + dir.Normalize(); + tb->Translate (dir * (-WheelNotch)); +} + +void ZMode::Apply (Trackball * tb, Point3f new_point) +{ + Point3f dir= (GetViewPlane (tb->camera, tb->center)).Direction(); + dir.Normalize(); + tb->Translate (dir * ( -2.0f * getDeltaY(tb,new_point))); +} + +void ZMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + DrawUglyZMode(tb); + } + +// Scale mode implementation. +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))); +} + +void ScaleMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + DrawUglyScaleMode(tb); +} + +// Axis mode implementation. +void AxisMode::Apply (Trackball * tb, float WheelNotch) +{ + tb->Translate (axis.Direction () * (WheelNotch / 10.0f)); +} + +void AxisMode::Apply (Trackball * tb, Point3f new_point) +{ + pair< Point3f,bool > hitOld = HitNearestPointOnAxis (tb, axis, tb->last_point); + pair< Point3f,bool > hitNew = HitNearestPointOnAxis (tb, axis, new_point); + if (hitOld.second && hitNew.second){ + tb->Translate (hitNew.first - hitOld.first); + } +} + +void AxisMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + DrawUglyAxisMode(tb,axis); +} + +// Plane mode implementation. +void PlaneMode::Apply (Trackball * tb, Point3f new_point) +{ + pair< Point3f, bool > hitOld = HitPlane(tb,tb->last_point,plane); + pair< Point3f, bool > hitNew = HitPlane(tb,new_point,plane); + if(hitOld.second && hitNew.second){ + tb->Translate (hitNew.first - hitOld.first); + } +} + +void PlaneMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + DrawUglyPlaneMode(tb, plane); +} + +// Cylinder mode implementation. +void CylinderMode::Apply (Trackball * tb, float WheelNotch) +{ + const float PI2=6.283185307179586232; + tb->track.rot = tb->last_track.rot * Quaternionf (WheelNotch/(tb->radius * PI2),axis.Direction()); +} + +void CylinderMode::Apply (Trackball * tb, Point3f new_point) +{ + Plane3f viewplane=GetViewPlane (tb->camera, tb->center); + Line3f axisproj; + axisproj=ProjectLineOnPlane(axis,viewplane); + float angle; + const float EPSILON=0.005f; // this IS scale independent + if(axisproj.Direction().Norm() < EPSILON){ + angle=(10.0 * 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(); + float distOld = signedDistance(axisproj,hitOld,plusdir); + float distNew = signedDistance(axisproj,hitNew,plusdir); + angle= (distNew-distOld) / tb->radius; + } + tb->track.rot = tb->last_track.rot * Quaternionf (angle,axis.Direction()); +} + +void CylinderMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + DrawUglyCylinderMode(tb,axis); +} + +// Path mode implementation. +void PathMode::Init(const vector < Point3f > &pts) +{ + unsigned int npts=pts.size(); + assert(npts >= 2); + points.reserve(npts); + for(unsigned int i=0;i= 0.0 ); + if(nearest_state > 1.0){ + nearest_state=1.0; + nearest_point=( wrap ? points[0] : points[npts-1] ); + } + initial_state=nearest_state; + return nearest_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; + Point3f p0,p1; + unsigned int npts=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]; + } + float segment_norm= Distance(p0,p1) / path_length; + if (segment_norm < remaining_norm){ + remaining_norm -= segment_norm; + continue; + } + prev_point = p0; + 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; + if(Distance(point,prev_point) < EPSILON){ + point=prev_point; + if (i > 1){ + 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]; + } else { + 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; + if (wrap){ + next_point=points[1]; + }else{ + next_point = points[npts-1]; + } +} + +void PathMode::Apply (Trackball * tb, float WheelNotch) +{ + const float STEP_COEFF = min_seg_length * 0.5f; + float delta=(WheelNotch*STEP_COEFF)/path_length; + Point3f old_point,new_point,prev_point,next_point; + 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); +} + +float PathMode::Normalize(float state) +{ + if ( wrap ) { + double intpart; + float fractpart; + fractpart =(float) modf(state,&intpart); + if( fractpart < 0.0f ) + fractpart += 1.0f; + return fractpart; + } + if ( state < 0.0f ) + return 0.0f; + if ( state > 1.0f ) + return 1.0f; + return state; +} + +int PathMode::Verse(Point3f reference_point,Point3f current_point,Point3f prev_point,Point3f next_point) +{ + Point3f reference_dir = reference_point - current_point ; + Point3f prev_dir = prev_point - current_point ; + Point3f next_dir = next_point - current_point ; + const float EPSILON=min_seg_length * 0.005f; + if (reference_dir.Norm() < EPSILON) + reference_dir = Point3f(0,0,0); + if (prev_dir.Norm() < EPSILON) + prev_dir = Point3f(0,0,0); + if (next_dir.Norm() < EPSILON) + next_dir = Point3f(0,0,0); + reference_dir.Normalize(); + prev_dir.Normalize(); + next_dir.Normalize(); + float prev_coeff,next_coeff; + prev_coeff = prev_dir * reference_dir; + next_coeff = next_dir * reference_dir; + if (prev_coeff < 0.0f) + prev_coeff = 0.0f; + if (next_coeff < 0.0f) + next_coeff = 0.0f; + if( (prev_coeff == 0.0f) && (next_coeff == 0.0f)){ + return 0; + } + if ( prev_coeff <= next_coeff ){ + return 1; + } + return -1; +} + +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); + if (verse == 0){ + hit_point=current_point; + return 0.0f; + } + + Segment3f active_segment; + if (verse > 0){ + active_segment=Segment3f(current_point,next_point); + } else { + active_segment= Segment3f(current_point,prev_point); + } + + hit_point=ClosestPoint(active_segment,closest_point); + + return verse * ((hit_point-current_point).Norm() / path_length); +} + +void PathMode::SetAction (){ + Point3f temp1,temp2; + GetPoints(current_state,old_hitpoint,temp1,temp2); +} + +void PathMode::Apply (Trackball * tb, Point3f new_point) +{ + Ray3fN ray = line2ray(tb->camera.ViewLineFromWindow (new_point)); + Point3f hit_point; + float delta_state=HitPoint(current_state,ray,hit_point); + current_state=Normalize(current_state+delta_state); + tb->Translate (hit_point - old_hitpoint); +} + +void PathMode::Draw(Trackball * tb){ + DrawSphereIcon(tb,true ); + Point3f current_point,prev_point,next_point; + GetPoints(current_state,current_point,prev_point,next_point); + DrawUglyPathMode(tb,points,current_point,prev_point, + next_point,old_hitpoint,wrap); +} + +// Area mode implementation. +void AreaMode::Init(const vector < Point3f > &pts) +{ + unsigned int npts=pts.size(); + + assert(npts >= 3); + //get the plane + Point3f p0=pts[0]; + unsigned int onethird=(unsigned int)floor(npts/3.0); + const float EPSILON=0.005; + bool pts_not_in_line=false; + Point3f a,b; + for(unsigned int i=0;i EPSILON; + if(pts_not_in_line){ + plane.Init( pts[i%npts], + pts[(i+(onethird))%npts], + pts[(i+(2*onethird))%npts]); + break; + } + } + assert(pts_not_in_line); + float ncx,ncy,ncz; + ncx=fabs(plane.Direction()[0]); + ncy=fabs(plane.Direction()[1]); + 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 { + first_coord_kept=0; + second_coord_kept=1; + } + points.reserve(npts); + for(unsigned int i=0;icamera.Project(status)-new_point; + begin_action=false; + } + pair< Point3f, bool > hitNew = HitPlane(tb,new_point+delta_mouse,plane); + if(! hitNew.second){ + return; + } + Point3f hit_point=hitNew.first; + Point3f delta_status=Move(status,hit_point); + status += delta_status; + tb->Translate (status - old_status); + rubberband_handle=hit_point; +} + + +void AreaMode::SetAction () +{ + begin_action=true; + old_status=status; + + + path.clear(); + path.push_back(status); + rubberband_handle=status; +} + +Point3f AreaMode::Move(Point3f start,Point3f end) +{ + const float EPSILON=min_side_length*0.001f; + Point3f pt=start; + bool done=false; + bool end_inside=Inside(end); + while(!done){ + path.push_back(pt); + Segment3f segment(pt,end); + bool p_on_side = false; + bool hit=false; + + Point3f pside,phit; + bool slide,mid_inside; + + int np=points.size(), i, j; + for (i = 0, j = np-1; i < np; j = i++) { + Segment3f side(points[i],points[j]); + Point3f pseg,psid; + pair res=SegmentSegmentDistance(segment,side,pseg,psid); + if(res.first < EPSILON && ! res.second){ + float dist= Distance(pt,pseg); + if(dist < EPSILON){ + Point3f pn=ClosestPoint(side,end); + if(!p_on_side || (Distance(pn,end) EPSILON; + + if (hit) + mid_inside = Inside( pt + ( ( phit - pt ) / 2) ); + + if ( !hit && end_inside ){ + pt = end; + done = true; + } else if ( hit && (!p_on_side || (p_on_side && mid_inside))) { + pt = phit; + } else if ( p_on_side && slide) { + pt = pside; + } else { + done = true; + } + } + 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) +{ + bool inside=false; + float x=point[first_coord_kept]; + float y=point[second_coord_kept]; + float yi, yj, xi, xj; + int i, j, np=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]; + if ( ( ( (yi<=y) && (y #include +#include +#include #include +using namespace std; + namespace vcg { class Trackball; +// Base class for all the track modes. +// This class' functions does nothing. class TrackMode { public: - virtual ~TrackMode() {} - virtual void Apply(Trackball *trackball, Point3f new_point) = 0; - virtual void Apply(Trackball *trackball, float WheelNotch); - virtual const char *Name()=0; - virtual void Draw() {} - protected: - Plane3f GetViewPlane(const View &view, const Point3f ¢er); - Point3f HitViewPlane(Trackball *trackball, const Point3f &p); + virtual ~TrackMode () { + } + virtual void Apply (Trackball * trackball, Point3f new_point); + virtual void Apply (Trackball * trackball, float WheelNotch); + virtual void SetAction (); + virtual void Reset (); + virtual const char *Name (){ + return "TrackMode"; + }; + virtual void Draw (Trackball * trackball); +}; + +// Inactive mode. +// useful only for drawing the inactive trackball +class InactiveMode:public TrackMode { +public: + const char *Name () { + return "InactiveMode"; + }; + void Draw (Trackball * trackball); }; - + /* View space modes */ +// old interfaces +/* class SphereMode: public TrackMode { - public: - void Apply(Trackball *trackball, Point3f new_point); - const char* Name() {return "SphereMode";}; - protected: - Point3f Hit(Trackball *trackball, const Point3f &p); - bool HitHyper(Point3f center, float radius, Point3f viewpoint, Plane3f vp, Point3f hitplane, Point3f &hit) ; -}; - +} class CylinderMode: public TrackMode { +} +class PlaneMode: public TrackMode { +} +class ZMode: public TrackMode { +} +class LineMode: public TrackMode { +} +class LineMode: public TrackMode { +} +class ScaleMode: public TrackMode { + +*/ + +// Sphere mode. +// The classic trackball. +class SphereMode:public TrackMode { public: - CylinderMode(const Line3f &/*line*/, float /*radius = 1*/) {} - void Apply(Trackball * /*trackball*/, Point3f /*new_point*/) {} - const char* Name() {return "CylinderMode";}; -protected: - Line3f line; - float radius; + void Apply (Trackball * trackball, Point3f new_point); + const char *Name () { + return "SphereMode"; + }; + void Draw (Trackball * trackball); }; -class PlaneMode: public TrackMode { +// Panning mode. +// The user can drag the model on the view plane. +class PanMode:public TrackMode { public: - PlaneMode(const Plane3f &pl): plane(pl) {} - void Apply(Trackball *trackball, Point3f new_point); - const char* Name() {return "PlaneMode";}; -protected: + void Apply (Trackball * trackball, Point3f new_point); + const char *Name () { + return "PanMode"; + }; + void Draw (Trackball * trackball); +}; + +// Z mode. +// Dragging the mouse up and down or scrolling the +// mouse wheel will move the object along the Z of the camera. +class ZMode:public TrackMode { +public: + const char *Name () { + return "ZMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Apply (Trackball * trackball, float WheelNotch); + void Draw (Trackball * trackball); +}; + +// Scale Mode. +// Dragging the mouse up and down or scrolling the +// mouse wheel will scale the object. +class ScaleMode:public TrackMode { +public: + const char *Name () { + return "ScaleMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Apply (Trackball * trackball, float WheelNotch); + void Draw (Trackball * trackball); +}; + +// Axis mode. +// Moves the object in a costrained direction. +// The user can either drag the mouse or scroll the wheel. +// The direction can be specified either with a line +// or a origin and a direction. +// the object posistion is not needed to be on the line. +class AxisMode:public TrackMode { +public: + AxisMode (const Line3f & ln) + : axis (ln) { + } + AxisMode (const Point3f & origin, const Point3f & direction) { + axis = Line3fN (origin, direction); + } + const char *Name () { + return "AxisMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Apply (Trackball * trackball, float WheelNotch); + void Draw (Trackball * trackball); +private: + Line3fN axis; +}; + +// Plane mode. +// The user can drag the object in a costrained plane. +// The plane can be specified either with a plane +// or the plane's equation parameters +// the object posistion is not needed to be on the plane. +class PlaneMode:public TrackMode { +public: + PlaneMode (float a, float b, float c, float d) + : plane(Plane3f(d,Point3f(a,b,c))){ + } + PlaneMode (Plane3f & pl) + : plane(pl) { + } + const char *Name () { + return "PlaneMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Draw (Trackball * trackball); +private: Plane3f plane; }; -// Move the object along the Z of the Camera -// complement of the Plane mode -class ZMode: public TrackMode { - const char* Name() {return "ZMode";}; +// Cylinder mode. +// Rotates the object along a fixed axis +// The user can either drag the mouse or scroll the wheel, +// in either cases the rotation's angle is influenced by +// the radius of the trackball. +// The axis can be specified either with a line +// or a origin and a direction +// when the user drags the mouse, if the axis is too +// perpendicular to view plane, the angle is specified +// only by the vertical component of the mouse drag and the radius. +class CylinderMode:public TrackMode { public: - void Apply(Trackball *trackball, Point3f new_point); + CylinderMode (Line3fN & ln) + : axis (ln){ + } + CylinderMode (const Point3f & origin, const Point3f & direction) + : axis (Line3fN(origin,direction)){ + } + const char *Name () { + return "CylinderMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Apply (Trackball * trackball, float WheelNotch); + void Draw (Trackball * trackball); +private: + Line3fN axis; }; -class LineMode: public TrackMode { +// Path mode. +// move the object along an eventually closed path. +// The user can either drag the mouse or scroll the wheel, +// when the user drags the mouse, the object tries to slide toward it. +// if the path is a simple segment, it can be specified just with the endpoints, +// otherwise it's specified with a point vector and, eventually, a boolean value used for closing the path. +// the object is assumed to initially be on the same position of the first point on the path. +// you can try to set the starting point calling SetStartNear(Point3f) +// the path is NOT assumed to have 0-length segments, so, if you want to close the path, please DO NOT add +// a copy of the first point on the end of the vector... +// the vector passed to build the path is copied locally. +class PathMode:public TrackMode { public: - LineMode(const Line3f &/*line*/) {} - void Apply(Trackball * /*trackball*/, Point3f /*new_point*/) {} - const char* Name() {return "LineMode";}; -protected: - Line3f line; + PathMode ( const vector < Point3f > &pts, bool w = false) + : points(), wrap(w), current_state(0), initial_state(0), old_hitpoint() + { + Init(pts); + assert(min_seg_length > 0.0f); + } + PathMode ( const Point3f &start, const Point3f &end ) + : points(), wrap(false), current_state(0), initial_state(0), old_hitpoint() + { + points.push_back(start); + points.push_back(end); + path_length=Distance(start,end); + min_seg_length=path_length; + assert(min_seg_length > 0.0f); + } + const char *Name () { + return "PathMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Apply (Trackball * trackball, float WheelNotch); + void Draw (Trackball * trackball); + void SetAction (); + void Reset (); + Point3f SetStartNear(Point3f p); +private: + void Init(const vector < Point3f > &points); + void GetPoints(float state, Point3f & point, Point3f & prev_point, Point3f & next_point); + float Normalize(float state); + float HitPoint(float state, Ray3fN ray, Point3f &hit_point); + int Verse(Point3f reference_point,Point3f current_point,Point3f prev_point,Point3f next_point); + + vector < Point3f > points; + bool wrap; + float current_state; + float initial_state; + float path_length; + float min_seg_length; + Point3f old_hitpoint; + }; -class ScaleMode: public TrackMode { +// Area mode. +// The user can drag the object inside a planar area, defined by a polygon. +// the polygon can be non convex, and is specified with a vector of vertexes +// if the object's trajectory intersects some poligon side, it tries to slide +// around it, in a "rubber band flavoured" way. +// for the vertexes vector its calculated the plane of the polygon, and then +// every point in the vector is projected on this plane. +// the object is assumed to initially be on the same position of the first vertex. +// you can try to set the starting point calling SetStartNear(Point3f) +// the vector is assumed to be formed of NON collinear points +// the polygon is NOT assumed to have 0-length sides, so please DO NOT add +// a copy of the first point on the end of the vector... +// the vector passed to build the polygon is copied locally. + +class AreaMode:public TrackMode { public: - const char* Name() {return "ScaleMode";}; - void Apply(Trackball *trackball, Point3f new_point); + AreaMode (const vector < Point3f > &pts) + { + Init(pts); + assert(min_side_length > 0.0f); + } + const char *Name () { + return "AreaMode"; + }; + void Apply (Trackball * trackball, Point3f new_point); + void Draw (Trackball * trackball); + void SetAction (); + void Reset (); + Point3f SetStartNear(Point3f p); +private: + void Init(const vector < Point3f > &pts); + bool Inside(Point3f point); + Point3f Move(Point3f start,Point3f end); + + vector < Point3f > points; + bool begin_action; + int first_coord_kept; + int second_coord_kept; + float min_side_length; + Point3f status,delta_mouse,old_status,initial_status; + + Plane3f plane; + Point3f rubberband_handle ; + vector < Point3f > path; + }; }//namespace