trackmode.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 * VCGLib                                                            o o     *
00003 * Visual and Computer Graphics Library                            o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2004                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
00021 *                                                                           *
00022 ****************************************************************************/
00023 
00024 #include <GL/glew.h>
00025 #include <vcg/space/distance3.h>
00026 #include <wrap/gui/trackmode.h>
00027 #include <wrap/gui/trackball.h>
00028 #include <wrap/gui/trackutils.h>
00029 
00030 using namespace vcg;
00031 using namespace vcg::trackutils;
00032 
00033 // Track mode implementation, dummy.
00034 void TrackMode::Apply (Trackball * , float ){}
00035 
00036 void TrackMode::Apply (Trackball * , Point3f ){}
00037 
00038 void TrackMode::Draw(Trackball * ){}
00039 
00040 void TrackMode::SetAction (){}
00041 
00042 void TrackMode::Reset (){}
00043 
00044 bool TrackMode::IsAnimating(const Trackball *){
00045     return false;
00046 }
00047 
00048 void TrackMode::Animate(unsigned int, Trackball *){
00049 }
00050 
00051 bool TrackMode::isSticky() {
00052   return false;
00053 }
00054 
00055 void TrackMode::Undo(){}
00056 
00057 // draw an inactive trackball
00058 void InactiveMode::Draw(Trackball * tb){
00059   DrawSphereIcon(tb,false);
00060 }
00061 
00062 // Sphere mode implementation.
00063 // the most important function; given a new point in window coord,
00064 // it update the transformation computed by the trackball.
00065 // General scheme : the transformation is a function of just
00066 //   the begin and current mouse positions, with greater precision
00067 //   is function of just two 3d points over the manipulator.
00068 void SphereMode::Apply (Trackball * tb, Point3f new_point)
00069 {
00070   Point3f hitOld = HitSphere (tb, tb->last_point);
00071   Point3f hitNew = HitSphere (tb, new_point);
00072   tb->Hits.push_back (hitNew);
00073   Point3f center = tb->center;
00074   Point3f axis = (hitNew - center) ^ (hitOld - center);
00075   vcg::Normalize(axis);
00076 
00077   //  Figure out how much to rotate around that axis.
00078 //  float phi = Distance (hitNew, hitOld) / tb->radius;
00079 //  float phi = vcg::Angle(hitNew - center,hitOld - center)*(Distance(hitNew,center)/tb->radius);
00080   float phi = max(vcg::Angle(hitNew - center,hitOld - center),(Distance(hitNew,hitOld)/tb->radius)) ;
00081 
00082   tb->track.rot = Quaternionf (-phi, axis) * tb->last_track.rot;
00083 }
00084 
00085 void SphereMode::Draw(Trackball * tb){
00086   DrawSphereIcon(tb,true );
00087 }
00088 
00089 // Pan mode implementation.
00090 void PanMode::Apply (Trackball * tb, Point3f new_point)
00091 {
00092   Point3f hitOld = HitViewPlane (tb, tb->last_point);
00093   Point3f hitNew = HitViewPlane (tb, new_point);
00094   tb->Translate (hitNew - hitOld);
00095 }
00096 
00097 void PanMode::Draw(Trackball * tb){
00098   DrawSphereIcon(tb,true );
00099   DrawUglyPanMode(tb);
00100 }
00101 
00102 // Z mode implementation.
00103 void ZMode::Apply (Trackball * tb, float WheelNotch)
00104 {
00105   Point3f dir= (GetViewPlane (tb->camera, tb->center)).Direction();
00106   dir.Normalize();
00107   tb->Translate (dir * (-WheelNotch));
00108 }
00109 
00110 void ZMode::Apply (Trackball * tb, Point3f new_point)
00111 {
00112   Point3f dir= (GetViewPlane (tb->camera, tb->center)).Direction();
00113   dir.Normalize();
00114   tb->Translate (dir * ( -2.0f * getDeltaY(tb,new_point)));
00115 }
00116 
00117 void ZMode::Draw(Trackball * tb){
00118   DrawSphereIcon(tb,true );
00119   DrawUglyZMode(tb);
00120  }
00121 
00122 // Scale mode implementation.
00123 void ScaleMode::Apply (Trackball * tb, float WheelNotch)
00124 {
00125   tb->track.sca *= pow (1.2f, -WheelNotch);
00126 }
00127 
00128 void ScaleMode::Apply (Trackball * tb, Point3f new_point)
00129 {
00130   tb->track.sca = tb->last_track.sca * pow (3.0f, -(getDeltaY(tb,new_point)));
00131 }
00132 
00133 void ScaleMode::Draw(Trackball * tb){
00134   DrawSphereIcon(tb,true );
00135   DrawUglyScaleMode(tb);
00136 }
00137 
00138 // Axis mode implementation.
00139 void AxisMode::Apply (Trackball * tb, float WheelNotch)
00140 {
00141   tb->Translate (axis.Direction () * (WheelNotch / 10.0f));
00142 }
00143 
00144 void AxisMode::Apply (Trackball * tb, Point3f new_point)
00145 {
00146   std::pair< Point3f,bool > hitOld = HitNearestPointOnAxis (tb, axis, tb->last_point);
00147   std::pair< Point3f,bool > hitNew = HitNearestPointOnAxis (tb, axis, new_point);
00148   if (hitOld.second && hitNew.second){
00149     tb->Translate (hitNew.first - hitOld.first);
00150   }
00151 }
00152 
00153 void AxisMode::Draw(Trackball * tb){
00154   DrawSphereIcon(tb,true );
00155   DrawUglyAxisMode(tb,axis);
00156 }
00157 
00158 // Plane mode implementation.
00159 void PlaneMode::Apply (Trackball * tb, Point3f new_point)
00160 {
00161   std::pair< Point3f, bool > hitOld = HitPlane(tb,tb->last_point,plane);
00162   std::pair< Point3f, bool > hitNew = HitPlane(tb,new_point,plane);
00163   if(hitOld.second && hitNew.second){
00164       tb->Translate (hitNew.first - hitOld.first);
00165   }
00166 }
00167 
00168 void PlaneMode::Draw(Trackball * tb){
00169   DrawSphereIcon(tb,true );
00170   DrawUglyPlaneMode(tb, plane);
00171 }
00172 
00173 // Cylinder mode implementation.
00174 void CylinderMode::Apply (Trackball * tb, float WheelNotch)
00175 {
00176   const float PI2=6.283185307179586232f;
00177   float angle= (snap==0.0) ? WheelNotch/(tb->radius * PI2) : WheelNotch * snap;
00178   tb->track.rot = tb->last_track.rot * Quaternionf (angle,axis.Direction());
00179 }
00180 
00181 void CylinderMode::Apply (Trackball * tb, Point3f new_point)
00182 {
00183   Plane3f viewplane=GetViewPlane (tb->camera, tb->center);
00184   Line3f axisproj;
00185   axisproj=ProjectLineOnPlane(axis,viewplane);
00186   float angle;
00187   const float EPSILON=0.005f; // this IS scale independent
00188   if(axisproj.Direction().Norm() < EPSILON){
00189     angle=(10.0f * getDeltaY(tb,new_point)) / tb->radius;
00190   } else {
00191     Point3f hitOld = HitViewPlane (tb, tb->last_point);
00192     Point3f hitNew = HitViewPlane (tb, new_point);
00193     axisproj.Normalize();
00194     Point3f plusdir= viewplane.Direction() ^ axisproj.Direction();
00195     float distOld = signedDistance(axisproj,hitOld,plusdir);
00196     float distNew = signedDistance(axisproj,hitNew,plusdir);
00197     angle= (distNew-distOld) / tb->radius;
00198   }
00199   if(snap>0.0){
00200     angle = ((angle<0)?-1:1)* floor((((angle<0)?-angle:angle)/snap)+0.5f)*snap;
00201   }
00202 //  tb->track.rot = tb->last_track.rot * Quaternionf (angle,axis.Direction());
00203   tb->track.rot = Quaternionf (-angle,axis.Direction()) * tb->last_track.rot;
00204 }
00205 
00206 void CylinderMode::Draw(Trackball * tb){
00207   DrawSphereIcon(tb,true );
00208   DrawUglyCylinderMode(tb,axis);
00209 }
00210 
00211 // Path mode implementation.
00212 void PathMode::Init(const std::vector < Point3f > &pts)
00213 {
00214   unsigned int npts = int(pts.size());
00215   assert(npts >= 2);
00216   points.reserve(npts);
00217   for(unsigned int i=0;i<npts;i++){
00218     points.push_back(pts[i]);
00219   }
00220   path_length=0.0f;
00221   min_seg_length=Distance(points[0],points[1]);
00222   float seg_length;
00223   for(unsigned int i=1;i<npts;i++){
00224     seg_length=Distance(points[i-1],points[i]);
00225     path_length += seg_length;
00226     min_seg_length = (std::min)(seg_length,min_seg_length);
00227   }
00228   if(wrap){
00229     seg_length=Distance(points[npts-1],points[0]);
00230     path_length += seg_length;
00231     min_seg_length = (std::min)(seg_length,min_seg_length);
00232   }
00233 }
00234 
00235 void PathMode::Reset()
00236 {
00237   current_state=initial_state;
00238 }
00239 
00240 Point3f PathMode::SetStartNear(Point3f point)
00241 {
00242   float p0_state=0;
00243   Point3f p0,p1;
00244   float nearest_state=0;
00245   Point3f nearest_point=points[0];
00246   float nearest_distance=Distance(nearest_point,point);
00247   unsigned int npts = int(points.size());
00248   for(unsigned int i = 1;i <= npts;i++){
00249     if( i == npts){
00250       if (wrap){
00251         p0=points[npts-1];
00252         p1=points[0];
00253       } else {
00254         break;
00255       }
00256     } else {
00257         p0=points[i-1];
00258         p1=points[i];
00259     }
00260     //Point3f segment_point=ClosestPoint(Segment3f(p0,p1),point);
00261         Point3f segment_point;
00262         float distance;
00263         vcg::SegmentPointDistance<float>(Segment3f(p0,p1),point,segment_point,distance);
00264    // float distance=Distance(segment_point,point);
00265     if(distance<nearest_distance){
00266       nearest_point=segment_point;
00267       nearest_distance=distance;
00268       nearest_state=p0_state+(Distance(p0,nearest_point)/path_length);
00269     }
00270     float segment_norm= Distance(p0,p1) / path_length;
00271     p0_state+=segment_norm;
00272   }
00273   assert( nearest_state >= 0.0 );
00274   if(nearest_state > 1.0){
00275     nearest_state=1.0;
00276     nearest_point=( wrap ? points[0] : points[npts-1] );
00277   }
00278   initial_state=nearest_state;
00279   return nearest_point;
00280 }
00281 
00282 void PathMode::GetPoints(float state, Point3f & point, Point3f & prev_point, Point3f & next_point)
00283 {
00284   assert(state >= 0.0f);
00285   assert(state <= 1.0f);
00286   float remaining_norm=state;
00287   Point3f p0(0,0,0),p1(0,0,0);
00288   unsigned int npts = int(points.size());
00289   for(unsigned int i = 1;i <= npts;i++){
00290     if( i == npts){
00291       if (wrap){
00292         p0=points[npts-1];
00293         p1=points[0];
00294       } else {
00295         break;
00296       }
00297     } else {
00298         p0=points[i-1];
00299         p1=points[i];
00300     }
00301     float segment_norm= Distance(p0,p1) / path_length;
00302     if (segment_norm < remaining_norm){
00303        remaining_norm -= segment_norm;
00304       continue;
00305     }
00306     prev_point = p0;
00307     next_point = p1;
00308     float ratio= remaining_norm / segment_norm;
00309     point = prev_point + (( next_point - prev_point ) * ratio);
00310     const float EPSILON=min_seg_length * 0.01f;
00311     if(Distance(point,prev_point) < EPSILON){
00312       point=prev_point;
00313       if (i > 1){
00314         prev_point=points[i-2];
00315       } else if (wrap){
00316         prev_point=points[npts-1];
00317       }
00318     } else if (Distance(point,next_point) < EPSILON){
00319       point=next_point;
00320       if( i < (npts-1)){
00321         next_point=points[i+1];
00322       } else {
00323         if (wrap){
00324           next_point=points[1];
00325         } else {
00326           next_point=points[npts-1];
00327         }
00328       }
00329     }
00330     return;
00331   }
00332   // rounding errors can lead out of the for..
00333   prev_point = p0;
00334   point = p1;
00335   if (wrap){
00336     next_point=points[1];
00337   }else{
00338     next_point = points[npts-1];
00339   }
00340 }
00341 
00342 void PathMode::Apply (Trackball * tb, float WheelNotch)
00343 {
00344   undo_current_state=current_state;
00345   undo_old_hitpoint=old_hitpoint;
00346 
00347   const float STEP_COEFF = min_seg_length * 0.5f;
00348   float delta=(WheelNotch*STEP_COEFF)/path_length;
00349   Point3f old_point,new_point,prev_point,next_point;
00350   GetPoints(current_state,old_point,prev_point,next_point);
00351   current_state=Normalize(current_state+delta);
00352   GetPoints(current_state,new_point,prev_point,next_point);
00353   tb->Translate (new_point - old_point);
00354 }
00355 
00356 float PathMode::Normalize(float state)
00357 {
00358   if ( wrap ) {
00359     double intpart;
00360     float fractpart;
00361     fractpart =(float) modf(state,&intpart);
00362     if( fractpart < 0.0f )
00363       fractpart += 1.0f;
00364     return fractpart;
00365   }
00366   if ( state < 0.0f )
00367     return 0.0f;
00368   if ( state > 1.0f )
00369     return 1.0f;
00370   return state;
00371 }
00372 
00373 int PathMode::Verse(Point3f reference_point,Point3f current_point,Point3f prev_point,Point3f next_point)
00374 {
00375   Point3f reference_dir = reference_point - current_point ;
00376   Point3f prev_dir = prev_point - current_point ;
00377   Point3f next_dir = next_point - current_point ;
00378   const float EPSILON=min_seg_length * 0.005f;
00379   if (reference_dir.Norm()  < EPSILON)
00380     reference_dir = Point3f(0,0,0);
00381   if (prev_dir.Norm() < EPSILON)
00382     prev_dir = Point3f(0,0,0);
00383   if (next_dir.Norm()   < EPSILON)
00384     next_dir = Point3f(0,0,0);
00385   reference_dir.Normalize();
00386   prev_dir.Normalize();
00387   next_dir.Normalize();
00388   float prev_coeff,next_coeff;
00389   prev_coeff = prev_dir.dot(reference_dir);
00390   next_coeff = next_dir.dot(reference_dir);
00391   if (prev_coeff < 0.0f)
00392     prev_coeff = 0.0f;
00393    if (next_coeff < 0.0f)
00394     next_coeff = 0.0f;
00395   if( (prev_coeff == 0.0f) && (next_coeff == 0.0f)){
00396     return 0;
00397   }
00398   if ( prev_coeff <= next_coeff ){
00399     return 1;
00400   }
00401   return -1;
00402 }
00403 
00404 float PathMode::HitPoint(float state, Ray3fN ray, Point3f &hit_point)
00405 {
00406  Point3f current_point, next_point, prev_point;
00407   GetPoints(state,current_point,prev_point,next_point);
00408 
00409   Point3f closest_point;
00410   closest_point=ray.ClosestPoint(current_point);
00411   int verse=Verse(closest_point,current_point,prev_point,next_point);
00412   if (verse == 0){
00413     hit_point=current_point;
00414     return 0.0f;
00415   }
00416 
00417   Segment3f active_segment;
00418   if (verse > 0){
00419     active_segment=Segment3f(current_point,next_point);
00420   } else {
00421     active_segment= Segment3f(current_point,prev_point);
00422   }
00423 
00424   //hit_point=ClosestPoint(active_segment,closest_point);
00425     float dist;
00426     vcg::SegmentPointDistance<float>(active_segment,closest_point,hit_point,dist);
00427 
00428   return verse * ((hit_point-current_point).Norm() / path_length);
00429 }
00430 
00431 void PathMode::SetAction (){
00432   Point3f temp1,temp2;
00433   GetPoints(current_state,old_hitpoint,temp1,temp2);
00434 }
00435 
00436 void PathMode::Apply (Trackball * tb, Point3f new_point)
00437 {
00438     undo_current_state=current_state;
00439     undo_old_hitpoint=old_hitpoint;
00440 
00441     Ray3fN ray = line2ray(tb->camera.ViewLineFromWindow (new_point));
00442     Point3f hit_point;
00443     float delta_state=HitPoint(current_state,ray,hit_point);
00444     current_state=Normalize(current_state+delta_state);
00445     tb->Translate (hit_point - old_hitpoint);
00446 }
00447 
00448 bool PathMode::isSticky() {
00449   return true;
00450 }
00451 
00452 void PathMode::Undo(){
00453   current_state=undo_current_state;
00454   old_hitpoint=undo_old_hitpoint;
00455 }
00456 
00457 void PathMode::Draw(Trackball * tb){
00458   DrawSphereIcon(tb,true );
00459   Point3f current_point,prev_point,next_point;
00460   GetPoints(current_state,current_point,prev_point,next_point);
00461   DrawUglyPathMode(tb,points,current_point,prev_point,
00462   next_point,old_hitpoint,wrap);
00463 }
00464 
00465 // Area mode implementation.
00466 void AreaMode::Init(const std::vector < Point3f > &pts)
00467 {
00468   unsigned int npts = int(pts.size());
00469 
00470   assert(npts >= 3);
00471   //get the plane
00472   Point3f p0=pts[0];
00473   unsigned int onethird=(unsigned int)floor(npts/3.0);
00474   const float EPSILON = 0.005f;
00475   bool pts_not_in_line=false;
00476   Point3f a,b;
00477   for(unsigned int i=0;i<onethird;i++){
00478      a=(pts[(i+   onethird )%npts] - pts[i%npts]).normalized();
00479      b=(pts[(i+(2*onethird))%npts] - pts[i%npts]).normalized();
00480      pts_not_in_line = (a ^ b).Norm() > EPSILON;
00481      if(pts_not_in_line){
00482         plane.Init( pts[i%npts],
00483                     pts[(i+(onethird))%npts],
00484                     pts[(i+(2*onethird))%npts]);
00485         break;
00486      }
00487   }
00488   assert(pts_not_in_line);
00489   float ncx,ncy,ncz;
00490   ncx=fabs(plane.Direction()[0]);
00491   ncy=fabs(plane.Direction()[1]);
00492   ncz=fabs(plane.Direction()[2]);
00493   if(( ncx > ncy ) && ( ncx > ncz )){
00494     first_coord_kept=1;
00495     second_coord_kept=2;
00496   } else if(( ncy > ncx ) && ( ncy > ncz)){
00497     first_coord_kept=0;
00498     second_coord_kept=2;
00499   } else {
00500     first_coord_kept=0;
00501     second_coord_kept=1;
00502   }
00503   points.reserve(npts);
00504   for(unsigned int i=0;i<npts;i++){
00505     points.push_back(plane.Projection(pts[i]));
00506   }
00507   min_side_length=Distance(points[0],points[1]);
00508   for(unsigned int i=1;i<npts;i++){
00509     min_side_length=(std::min)(Distance(points[i-1],points[i]),min_side_length);
00510   }
00511   rubberband_handle=old_status=status=initial_status=p0;
00512 }
00513 
00514 void AreaMode::Reset()
00515 {
00516   rubberband_handle=old_status=status=initial_status;
00517   path.clear();
00518 }
00519 
00520 void AreaMode::Apply (Trackball * tb, Point3f new_point)
00521 {
00522   undo_begin_action=begin_action;
00523   undo_status=status;
00524   undo_delta_mouse=delta_mouse;
00525   undo_old_status=old_status;
00526   undo_rubberband_handle=rubberband_handle;
00527   undo_path_index=path.size();
00528 
00529   if(begin_action){
00530     delta_mouse=tb->camera.Project(status)-new_point;
00531     begin_action=false;
00532   }
00533   std::pair< Point3f, bool > hitNew = HitPlane(tb,new_point+delta_mouse,plane);
00534   if(! hitNew.second){
00535       return;
00536   }
00537   Point3f hit_point=hitNew.first;
00538   Point3f delta_status=Move(status,hit_point);
00539   status += delta_status;
00540   tb->Translate (status - old_status);
00541   rubberband_handle=hit_point;
00542 }
00543 
00544 
00545 void AreaMode::SetAction ()
00546 {
00547   begin_action=true;
00548   old_status=status;
00549 
00550   path.clear();
00551   path.push_back(status);
00552   rubberband_handle=status;
00553 }
00554 
00555 Point3f AreaMode::Move(Point3f start,Point3f end)
00556 {
00557   const float EPSILON=min_side_length*0.001f;
00558   Point3f pt=start;
00559   bool done=false;
00560   bool end_inside=Inside(end);
00561   while(!done){
00562     path.push_back(pt);
00563     Segment3f segment(pt,end);
00564     bool p_on_side = false;
00565     bool hit=false;
00566 
00567     Point3f pside(0,0,0),phit(0,0,0);
00568     bool slide=false,mid_inside=false;
00569 
00570     int np = int(points.size()), i, j;
00571     for (i = 0, j = np-1; i < np; j = i++) {
00572       Segment3f side(points[i],points[j]);
00573       Point3f pseg,psid;
00574       //std::pair<float,bool> res=SegmentSegmentDistance(segment,side,pseg,psid);
00575             std::pair<float,bool> res;
00576             vcg::SegmentSegmentDistance(segment,side,res.first,res.second,pseg,psid);
00577       if(res.first < EPSILON && ! res.second){
00578         float dist= Distance(pt,pseg);
00579         if(dist < EPSILON){
00580           //Point3f pn=ClosestPoint(side,end);
00581                     Point3f pn;
00582                     float dist;
00583                     vcg::SegmentPointDistance<float>(side,end,pn,dist);
00584           if(!p_on_side || (Distance(pn,end)<Distance(end,pside))){
00585             pside=pn;
00586             p_on_side=true;
00587           }
00588         } else {
00589           if (!hit || Distance(pt,pseg) < Distance(pt,phit)){
00590             phit=pseg;
00591             hit=true;
00592           }
00593         }
00594       }
00595     }
00596     if (p_on_side)
00597       slide = Distance(pside,pt) > EPSILON;
00598 
00599     if (hit)
00600       mid_inside = Inside( pt + ( ( phit - pt ) / 2) );
00601 
00602     if ( !hit && end_inside ){
00603       pt = end;
00604       done = true;
00605     } else if ( hit && (!p_on_side || (p_on_side && mid_inside))) {
00606       pt = phit;
00607     } else if ( p_on_side && slide) {
00608       pt = pside;
00609     } else {
00610       done = true;
00611     }
00612   }
00613   path.push_back(pt);
00614   return pt - start;
00615 }
00616 
00617 // adapted from the original C code by W. Randolph Franklin
00618 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
00619 bool AreaMode::Inside(Point3f point)
00620 {
00621   bool inside=false;
00622   float x=point[first_coord_kept];
00623   float y=point[second_coord_kept];
00624   float yi, yj, xi, xj;
00625   int i, j, np=int(points.size());
00626   for (i = 0, j = np-1; i < np; j = i++) {
00627     xi=points[i][first_coord_kept];
00628     yi=points[i][second_coord_kept];
00629     xj=points[j][first_coord_kept];
00630     yj=points[j][second_coord_kept];
00631     if ( ( ( (yi<=y) && (y<yj) ) || ( (yj<=y) && (y<yi) ) ) &&
00632          ( x < ( xj - xi ) * ( y - yi ) / ( yj - yi ) + xi )  )
00633     {
00634       inside=!inside;
00635     }
00636    }
00637   return inside;
00638 }
00639 
00640 Point3f AreaMode::SetStartNear(Point3f point)
00641 {
00642   Point3f candidate=plane.Projection(point);
00643   if (Inside(candidate)){
00644     initial_status=candidate;
00645     return initial_status;
00646   }
00647   Point3f nearest_point=initial_status;
00648   float nearest_distance=Distance(nearest_point,candidate);
00649   int i, j, np=int(points.size());
00650   for (i = 0, j = np-1; i < np; j = i++) {
00651     Segment3f side(points[i],points[j]);
00652     //Point3f side_point=ClosestPoint(side,candidate);
00653     //float distance=Distance(side_point,candidate);
00654         Point3f side_point;
00655         float distance;
00656         vcg::SegmentPointDistance<float>(side,candidate,side_point,distance);
00657     if( distance < nearest_distance ){
00658       nearest_point=side_point;
00659       nearest_distance=distance;
00660     }
00661   }
00662   initial_status=nearest_point;
00663   return initial_status;
00664 }
00665 
00666 bool AreaMode::isSticky() {
00667   return true;
00668 }
00669 
00670 void AreaMode::Undo(){
00671   begin_action=undo_begin_action;
00672   status=undo_status;
00673   delta_mouse=undo_delta_mouse;
00674   old_status=undo_old_status;
00675   rubberband_handle=undo_rubberband_handle;
00676   for(size_t i=path.size() - 1; i > undo_path_index; --i)
00677      path.pop_back();
00678 }
00679 
00680 void AreaMode::Draw(Trackball * tb)
00681 {
00682   DrawSphereIcon(tb,true );
00683   DrawUglyAreaMode(tb,points,status,old_status,plane,path,rubberband_handle);
00684 }
00685 
00686 // Polar mode implementation.
00687 void PolarMode::Apply (Trackball * tb, Point3f new_point)
00688 {
00689   Point3f hitOld = HitViewPlane (tb, tb->last_point);
00690   Point3f hitNew = HitViewPlane (tb, new_point);
00691   float dx = (hitNew.X() - hitOld.X());
00692   float dy = (hitNew.Y() - hitOld.Y());
00693 
00694   const float scale = float(0.5*M_PI); //sensitivity of the mouse
00695   const float top = float(0.9*M_PI/2); //maximum top view angle
00696 
00697   float anglex =  dx/(tb->radius * scale);
00698   float angley = -dy/(tb->radius * scale);
00699   enda = alpha + anglex;
00700   endb = beta + angley;
00701   if(endb > top) endb = top;
00702   if(endb < -top) endb = -top;
00703   tb->track.rot = Quaternionf (endb, Point3f(1,0,0)) *
00704                   Quaternionf (enda, Point3f(0,1,0)) ;
00705 
00706 }
00707 
00708 void PolarMode::SetAction() {
00709   alpha = enda;
00710   beta = endb;
00711 }
00712 
00713 void PolarMode::Reset() {
00714   alpha = beta = enda = endb = 0;
00715 }
00716 
00717 
00718 void PolarMode::Draw(Trackball * tb){
00719   DrawSphereIcon(tb,true );
00720 }
00721 
00722 
00723 // Navigator WASD implementation
00724 
00725 NavigatorWasdMode::NavigatorWasdMode() {
00726   _flipH=1; _flipV=1;
00727   SetTopSpeedsAndAcc(1,1,4);
00728     step_height = step_length = 0;
00729   Reset();
00730 };
00731 
00732 void NavigatorWasdMode::Reset() {
00733   alpha=0;
00734     beta=0;
00735     current_speed.SetZero();
00736     step_x=0.0f;
00737 
00738     step_current = step_last = 0.0;
00739 }
00740 
00741 void NavigatorWasdMode::FlipH(){
00742  _flipH*=-1;
00743 }
00744 
00745 void NavigatorWasdMode::FlipV(){
00746  _flipV*=-1;
00747 }
00748 
00749 
00750 void NavigatorWasdMode::SetAction() {
00751 
00752 }
00753 
00754 bool NavigatorWasdMode::IsAnimating(const Trackball * tb){
00755     const unsigned int MOVEMENT_KEY_MASK = (const unsigned int)(~Trackball::MODIFIER_MASK);
00756     if (tb->current_button & MOVEMENT_KEY_MASK) return true;
00757     if (current_speed!=Point3f(0,0,0)) return true;
00758     if (step_current>0.0) return true;
00759     return false;
00760 }
00761 
00762 void NavigatorWasdMode::Animate(unsigned int msec, Trackball * tb){
00763     vcg::Point3f acc(0,0,0);
00764 
00765     float sa = sin(-alpha);
00766     float ca = cos(-alpha);
00767     if (tb->current_button & Trackball::KEY_UP    ) acc += vcg::Point3f( sa,0,ca)*(accY*_flipH);
00768     if (tb->current_button & Trackball::KEY_DOWN  ) acc -= vcg::Point3f( sa,0,ca)*(accY*_flipH);
00769     if (tb->current_button & Trackball::KEY_LEFT  ) acc -= vcg::Point3f(-ca,0,sa)*accX;
00770     if (tb->current_button & Trackball::KEY_RIGHT ) acc += vcg::Point3f(-ca,0,sa)*accX;
00771     if (tb->current_button & Trackball::KEY_PGUP  ) acc -= vcg::Point3f(  0,1, 0)*accZ;
00772     if (tb->current_button & Trackball::KEY_PGDOWN) acc += vcg::Point3f(  0,1, 0)*accZ;
00773 
00774     float sec = msec/1.0f;
00775     current_speed += acc*sec;
00776     tb->track.tra+=current_speed*sec;
00777 
00778     // compute step height.
00779     Point3f current_speed_h = current_speed;
00780     current_speed_h[1]=0;
00781     float vel = current_speed_h.Norm();
00782     if (vel<topSpeedH*0.05) {
00783     // stopped: decrease step heigth to zero
00784         step_current*=pow(dumping,sec);
00785     if (step_current<step_height*0.06) { step_current=0; step_x=0.0f;}
00786   } else {
00787     // running: rise step heigth
00788     vel = current_speed.Norm();
00789         step_x += vel*sec;
00790       float step_current_min = (float)fabs(sin( step_x*M_PI / step_length ))*step_height;
00791         if (step_current<step_current_min) step_current=step_current_min;
00792     }
00793 
00794     current_speed*=pow(dumping,sec);
00795     if (current_speed.Norm()<topSpeedH*0.005) current_speed.SetZero(); // full stop
00796 
00797   tb->track.tra[1]+=step_last;
00798   tb->track.tra[1]-=step_current;
00799     step_last=step_current;
00800 
00801   //tb->track.tra[1]+=0.01;
00802 }
00803 
00804 void NavigatorWasdMode::Apply (Trackball * tb, Point3f new_point)
00805 {
00806   Point3f hitOld = tb->last_point;
00807   Point3f hitNew = new_point;
00808     tb->last_point=new_point;
00809   float dx = (hitNew.X() - hitOld.X());
00810   float dy = (hitNew.Y() - hitOld.Y());
00811 
00812   const float scale = float(150*M_PI); //sensitivity of the mouse
00813   const float top = float(0.9f*M_PI/2); //maximum top view angle
00814 
00815   float anglex =  dx/(tb->radius * scale);
00816   float angley = -dy/(tb->radius * scale * 0.5f);
00817   alpha+= anglex*_flipH;
00818   beta += angley*_flipV;
00819   if(beta > +top) beta = +top;
00820   if(beta < -top) beta = -top;
00821 
00822   Point3f viewpoint = tb->track.InverseMatrix()*Point3f(0,0,0);
00823     tb->track.tra = tb->track.rot.Inverse().Rotate(tb->track.tra + viewpoint ) ;
00824   tb->track.rot = Quaternionf (beta , Point3f(1,0,0)) *
00825                   Quaternionf (alpha, Point3f(0,1,0)) ;
00826     tb->track.tra = tb->track.rot.Rotate(tb->track.tra)  - viewpoint ;
00827 
00828     tb->track.tra[1]+=step_last;
00829   tb->track.tra[1]-=step_current;
00830 
00831     step_last=step_current;
00832 
00833 }
00834 
00835 void NavigatorWasdMode::SetTopSpeedsAndAcc(float hspeed, float vspeed, float acc){
00836   // conversion to msec
00837   hspeed /= 1000;
00838   vspeed /= 1000;
00839   acc /= 1000000;
00840 
00841   accX = accY = acc;
00842   dumping = hspeed / ( hspeed + acc );
00843   accZ = ( vspeed  / dumping ) - vspeed;
00844   if (acc==0) {
00845     accX = accY = hspeed;
00846     accZ = vspeed;
00847     dumping=0.0;
00848   }
00849   topSpeedH = hspeed;  topSpeedV=vspeed;
00850 
00851 }
00852 
00853 void NavigatorWasdMode::SetStepOnWalk(float width, float height){
00854   step_length  = width;
00855   step_height = height;
00856 }
00857 
00858 void NavigatorWasdMode::Apply (Trackball * tb, float WheelNotch)
00859 {
00860   tb->Translate(Point3f(0,topSpeedV,0)*(-WheelNotch*100));
00861 }
00862 
00863 
00864 bool NavigatorWasdMode::isSticky(){
00865     return false;
00866 }


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:37:26