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