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 "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <cfloat>
00027 # include "InventorAll.h"
00028 # include <QAction>
00029 # include <QActionGroup>
00030 # include <QApplication>
00031 # include <QByteArray>
00032 # include <QCursor>
00033 # include <QList>
00034 # include <QMenu>
00035 # include <QMetaObject>
00036 # include <QRegExp>
00037 #endif
00038
00039 #include <Inventor/sensors/SoTimerSensor.h>
00040
00041 #include <App/Application.h>
00042 #include "NavigationStyle.h"
00043 #include "View3DInventorViewer.h"
00044 #include "Application.h"
00045 #include "MenuManager.h"
00046 #include "MouseSelection.h"
00047
00048 using namespace Gui;
00049
00050 namespace Gui {
00051 struct NavigationStyleP {
00052 int animationsteps;
00053 int animationdelta;
00054 SbVec3f focal1, focal2;
00055 SbRotation endRotation;
00056 SoTimerSensor * animsensor;
00057
00058 NavigationStyleP()
00059 {
00060 this->animationsteps = 0;
00061 }
00062 static void viewAnimationCB(void * data, SoSensor * sensor);
00063 };
00064 }
00065
00066 class FCSphereSheetProjector : public SbSphereSheetProjector {
00067 typedef SbSphereSheetProjector inherited;
00068
00069 public:
00070 enum OrbitStyle {
00071 Turntable,
00072 Trackball
00073 };
00074
00075 FCSphereSheetProjector(const SbSphere & sph, const SbBool orienttoeye = TRUE)
00076 : SbSphereSheetProjector(sph, orienttoeye), orbit(Trackball)
00077 {
00078 }
00079
00080 void setViewVolume (const SbViewVolume &vol)
00081 {
00082 inherited::setViewVolume(vol);
00083 }
00084
00085 void setWorkingSpace (const SbMatrix &space)
00086 {
00087
00088 this->worldToScreen = space.inverse();
00089 }
00090
00091 SbVec3f project(const SbVec2f &point)
00092 {
00093 return inherited::project(point);
00094 }
00095
00096 SbRotation getRotation(const SbVec3f &point1, const SbVec3f &point2)
00097 {
00098 SbRotation rot = inherited::getRotation(point1, point2);
00099 if (orbit == Trackball)
00100 return rot;
00101
00102
00103 SbVec3f axis;
00104 float angle;
00105 rot.getValue(axis, angle);
00106 SbVec3f dif = point1 - point2;
00107 if (fabs(dif[1]) > fabs(dif[0])) {
00108 SbVec3f xaxis(1,0,0);
00109 if (dif[1] < 0)
00110 angle = -angle;
00111 rot.setValue(xaxis, angle);
00112 }
00113 else {
00114 SbVec3f zaxis(0,0,1);
00115 this->worldToScreen.multDirMatrix(zaxis, zaxis);
00116 if (dif[0] > 0)
00117 angle = -angle;
00118 rot.setValue(zaxis, angle);
00119 }
00120
00121 return rot;
00122 }
00123
00124 void setOrbitStyle(OrbitStyle style)
00125 {
00126 this->orbit = style;
00127 }
00128
00129 OrbitStyle getOrbitStyle() const
00130 {
00131 return this->orbit;
00132 }
00133
00134 private:
00135 SbMatrix worldToScreen;
00136 OrbitStyle orbit;
00137 };
00138
00139 NavigationStyleEvent::NavigationStyleEvent(const Base::Type& s)
00140 : QEvent(QEvent::User), t(s)
00141 {
00142 }
00143
00144 NavigationStyleEvent::~NavigationStyleEvent()
00145 {
00146 }
00147
00148 const Base::Type& NavigationStyleEvent::style() const
00149 {
00150 return t;
00151 }
00152
00153 #define PRIVATE(ptr) (ptr->pimpl)
00154 #define PUBLIC(ptr) (ptr->pub)
00155
00156 TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStyle,Base::BaseClass);
00157
00158 NavigationStyle::NavigationStyle() : viewer(0), mouseSelection(0)
00159 {
00160 PRIVATE(this) = new NavigationStyleP();
00161 PRIVATE(this)->animsensor = new SoTimerSensor(NavigationStyleP::viewAnimationCB, this);
00162 initialize();
00163 }
00164
00165 NavigationStyle::~NavigationStyle()
00166 {
00167 finalize();
00168 if (PRIVATE(this)->animsensor->isScheduled())
00169 PRIVATE(this)->animsensor->unschedule();
00170 delete PRIVATE(this)->animsensor;
00171 delete PRIVATE(this);
00172 }
00173
00174 NavigationStyle& NavigationStyle::operator = (const NavigationStyle& ns)
00175 {
00176 this->panningplane = ns.panningplane;
00177 this->menuenabled = ns.menuenabled;
00178 this->spinanimatingallowed = ns.spinanimatingallowed;
00179 return *this;
00180 }
00181
00182 void NavigationStyle::setViewer(View3DInventorViewer* view)
00183 {
00184 this->viewer = view;
00185 }
00186
00187 void NavigationStyle::initialize()
00188 {
00189 this->currentmode = NavigationStyle::IDLE;
00190 this->prevRedrawTime = SbTime::getTimeOfDay();
00191 this->spinanimatingallowed = TRUE;
00192 this->spinsamplecounter = 0;
00193 this->spinincrement = SbRotation::identity();
00194 this->spinRotation.setValue(SbVec3f(0, 0, -1), 0);
00195
00196
00197
00198
00199 this->spinprojector = new FCSphereSheetProjector(SbSphere(SbVec3f(0, 0, 0), 0.8f));
00200 SbViewVolume volume;
00201 volume.ortho(-1, 1, -1, 1, -1, 1);
00202 this->spinprojector->setViewVolume(volume);
00203
00204 this->log.size = 16;
00205 this->log.position = new SbVec2s [ 16 ];
00206 this->log.time = new SbTime [ 16 ];
00207 this->log.historysize = 0;
00208
00209 this->menuenabled = TRUE;
00210 this->button1down = FALSE;
00211 this->button2down = FALSE;
00212 this->button3down = FALSE;
00213 this->ctrldown = FALSE;
00214 this->shiftdown = FALSE;
00215 this->altdown = FALSE;
00216 this->invertZoom = App::GetApplication().GetParameterGroupByPath
00217 ("User parameter:BaseApp/Preferences/View")->GetBool("InvertZoom",false);
00218 }
00219
00220 void NavigationStyle::finalize()
00221 {
00222 delete this->spinprojector;
00223 delete[] this->log.position;
00224 delete[] this->log.time;
00225 }
00226
00227 void NavigationStyle::interactiveCountInc(void)
00228 {
00229 viewer->interactiveCountInc();
00230 }
00231
00232 void NavigationStyle::interactiveCountDec(void)
00233 {
00234 viewer->interactiveCountDec();
00235 }
00236
00237 int NavigationStyle::getInteractiveCount(void) const
00238 {
00239 return viewer->getInteractiveCount();
00240 }
00241
00242 void NavigationStyle::setOrbitStyle(NavigationStyle::OrbitStyle style)
00243 {
00244 FCSphereSheetProjector* projector = static_cast<FCSphereSheetProjector*>(this->spinprojector);
00245 projector->setOrbitStyle(FCSphereSheetProjector::OrbitStyle(style));
00246 }
00247
00248 NavigationStyle::OrbitStyle NavigationStyle::getOrbitStyle() const
00249 {
00250 FCSphereSheetProjector* projector = static_cast<FCSphereSheetProjector*>(this->spinprojector);
00251 return NavigationStyle::OrbitStyle(projector->getOrbitStyle());
00252 }
00253
00254 SbBool NavigationStyle::isViewing(void) const
00255 {
00256 return viewer->isViewing();
00257 }
00258
00259 void NavigationStyle::setViewing(SbBool enable)
00260 {
00261 viewer->setViewing(enable);
00262 }
00263
00264 SbBool NavigationStyle::isSeekMode(void) const
00265 {
00266 return viewer->isSeekMode();
00267 }
00268
00269 void NavigationStyle::setSeekMode(SbBool enable)
00270 {
00271 viewer->setSeekMode(enable);
00272 }
00273
00274 SbBool NavigationStyle::seekToPoint(const SbVec2s screenpos)
00275 {
00276 return viewer->seekToPoint(screenpos);
00277 }
00278
00279 void NavigationStyle::seekToPoint(const SbVec3f& scenepos)
00280 {
00281 viewer->seekToPoint(scenepos);
00282 }
00283
00284 SbBool NavigationStyle::lookAtPoint(const SbVec2s screenpos)
00285 {
00286 SoCamera* cam = viewer->getCamera();
00287 if (cam == 0) return FALSE;
00288
00289 SoRayPickAction rpaction(viewer->getViewportRegion());
00290 rpaction.setPoint(screenpos);
00291 rpaction.setRadius(2);
00292 rpaction.apply(viewer->getSceneManager()->getSceneGraph());
00293
00294 SoPickedPoint * picked = rpaction.getPickedPoint();
00295 if (!picked) {
00296 this->interactiveCountInc();
00297 return FALSE;
00298 }
00299
00300 SbVec3f hitpoint;
00301 hitpoint = picked->getPoint();
00302 lookAtPoint(hitpoint);
00303 return TRUE;
00304 }
00305
00306 void NavigationStyle::lookAtPoint(const SbVec3f& pos)
00307 {
00308 SoCamera* cam = viewer->getCamera();
00309 if (cam == 0) return;
00310
00311
00312 SbVec3f direction;
00313 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00314 PRIVATE(this)->focal1 = cam->position.getValue() +
00315 cam->focalDistance.getValue() * direction;
00316 PRIVATE(this)->focal2 = pos;
00317
00318
00319 if (this->isAnimating())
00320 this->stopAnimating();
00321
00322 if (PRIVATE(this)->animsensor->isScheduled()) {
00323 PRIVATE(this)->animsensor->unschedule();
00324 this->interactiveCountDec();
00325 }
00326
00327 if (isAnimationEnabled()) {
00328 SbRotation cam_rot = cam->orientation.getValue();
00329
00330 SbVec3f dir1 = direction, dir2;
00331 dir2 = pos - cam->position.getValue();
00332 dir2.normalize();
00333 SbRotation rot(dir1, dir2);
00334 float val = 0.5f*(1.0f + dir1.dot(dir2));
00335 int div = (int)(val * 20.0f);
00336 int steps = 20-div;
00337
00338
00339 if (steps > 0) {
00340 PRIVATE(this)->endRotation = cam_rot;
00341 this->spinRotation = cam_rot;
00342 PRIVATE(this)->animationsteps = 5;
00343 PRIVATE(this)->animationdelta = std::max<int>(100/steps, 5);
00344 PRIVATE(this)->animsensor->setBaseTime(SbTime::getTimeOfDay());
00345 PRIVATE(this)->animsensor->schedule();
00346 this->interactiveCountInc();
00347 }
00348 else {
00349
00350 SbVec3f direction;
00351 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00352 cam->position = pos - cam->focalDistance.getValue() * direction;
00353 }
00354 }
00355 else {
00356
00357 SbVec3f direction;
00358 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00359 cam->position = pos - cam->focalDistance.getValue() * direction;
00360 }
00361 }
00362
00363 void NavigationStyle::setCameraOrientation(const SbRotation& rot)
00364 {
00365 SoCamera* cam = viewer->getCamera();
00366 if (cam == 0) return;
00367
00368
00369 SbVec3f direction;
00370 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00371 PRIVATE(this)->focal1 = cam->position.getValue() +
00372 cam->focalDistance.getValue() * direction;
00373 PRIVATE(this)->focal2 = PRIVATE(this)->focal1;
00374 SoGetBoundingBoxAction action(viewer->getViewportRegion());
00375 action.apply(viewer->getSceneGraph());
00376 SbBox3f box = action.getBoundingBox();
00377 if (!box.isEmpty()) {
00378 rot.multVec(SbVec3f(0, 0, -1), direction);
00379
00380
00381
00382
00383 PRIVATE(this)->focal2 = box.getCenter();
00384 }
00385
00386
00387 if (this->isAnimating())
00388 this->stopAnimating();
00389
00390 if (PRIVATE(this)->animsensor->isScheduled()) {
00391 PRIVATE(this)->animsensor->unschedule();
00392 this->interactiveCountDec();
00393 }
00394
00395 if (isAnimationEnabled()) {
00396
00397 SbVec3f dir1, dir2;
00398 SbRotation cam_rot = cam->orientation.getValue();
00399 cam_rot.multVec(SbVec3f(0, 0, -1), dir1);
00400 rot.multVec(SbVec3f(0, 0, -1), dir2);
00401 float val = 0.5f*(1.0f + dir1.dot(dir2));
00402 int div = (int)(val * 20.0f);
00403 int steps = 20-div;
00404
00405
00406 if (steps > 0) {
00407 PRIVATE(this)->endRotation = rot;
00408 this->spinRotation = cam_rot;
00409 PRIVATE(this)->animationsteps = 5;
00410 PRIVATE(this)->animationdelta = std::max<int>(100/steps, 5);
00411 PRIVATE(this)->animsensor->setBaseTime(SbTime::getTimeOfDay());
00412 PRIVATE(this)->animsensor->schedule();
00413 this->interactiveCountInc();
00414 }
00415 else {
00416
00417
00418 cam->orientation.setValue(rot);
00419 }
00420 }
00421 else {
00422
00423 cam->orientation.setValue(rot);
00424 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00425 cam->position = PRIVATE(this)->focal2 - cam->focalDistance.getValue() * direction;
00426 }
00427 }
00428
00429 void NavigationStyleP::viewAnimationCB(void * data, SoSensor * sensor)
00430 {
00431 NavigationStyle* that = reinterpret_cast<NavigationStyle*>(data);
00432 if (PRIVATE(that)->animationsteps > 0) {
00433
00434
00435
00436
00437 float step = std::min<float>((float)PRIVATE(that)->animationsteps/100.0f, 1.0f);
00438 SbRotation slerp = SbRotation::slerp(that->spinRotation, PRIVATE(that)->endRotation, step);
00439 SbVec3f focalpoint = (1.0f-step)*PRIVATE(that)->focal1 + step*PRIVATE(that)->focal2;
00440 SoCamera* cam = that->viewer->getCamera();
00441 SbVec3f direction;
00442 cam->orientation.setValue(slerp);
00443 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00444 cam->position = focalpoint - cam->focalDistance.getValue() * direction;
00445
00446 PRIVATE(that)->animationsteps += PRIVATE(that)->animationdelta;
00447 if (PRIVATE(that)->animationsteps > 100) {
00448
00449 PRIVATE(that)->animationsteps=0;
00450 PRIVATE(that)->animsensor->unschedule();
00451 that->interactiveCountDec();
00452
00453 cam->orientation.setValue(PRIVATE(that)->endRotation);
00454 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00455 cam->position = PRIVATE(that)->focal2 - cam->focalDistance.getValue() * direction;
00456 }
00457 }
00458 }
00459
00460 void NavigationStyle::boxZoom(const SbBox2s& box)
00461 {
00462 SoCamera* cam = viewer->getCamera();
00463 if (!cam) return;
00464 const SbViewportRegion & vp = viewer->getViewportRegion();
00465 SbViewVolume vv = cam->getViewVolume(vp.getViewportAspectRatio());
00466
00467 short sizeX,sizeY;
00468 box.getSize(sizeX, sizeY);
00469 SbVec2s size = vp.getViewportSizePixels();
00470
00471
00472
00473 if (sizeX == 0 && sizeY == 0)
00474 return;
00475
00476
00477 short xmin,xmax,ymin,ymax;
00478 box.getBounds(xmin,ymin,xmax,ymax);
00479 const SbVec2f center((float) ((xmin+xmax)/2) / (float) SoQtMax((int)(size[0] - 1), 1),
00480 (float) (size[1]-(ymin+ymax)/2) / (float) SoQtMax((int)(size[1] - 1), 1));
00481
00482 SbPlane plane = vv.getPlane(cam->focalDistance.getValue());
00483 panCamera(cam,vp.getViewportAspectRatio(),plane, SbVec2f(0.5,0.5), center);
00484
00485
00486 float scaleX = (float)sizeX/(float)size[0];
00487 float scaleY = (float)sizeY/(float)size[1];
00488 float scale = std::max<float>(scaleX, scaleY);
00489 if (cam && cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
00490 float height = static_cast<SoOrthographicCamera*>(cam)->height.getValue() * scale;
00491 static_cast<SoOrthographicCamera*>(cam)->height = height;
00492 }
00493 else if (cam && cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
00494 float height = static_cast<SoPerspectiveCamera*>(cam)->heightAngle.getValue() / 2.0f;
00495 height = 2.0f * atan(tan(height) * scale);
00496 static_cast<SoPerspectiveCamera*>(cam)->heightAngle = height;
00497 }
00498 }
00499
00500 void NavigationStyle::viewAll()
00501 {
00502
00503 SoGetBoundingBoxAction action(viewer->getViewportRegion());
00504 action.apply(viewer->getSceneGraph());
00505 SbBox3f box = action.getBoundingBox();
00506 if (box.isEmpty()) return;
00507
00508 #if 0
00509
00510 float box_width, box_height, box_depth;
00511 box.getSize( box_width, box_height, box_depth );
00512 if (box_width < 5.0f*box_height && box_width < 5.0f*box_depth &&
00513 box_height < 5.0f*box_width && box_height < 5.0f*box_depth &&
00514 box_depth < 5.0f*box_width && box_depth < 5.0f*box_height )
00515 return;
00516 #endif
00517
00518 SoCamera* cam = viewer->getCamera();
00519 if (!cam) return;
00520
00521 SbViewVolume vol = cam->getViewVolume();
00522 if (vol.ulf == vol.llf)
00523 return;
00524 SbVec2f s = vol.projectBox(box);
00525 SbVec2s size = viewer->getSize();
00526
00527 SbVec3f pt1, pt2, pt3, tmp;
00528 vol.projectPointToLine( SbVec2f(0.0f,0.0f), pt1, tmp );
00529 vol.projectPointToLine( SbVec2f(s[0],0.0f), pt2, tmp );
00530 vol.projectPointToLine( SbVec2f(0.0f,s[1]), pt3, tmp );
00531
00532 float cam_width = (pt2-pt1).length();
00533 float cam_height = (pt3-pt1).length();
00534
00535
00536 cam_height = 1.08f * std::max<float>((cam_width*(float)size[1])/(float)size[0],cam_height);
00537
00538 float aspect = cam->aspectRatio.getValue();
00539
00540 if (cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 }
00556 else if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
00557 SoOrthographicCamera* ocam = (SoOrthographicCamera *)cam;
00558 if (aspect < 1.0f)
00559 ocam->height = cam_height / aspect;
00560 else
00561 ocam->height = cam_height;
00562 }
00563 }
00564
00568 void NavigationStyle::reorientCamera(SoCamera * cam, const SbRotation & rot)
00569 {
00570 if (cam == NULL) return;
00571
00572
00573 SbVec3f direction;
00574 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00575 SbVec3f focalpoint = cam->position.getValue() +
00576 cam->focalDistance.getValue() * direction;
00577
00578
00579 cam->orientation = rot * cam->orientation.getValue();
00580
00581
00582 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00583 cam->position = focalpoint - cam->focalDistance.getValue() * direction;
00584 }
00585
00586 void NavigationStyle::panCamera(SoCamera * cam, float aspectratio, const SbPlane & panplane,
00587 const SbVec2f & currpos, const SbVec2f & prevpos)
00588 {
00589 if (cam == NULL) return;
00590 if (currpos == prevpos) return;
00591
00592
00593
00594 SbViewVolume vv = cam->getViewVolume(aspectratio);
00595 SbLine line;
00596 vv.projectPointToLine(currpos, line);
00597 SbVec3f current_planept;
00598 panplane.intersect(line, current_planept);
00599 vv.projectPointToLine(prevpos, line);
00600 SbVec3f old_planept;
00601 panplane.intersect(line, old_planept);
00602
00603
00604
00605 cam->position = cam->position.getValue() - (current_planept - old_planept);
00606 }
00607
00608 void NavigationStyle::pan(SoCamera* camera)
00609 {
00610
00611
00612
00613 if (camera == NULL) {
00614 this->panningplane = SbPlane(SbVec3f(0, 0, 1), 0);
00615 }
00616 else {
00617 const SbViewportRegion & vp = viewer->getViewportRegion();
00618 SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio());
00619 this->panningplane = vv.getPlane(camera->focalDistance.getValue());
00620 }
00621 }
00622
00623 void NavigationStyle::panToCenter(const SbPlane & pplane, const SbVec2f & currpos)
00624 {
00625 const SbViewportRegion & vp = viewer->getViewportRegion();
00626 float ratio = vp.getViewportAspectRatio();
00627 panCamera(viewer->getCamera(), ratio, pplane, SbVec2f(0.5,0.5), currpos);
00628 }
00629
00634 void NavigationStyle::zoom(SoCamera * cam, float diffvalue)
00635 {
00636 if (cam == NULL) return;
00637 SoType t = cam->getTypeId();
00638 SbName tname = t.getName();
00639
00640
00641 float multiplicator = float(exp(diffvalue));
00642
00643 if (t.isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
00644
00645
00646
00647
00648
00649 SoOrthographicCamera * oc = (SoOrthographicCamera *)cam;
00650 oc->height = oc->height.getValue() * multiplicator;
00651
00652 }
00653 else {
00654
00655
00656
00657 if (!t.isDerivedFrom(SoPerspectiveCamera::getClassTypeId()) &&
00658 tname != "FrustumCamera") {
00659
00660
00661
00662
00663
00664
00665
00666 }
00667
00668 const float oldfocaldist = cam->focalDistance.getValue();
00669 const float newfocaldist = oldfocaldist * multiplicator;
00670
00671 SbVec3f direction;
00672 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00673
00674 const SbVec3f oldpos = cam->position.getValue();
00675 const SbVec3f newpos = oldpos + (newfocaldist - oldfocaldist) * -direction;
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691 const float distorigo = newpos.length();
00692
00693
00694 if (distorigo > float(sqrt(FLT_MAX))) {
00695 }
00696 else {
00697 cam->position = newpos;
00698 cam->focalDistance = newfocaldist;
00699 }
00700 }
00701 }
00702
00703
00704
00705 void NavigationStyle::zoomByCursor(const SbVec2f & thispos, const SbVec2f & prevpos)
00706 {
00707
00708
00709 zoom(viewer->getCamera(), (thispos[1] - prevpos[1]) * 10.0f);
00710 }
00711
00715 void NavigationStyle::spin(const SbVec2f & pointerpos)
00716 {
00717 if (this->log.historysize < 2) return;
00718 assert(this->spinprojector != NULL);
00719
00720 const SbViewportRegion & vp = viewer->getViewportRegion();
00721 SbVec2s glsize(vp.getViewportSizePixels());
00722 SbVec2f lastpos;
00723 lastpos[0] = float(this->log.position[1][0]) / float(SoQtMax((int)(glsize[0]-1), 1));
00724 lastpos[1] = float(this->log.position[1][1]) / float(SoQtMax((int)(glsize[1]-1), 1));
00725
00726
00727 SbMatrix mat;
00728 viewer->getCamera()->orientation.getValue().getValue(mat);
00729 this->spinprojector->setWorkingSpace(mat);
00730
00731 this->spinprojector->project(lastpos);
00732 SbRotation r;
00733 this->spinprojector->projectAndGetRotation(pointerpos, r);
00734 r.invert();
00735 this->reorientCamera(viewer->getCamera(), r);
00736
00737
00738
00739
00740 SbVec3f dummy_axis, newaxis;
00741 float acc_angle, newangle;
00742 this->spinincrement.getValue(dummy_axis, acc_angle);
00743 acc_angle *= this->spinsamplecounter;
00744 r.getValue(newaxis, newangle);
00745 acc_angle += newangle;
00746
00747 this->spinsamplecounter++;
00748 acc_angle /= this->spinsamplecounter;
00749
00750 this->spinincrement.setValue(newaxis, acc_angle);
00751
00752
00753
00754
00755 if (this->spinsamplecounter > 3) this->spinsamplecounter = 3;
00756 }
00757
00758 SbBool NavigationStyle::doSpin()
00759 {
00760 if (this->log.historysize >= 3) {
00761 SbTime stoptime = (SbTime::getTimeOfDay() - this->log.time[0]);
00762 if (this->spinanimatingallowed && stoptime.getValue() < 0.100) {
00763 const SbViewportRegion & vp = viewer->getViewportRegion();
00764 const SbVec2s glsize(vp.getViewportSizePixels());
00765 SbVec3f from = this->spinprojector->project(SbVec2f(float(this->log.position[2][0]) / float(SoQtMax(glsize[0]-1, 1)),
00766 float(this->log.position[2][1]) / float(SoQtMax(glsize[1]-1, 1))));
00767 SbVec3f to = this->spinprojector->project(this->lastmouseposition);
00768 SbRotation rot = this->spinprojector->getRotation(from, to);
00769
00770 SbTime delta = (this->log.time[0] - this->log.time[2]);
00771 double deltatime = delta.getValue();
00772 rot.invert();
00773 rot.scaleAngle(float(0.200 / deltatime));
00774
00775 SbVec3f axis;
00776 float radians;
00777 rot.getValue(axis, radians);
00778 if ((radians > 0.01f) && (deltatime < 0.300)) {
00779 this->spinRotation = rot;
00780 return TRUE;
00781 }
00782 }
00783 }
00784
00785 return FALSE;
00786 }
00787
00788 void NavigationStyle::updateAnimation()
00789 {
00790 SbTime now = SbTime::getTimeOfDay();
00791 double secs = now.getValue() - prevRedrawTime.getValue();
00792 this->prevRedrawTime = now;
00793
00794 if (this->isAnimating()) {
00795
00796 SbRotation deltaRotation = this->spinRotation;
00797 deltaRotation.scaleAngle(secs * 5.0);
00798 this->reorientCamera(viewer->getCamera(), deltaRotation);
00799 }
00800 }
00801
00802 void NavigationStyle::redraw()
00803 {
00804 if (mouseSelection)
00805 mouseSelection->redraw();
00806 }
00807
00808 SbBool NavigationStyle::handleEventInForeground(const SoEvent* const e)
00809 {
00810 SoHandleEventAction action(viewer->getViewportRegion());
00811 action.setEvent(e);
00812 action.apply(viewer->foregroundroot);
00813 return action.isHandled();
00814 }
00815
00823 void
00824 NavigationStyle::setAnimationEnabled(const SbBool enable)
00825 {
00826 this->spinanimatingallowed = enable;
00827 if (!enable && this->isAnimating()) { this->stopAnimating(); }
00828 }
00829
00835 SbBool
00836 NavigationStyle::isAnimationEnabled(void) const
00837 {
00838 return this->spinanimatingallowed;
00839 }
00840
00845 SbBool NavigationStyle::isAnimating(void) const
00846 {
00847 return this->currentmode == NavigationStyle::SPINNING;
00848 }
00849
00854 void NavigationStyle::startAnimating(const SbVec3f& axis, float velocity)
00855 {
00856 if (!isAnimationEnabled()) return;
00857
00858 this->prevRedrawTime = SbTime::getTimeOfDay();
00859 this->spinincrement = SbRotation::identity();
00860 SbRotation rot;
00861 rot.setValue(axis, velocity);
00862
00863 this->setViewing(true);
00864 this->setViewingMode(NavigationStyle::SPINNING);
00865 this->spinRotation = rot;
00866 }
00867
00868 void NavigationStyle::stopAnimating(void)
00869 {
00870 if (this->currentmode != NavigationStyle::SPINNING) {
00871 return;
00872 }
00873 this->setViewingMode(this->isViewing() ?
00874 NavigationStyle::IDLE : NavigationStyle::INTERACT);
00875 }
00876
00877 void NavigationStyle::setZoomInverted(SbBool on)
00878 {
00879 this->invertZoom = on;
00880 }
00881
00882 SbBool NavigationStyle::isZoomInverted() const
00883 {
00884 return this->invertZoom;
00885 }
00886
00887 void NavigationStyle::startSelection(AbstractMouseSelection* mouse)
00888 {
00889 if (!mouse)
00890 return;
00891
00892 mouseSelection = mouse;
00893 mouseSelection->grabMouseModel(viewer);
00894 }
00895
00896 void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode)
00897 {
00898 if (mouseSelection)
00899 return;
00900 if (isSelecting())
00901 stopSelection();
00902
00903 switch (mode)
00904 {
00905 case Lasso:
00906 mouseSelection = new PolyPickerSelection();
00907 break;
00908 case Rectangle:
00909 mouseSelection = new RectangleSelection();
00910 break;
00911 case BoxZoom:
00912 mouseSelection = new BoxZoomSelection();
00913 break;
00914 case Clip:
00915 mouseSelection = new PolyClipSelection();
00916 break;
00917 default:
00918 break;
00919 }
00920
00921 if (mouseSelection)
00922 mouseSelection->grabMouseModel(viewer);
00923 }
00924
00925 void NavigationStyle::stopSelection()
00926 {
00927 pcPolygon.clear();
00928 delete mouseSelection;
00929 mouseSelection = 0;
00930 }
00931
00932 SbBool NavigationStyle::isSelecting() const
00933 {
00934 return (mouseSelection ? TRUE : FALSE);
00935 }
00936
00937 const std::vector<SbVec2s>& NavigationStyle::getPolygon(SbBool* clip_inner) const
00938 {
00939 if (clip_inner)
00940 *clip_inner = this->clipInner;
00941 return pcPolygon;
00942 }
00943
00944
00945
00946 void NavigationStyle::addToLog(const SbVec2s pos, const SbTime time)
00947 {
00948
00949
00950 assert (this->log.size > 2 && "mouse log too small!");
00951
00952 if (this->log.historysize > 0 && pos == this->log.position[0]) {
00953 #if SOQt_DEBUG && 0 // debug
00954
00955 SoDebugError::postInfo("NavigationStyle::addToLog", "got position already!");
00956 #endif // debug
00957 return;
00958 }
00959
00960 int lastidx = this->log.historysize;
00961
00962 if (lastidx == this->log.size) { lastidx--; }
00963
00964 assert(lastidx < this->log.size);
00965 for (int i = lastidx; i > 0; i--) {
00966 this->log.position[i] = this->log.position[i-1];
00967 this->log.time[i] = this->log.time[i-1];
00968 }
00969
00970 this->log.position[0] = pos;
00971 this->log.time[0] = time;
00972 if (this->log.historysize < this->log.size)
00973 this->log.historysize += 1;
00974 }
00975
00976
00977
00978 void NavigationStyle::clearLog(void)
00979 {
00980 this->log.historysize = 0;
00981 }
00982
00983
00984
00985 void NavigationStyle::setViewingMode(const ViewerMode newmode)
00986 {
00987 const ViewerMode oldmode = this->currentmode;
00988 if (newmode == oldmode) { return; }
00989
00990 switch (newmode) {
00991 case DRAGGING:
00992
00993
00994 this->spinprojector->project(this->lastmouseposition);
00995 this->interactiveCountInc();
00996 this->clearLog();
00997 break;
00998
00999 case SPINNING:
01000 this->interactiveCountInc();
01001 viewer->scheduleRedraw();
01002 break;
01003
01004 case PANNING:
01005 pan(viewer->getCamera());
01006 this->interactiveCountInc();
01007 break;
01008
01009 case ZOOMING:
01010 this->interactiveCountInc();
01011 break;
01012
01013 case BOXZOOM:
01014 this->interactiveCountInc();
01015 break;
01016
01017 default:
01018 break;
01019 }
01020
01021 switch (oldmode) {
01022 case SPINNING:
01023 case DRAGGING:
01024 case PANNING:
01025 case ZOOMING:
01026 case BOXZOOM:
01027 this->interactiveCountDec();
01028 break;
01029
01030 default:
01031 break;
01032 }
01033
01034 viewer->setCursorRepresentation(newmode);
01035 this->currentmode = newmode;
01036 }
01037
01038 int NavigationStyle::getViewingMode() const
01039 {
01040 return (int)this->currentmode;
01041 }
01042
01043 SbBool NavigationStyle::processEvent(const SoEvent * const ev)
01044 {
01045
01046
01047 if (mouseSelection) {
01048 int hd=mouseSelection->handleEvent(ev,viewer->getViewportRegion());
01049 if (hd==AbstractMouseSelection::Continue||
01050 hd==AbstractMouseSelection::Restart) {
01051 return TRUE;
01052 }
01053 else if (hd==AbstractMouseSelection::Finish) {
01054 pcPolygon = mouseSelection->getPositions();
01055 clipInner = mouseSelection->isInner();
01056 delete mouseSelection; mouseSelection = 0;
01057 return NavigationStyle::processSoEvent(ev);
01058 }
01059 else if (hd==AbstractMouseSelection::Cancel) {
01060 pcPolygon.clear();
01061 delete mouseSelection; mouseSelection = 0;
01062 return NavigationStyle::processSoEvent(ev);
01063 }
01064 }
01065
01066 const ViewerMode curmode = this->currentmode;
01067
01068 SbBool processed = FALSE;
01069 processed = this->processSoEvent(ev);
01070
01071
01072 if (curmode == NavigationStyle::SELECTION && !processed) {
01073 if (ev->getTypeId().isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
01074 SoMouseButtonEvent * const e = (SoMouseButtonEvent *) ev;
01075 if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
01076 Gui::Selection().clearSelection();
01077 }
01078 }
01079 }
01080
01081 return processed;
01082 }
01083
01084 SbBool NavigationStyle::processSoEvent(const SoEvent * const ev)
01085 {
01086 return viewer->processSoEventBase(ev);
01087 }
01088
01089 void NavigationStyle::setPopupMenuEnabled(const SbBool on)
01090 {
01091 this->menuenabled = on;
01092 }
01093
01094 SbBool NavigationStyle::isPopupMenuEnabled(void) const
01095 {
01096 return this->menuenabled;
01097 }
01098
01099 void NavigationStyle::openPopupMenu(const SbVec2s& position)
01100 {
01101
01102 MenuItem* view = new MenuItem;
01103 Gui::Application::Instance->setupContextMenu("View", view);
01104
01105 QMenu contextMenu(viewer->getGLWidget());
01106 QMenu subMenu;
01107 QActionGroup subMenuGroup(&subMenu);
01108 subMenuGroup.setExclusive(true);
01109 subMenu.setTitle(QObject::tr("Navigation styles"));
01110
01111 MenuManager::getInstance()->setupContextMenu(view, contextMenu);
01112 contextMenu.addMenu(&subMenu);
01113
01114
01115 QRegExp rx(QString::fromAscii("^\\w+::(\\w+)Navigation\\w+$"));
01116 std::vector<Base::Type> types;
01117 Base::Type::getAllDerivedFrom(UserNavigationStyle::getClassTypeId(), types);
01118 for (std::vector<Base::Type>::iterator it = types.begin(); it != types.end(); ++it) {
01119 if (*it != UserNavigationStyle::getClassTypeId()) {
01120 QString data = QString::fromAscii(it->getName());
01121 QString name = data.mid(data.indexOf(QLatin1String("::"))+2);
01122 if (rx.indexIn(data) > -1) {
01123 name = QObject::tr("%1 navigation").arg(rx.cap(1));
01124 QAction* item = subMenuGroup.addAction(name);
01125 item->setData(QByteArray(it->getName()));
01126 item->setCheckable(true);
01127 if (*it == this->getTypeId())
01128 item->setChecked(true);
01129 subMenu.addAction(item);
01130 }
01131 }
01132 }
01133
01134 delete view;
01135 QAction* used = contextMenu.exec(QCursor::pos());
01136 if (used && subMenuGroup.actions().indexOf(used) >= 0 && used->isChecked()) {
01137 QByteArray type = used->data().toByteArray();
01138 QWidget* widget = viewer->getWidget();
01139 while (widget && !widget->inherits("Gui::View3DInventor"))
01140 widget = widget->parentWidget();
01141 if (widget) {
01142
01143 Base::Type style = Base::Type::fromName((const char*)type);
01144 if (style != this->getTypeId()) {
01145 QEvent* event = new NavigationStyleEvent(style);
01146 QApplication::postEvent(widget, event);
01147 }
01148 }
01149 }
01150 }
01151
01152
01153
01154 TYPESYSTEM_SOURCE_ABSTRACT(Gui::UserNavigationStyle,Gui::NavigationStyle);