00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
00058 void InactiveMode::Draw(Trackball * tb){
00059 DrawSphereIcon(tb,false);
00060 }
00061
00062
00063
00064
00065
00066
00067
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
00078
00079
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
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
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
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
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
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
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;
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
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
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
00261 Point3f segment_point;
00262 float distance;
00263 vcg::SegmentPointDistance<float>(Segment3f(p0,p1),point,segment_point,distance);
00264
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
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
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
00466 void AreaMode::Init(const std::vector < Point3f > &pts)
00467 {
00468 unsigned int npts = int(pts.size());
00469
00470 assert(npts >= 3);
00471
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
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
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
00618
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
00653
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
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);
00695 const float top = float(0.9*M_PI/2);
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
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
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
00784 step_current*=pow(dumping,sec);
00785 if (step_current<step_height*0.06) { step_current=0; step_x=0.0f;}
00786 } else {
00787
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();
00796
00797 tb->track.tra[1]+=step_last;
00798 tb->track.tra[1]-=step_current;
00799 step_last=step_current;
00800
00801
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);
00813 const float top = float(0.9f*M_PI/2);
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
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 }