1
/**************************************************************************\
3
* This file is part of the Coin 3D visualization library.
4
* Copyright (C) 1998-2005 by Systems in Motion. All rights reserved.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* ("GPL") version 2 as published by the Free Software Foundation.
9
* See the file LICENSE.GPL at the root directory of this source
10
* distribution for additional information about the GNU GPL.
12
* For using Coin with software that can not be combined with the GNU
13
* GPL, and for taking advantage of the additional benefits of our
14
* support services, please contact Systems in Motion about acquiring
15
* a Coin Professional Edition License.
17
* See <URL:http://www.coin3d.org/> for more information.
19
* Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY.
20
* <URL:http://www.sim.no/>.
22
\**************************************************************************/
24
// src/Inventor/Qt/viewers/SoQtFlyViewer.cpp. Generated from SoGuiFlyViewer.cpp.in by configure.
27
\class SoQtFlyViewer Inventor/Qt/viewers/SoQtFlyViewer.h
28
\brief The SoQtFlyViewer class implements controls for moving
29
the camera in a "flying" motion.
35
<li>Left mouse button increases the speed.</li>
37
<li>Middle mouse button decreases the speed.</li>
39
<li>Left and middle mouse button together sets the speed to zero.</li>
41
<li>"s" puts the viewer in seek mode. Click some geometry with the
42
left mouse button to start the seek zoom animation. (Hitting "s"
43
again before clicking will cancel the seek operation.)</li>
45
<li>"u" puts the viewer in up-vector pick mode. Click some geometry
46
with the left mouse button to set the camera's up-vector to the
47
normal vector of the face you pick.
48
(Hitting "u" again before clicking will cancel the pick operation.)</li>
50
<li>The control key stops the flying and lets you tilt the camera by moving
58
- animate camera when setting up-vector so the scene doesn't just
63
#include <Inventor/Qt/viewers/SoQtFlyViewer.h>
64
#include <Inventor/events/SoKeyboardEvent.h>
65
#include <Inventor/events/SoLocation2Event.h>
66
#include <Inventor/events/SoMouseButtonEvent.h>
67
#include <Inventor/nodes/SoCamera.h>
68
#include <Inventor/nodes/SoCallback.h>
69
#include <Inventor/nodes/SoCoordinate3.h>
70
#include <Inventor/nodes/SoSwitch.h>
71
#include <Inventor/nodes/SoScale.h>
72
#include <Inventor/nodes/SoTranslation.h>
73
#include <Inventor/errors/SoDebugError.h>
74
#include <Inventor/actions/SoSearchAction.h>
75
#include <Inventor/actions/SoHandleEventAction.h>
76
#include <Inventor/actions/SoGetBoundingBoxAction.h>
77
#include <string.h> // strlen() etc
78
#include <stdlib.h> // abs()
79
#include <Inventor/Qt/SoQtCursor.h>
82
// ************************************************************************
84
#ifndef DOXYGEN_SKIP_THIS
86
// FIXME: We should probably move this class out of this
87
// impl-file. There is code here that could be factored out and reused
88
// in other modules, for example camera handling. Now there is a
89
// duplication with some of the code in SoQtConstrainedViewerP, for
90
// example. 20021017 rolvs
91
class SoQtFlyViewerP {
93
SoQtFlyViewerP(SoQtFlyViewer * owner);
97
FLYING, TILTING, WAITING_FOR_SEEK, WAITING_FOR_UP_PICK
100
void constructor(SbBool build);
102
void dolly(const float delta) const;
103
void updateCursorRepresentation(void); // in SoNativeFlyViewer.cpp
104
void setMode(ViewerMode newmode);
105
int getMode(void) { return this->viewermode; }
107
#define SOQT_MIN_STEP 0.2f
108
#define SOQT_INC_FACTOR 1.2f
109
#define SOQT_MAX_SPEED 20.0f
115
// Maximum speed, target for currentspeed during
116
// acceleration/decceleration.
119
// Scales speed. Calculated in updateSpeedScalingFactor.
120
float speed_scaling_factor;
122
// Used to calculate a new max_speed, on the basis on 'where' we are
123
// in the speed landscape, see {increment|decrement}MaxSpeed().
124
int max_speed_factor;
127
void incrementMaxSpeed();
128
void decrementMaxSpeed();
129
void updateMaxSpeed();
130
void updateSpeedScalingFactor();
133
void updateSpeedIndicator(void);
134
void updateCameraPosition( SoCamera * camera, float speed, float dt );
135
void updateCameraOrientation( SoCamera * camera,
139
float calculateChangeInTime();
140
void updateCurrentSpeed( float dt );
143
// Current keyboard state.
151
// View, speed display, renderingstate.
152
SoSearchAction * searcher;
154
SoNode * superimposition;
155
SoCoordinate3 * sgeometry;
158
SoScale * crossscale;
160
SoTranslation * stranslation;
161
SoTranslation * crossposition;
163
SoSwitch * smaxspeedswitch;
164
SoSwitch * scurrentspeedswitch;
165
SoSwitch * crossswitch;
167
SoNode * getSuperimpositionNode(const char * name);
169
void superimpositionevent(SoAction * action);
170
static void superimposition_cb(void * closure, SoAction * action);
174
float tilt_increment; // Angle-adjustment between View-up and direction
175
float pan_increment; // Rotation-adjustment around View-up
181
// FIXME: Refactor event handlers and PUBLIC(this)->processSoEvent
182
// in a way similar to that in SoGuiExaminerViewer, where only
183
// internal state is red/set. 20021017 rolvs
184
SbBool processKeyboardEvent( const SoKeyboardEvent * const kevt );
185
SbBool processMouseButtonEvent( const SoMouseButtonEvent * const mevt );
186
SbBool processLocation2Event( const SoLocation2Event * const levt );
188
SoQtFlyViewer * publ;
189
ViewerMode viewermode;
192
SoQtFlyViewerP::SoQtFlyViewerP( SoQtFlyViewer * owner )
194
this->searcher = NULL;
196
this->viewermode = FLYING;
197
this->currentspeed = 0.0f;
198
this->maxspeed = 0.0f;
199
this->speed_scaling_factor = 0.4f;
200
this->max_speed_factor = 0;
201
this->stranslation = NULL;
203
this->button1down = FALSE;
204
this->button3down = FALSE;
207
this->lshiftdown = FALSE;
208
this->rshiftdown = FALSE;
209
this->lastrender = new SbTime;
210
this->tilt_increment = 0;
211
this->pan_increment = 0;
214
SoQtFlyViewerP::~SoQtFlyViewerP(void)
216
if ( this->searcher != NULL )
217
delete this->searcher;
218
delete this->lastrender;
220
// superimposition unrefed in other destructor
223
#define PRIVATE(o) (o->pimpl)
224
#define PUBLIC(o) (o->publ)
227
// Common constructor code.
229
SoQtFlyViewerP::constructor(SbBool build)
231
PUBLIC(this)->setClassName(PUBLIC(this)->getDefaultWidgetName());
233
static const char * superimposed[] = {
234
"#Inventor V2.1 ascii",
237
" MaterialBinding {",
240
" OrthographicCamera {",
245
" DEF soqt->callback Callback { }",
247
" DEF soqt->translation Translation {",
248
" translation 0 0 0",
250
" DEF soqt->scale Scale {",
251
" scaleFactor 1 1 1",
253
" DEF soqt->geometry Coordinate3 {",
264
" 0 0.02 0,", // idx 9
268
" 0 0.01 0,", // idx 13
274
" DEF soqt->maxspeedswitch Switch {",
276
// max speed indicator
278
" emissiveColor 1 0 0",
282
" 12, 11, 10, 9, -1",
286
// the coordinate system
298
// current speed indicator
299
" DEF soqt->currentspeedswitch Switch {",
302
" emissiveColor 0 0 1",
306
" 16, 15, 14, 13, -1",
312
" DEF soqt->crossswitch Switch {",
314
" DEF soqt->crossposition Translation {",
315
" translation 0 0 0",
317
" DEF soqt->crossscale Scale {",
318
" scaleFactor 1 1 1",
343
for (i = bufsize = 0; superimposed[i]; i++)
344
bufsize += strlen(superimposed[i]) + 1;
345
char * buf = new char [bufsize + 1];
346
for (i = bufsize = 0; superimposed[i]; i++) {
347
strcpy(buf + bufsize, superimposed[i]);
348
bufsize += strlen(superimposed[i]);
352
SoInput * input = new SoInput;
353
input->setBuffer(buf, bufsize);
354
SbBool ok = SoDB::read(input, this->superimposition);
358
this->superimposition->ref();
361
this->sscale = (SoScale *)
362
this->getSuperimpositionNode("soqt->scale");
363
this->stranslation = (SoTranslation *)
364
this->getSuperimpositionNode("soqt->translation");
365
this->sgeometry = (SoCoordinate3 *)
366
this->getSuperimpositionNode("soqt->geometry");
367
this->smaxspeedswitch = (SoSwitch *)
368
this->getSuperimpositionNode("soqt->maxspeedswitch");
369
this->scurrentspeedswitch = (SoSwitch *)
370
this->getSuperimpositionNode("soqt->currentspeedswitch");
371
this->crossswitch = (SoSwitch *)
372
this->getSuperimpositionNode("soqt->crossswitch");
373
this->crossposition = (SoTranslation *)
374
this->getSuperimpositionNode("soqt->crossposition");
375
this->crossscale = (SoScale *)
376
this->getSuperimpositionNode("soqt->crossscale");
378
SoCallback * cb = (SoCallback *)
379
this->getSuperimpositionNode("soqt->callback");
380
cb->setCallback(SoQtFlyViewerP::superimposition_cb, this);
382
this->updateSpeedIndicator();
384
PUBLIC(this)->addSuperimposition(this->superimposition);
385
PUBLIC(this)->setSuperimpositionEnabled(this->superimposition,TRUE);
388
QWidget * viewer = PUBLIC(this)->buildWidget(PUBLIC(this)->getParentWidget());
389
PUBLIC(this)->setBaseWidget(viewer);
393
// This method dollies the camera back and forth in the scene.
395
SoQtFlyViewerP::dolly(const float delta) const
397
SoCamera * const camera = PUBLIC(this)->getCamera();
398
if (camera == NULL) { return; } // if there's no scenegraph, for instance
400
SbPlane walkplane(PUBLIC(this)->getUpDirection(),
401
camera->position.getValue());
403
SbVec3f campos = camera->position.getValue();
405
camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), camvec);
406
SbLine cross(campos + camvec,
407
campos + camvec + PUBLIC(this)->getUpDirection());
409
walkplane.intersect(cross, intersect);
410
SbVec3f dir = intersect - campos;
413
camera->position = campos - dir * delta;
416
// The viewer is a state machine, and all changes to the current state
417
// are made through this call.
419
SoQtFlyViewerP::setMode(ViewerMode newmode)
421
this->viewermode = newmode;
422
this->updateCursorRepresentation();
425
// This method locates a named node in the superimposed scene.
427
SoQtFlyViewerP::getSuperimpositionNode(const char * name)
429
if (! this->searcher)
430
this->searcher = new SoSearchAction;
432
searcher->setName(SbName(name));
433
searcher->setInterest(SoSearchAction::FIRST);
434
searcher->setSearchingAll(TRUE);
435
searcher->apply(this->superimposition);
436
assert(searcher->getPath());
437
return searcher->getPath()->getTail();
441
SoQtFlyViewerP::processKeyboardEvent( const SoKeyboardEvent * const ke )
443
assert( ke != NULL );
444
switch (ke->getState()) {
445
case SoButtonEvent::UP:
446
switch (ke->getKey()) {
447
case SoKeyboardEvent::U:
449
// either to switch to up-vector pick mode, or back to fly
450
// mode if pick-mode already activated (ie cancel the
451
// up-vector pick operation)
453
this->getMode() == SoQtFlyViewerP::WAITING_FOR_UP_PICK;
454
this->setMode(uppickmode ? SoQtFlyViewerP::FLYING :
455
SoQtFlyViewerP::WAITING_FOR_UP_PICK);
459
this->updateSpeedIndicator();
460
PUBLIC(this)->scheduleRedraw();
465
case SoKeyboardEvent::S:
467
this->updateSpeedIndicator();
468
PUBLIC(this)->scheduleRedraw();
471
case SoKeyboardEvent::LEFT_SHIFT:
472
this->lshiftdown = FALSE;
473
if (this->lshiftdown < 0) {
475
SoDebugError::post("SoQtFlyViewerP::processKeyboardEvent",
476
"left shift key count < 0");
478
this->lshiftdown = 0;
481
case SoKeyboardEvent::RIGHT_SHIFT:
482
this->rshiftdown = FALSE;
483
if (this->rshiftdown < 0) {
485
SoDebugError::post("SoQtFlyViewerP::processKeyboardEvent",
486
"right shift key count < 0");
488
this->rshiftdown = 0;
491
case SoKeyboardEvent::LEFT_CONTROL:
492
this->lctrldown -= 1;
493
if (this->lctrldown < 0) {
495
SoDebugError::post("SoQtFlyViewerP::processKyeboardEvent",
496
"left control key count < 0");
501
case SoKeyboardEvent::RIGHT_CONTROL:
502
this->rctrldown -= 1;
503
if (this->rctrldown < 0) {
505
SoDebugError::post("SoQtFlyViewerP::processKyeboardEvent",
506
"right control key count < 0");
515
case SoButtonEvent::DOWN:
516
switch (ke->getKey()) {
517
case SoKeyboardEvent::LEFT_SHIFT:
518
this->lshiftdown += 1;
519
if (this->lshiftdown > 2) {
521
SoDebugError::post("SoQtFlyViewerP::processKeyboardEvent",
522
"left shift key count > 2");
524
this->lshiftdown = 2;
527
case SoKeyboardEvent::RIGHT_SHIFT:
528
this->rshiftdown += 1;
529
if (this->rshiftdown > 2) {
531
SoDebugError::post("SoQtFlyViewerP::processKeyboardEvent",
532
"right shift key count > 2");
534
this->rshiftdown = 2;
537
case SoKeyboardEvent::LEFT_CONTROL:
538
this->lctrldown += 1;
539
if (this->lctrldown > 2) {
541
SoDebugError::post("SoQtFlyViewerP::processKeyboardEvent",
542
"left control key count > 2");
547
case SoKeyboardEvent::RIGHT_CONTROL:
548
this->rctrldown += 1;
549
if (this->rctrldown > 2) {
551
SoDebugError::post("SoQtFlyViewer::processSoEvent",
552
"right control key count > 2");
565
if ((this->getMode() == SoQtFlyViewerP::FLYING) &&
566
(this->lctrldown || this->rctrldown)) {
567
this->setMode(SoQtFlyViewerP::TILTING);
569
this->tiltpos = this->mouseloc;
570
this->lastpos = this->mouseloc;
573
this->updateSpeedIndicator();
574
this->crossswitch->whichChild.setValue(SO_SWITCH_ALL);
575
PUBLIC(this)->scheduleRedraw();
576
// NOTE; this could be optimized to only draw the superimposition in
577
// question if speed is zero.
578
} else if ((this->getMode() == SoQtFlyViewerP::TILTING) &&
579
!this->lctrldown && !this->rctrldown) {
580
this->setMode(SoQtFlyViewerP::FLYING);
581
assert(this->crossswitch != NULL);
582
this->crossswitch->whichChild.setValue(SO_SWITCH_NONE);
583
PUBLIC(this)->scheduleRedraw();
590
SoQtFlyViewerP::processMouseButtonEvent( const SoMouseButtonEvent * const me )
592
assert( me != NULL );
594
// FIXME: only for fly mode
595
switch (this->getMode()) {
596
case SoQtFlyViewerP::WAITING_FOR_UP_PICK:
597
if ((me->getButton() == SoMouseButtonEvent::BUTTON1) &&
598
(me->getState() == SoButtonEvent::DOWN)) {
599
PUBLIC(this)->findUpDirection(me->getPosition());
600
this->setMode(SoQtFlyViewerP::FLYING);
604
case SoQtFlyViewerP::FLYING:
605
switch (me->getButton()) {
606
case SoMouseButtonEvent::BUTTON1:
608
switch (me->getState()) {
610
case SoButtonEvent::DOWN:
611
// Incrementing speed.
612
this->button1down = TRUE;
613
if (this->button3down) {
617
this->incrementMaxSpeed();
619
this->updateSpeedIndicator();
620
PUBLIC(this)->scheduleRedraw();
622
case SoButtonEvent::UP:
623
this->button1down = FALSE;
630
case SoMouseButtonEvent::BUTTON3:
632
switch (me->getState()) {
633
case SoButtonEvent::DOWN:
634
this->button3down = TRUE;
636
if (this->button1down) {
640
this->decrementMaxSpeed();
642
this->updateSpeedIndicator();
643
PUBLIC(this)->scheduleRedraw();
645
case SoButtonEvent::UP:
646
this->button3down = FALSE;
662
SoQtFlyViewerP::processLocation2Event( const SoLocation2Event * const lev )
664
this->mouseloc = lev->getPosition();
666
if (this->getMode() == SoQtFlyViewerP::TILTING) {
668
float pan = (this->lastpos[0] - this->mouseloc[0])/100.0f;
669
float tilt = (this->lastpos[1] - this->mouseloc[1])/100.0f;
671
SoCamera * camera = PUBLIC(this)->getCamera();
673
return TRUE; // probably sceneless
675
this->updateCameraOrientation( camera, tilt, pan, 1.0f );
676
this->lastpos = this->mouseloc;
679
// FIXME: The size of the glcanvas only changes when the viewer is
680
// resized. The GLSize should be set from the FlyViewer, to remove
681
// the dependency on the PUBLIC(this) class. 20021021 rolvs
682
SbVec2s glsize( PUBLIC(this)->getGLSize() );
684
// NOTE: The values are normalized, so that the FlyViewer behaves
685
// the same way no matter the screen-size. The old way to do it made
686
// the possible range of pan and tilt increment depend on the canvas
687
// size. 20021022 rolvs.
688
this->pan_increment = 0.5f - float(this->mouseloc[0])/glsize[0];
689
this->tilt_increment = 0.5f - float(this->mouseloc[1])/glsize[1];
695
SoQtFlyViewerP::superimpositionevent(SoAction * action)
697
if (!action->isOfType(SoGLRenderAction::getClassTypeId())) return;
698
SbViewportRegion vpRegion =
699
((SoGLRenderAction *) action)->getViewportRegion();
700
SbVec2s viewport = vpRegion.getViewportSizePixels();
701
float aspect = float(viewport[0]) / float(viewport[1]);
702
float factorx = 1.0f/float(viewport[1]) * 220.0f;
703
float factory = factorx;
705
this->stranslation->translation.setValue(SbVec3f(0.0f, -0.4f, 0.0f));
707
this->stranslation->translation.setValue(SbVec3f(0.0f, -0.4f / aspect, 0.0f));
711
if (viewport[0] > 500)
712
factorx *= 500.0f / 400.0f;
714
factorx *= float(viewport[0]) / 400.0f;
715
this->sscale->scaleFactor.setValue(SbVec3f(factorx, factory, 1.0f));
717
if (this->getMode() == TILTING) {
718
assert(this->crossposition != NULL);
719
assert(this->crossscale != NULL);
720
float tx = float(this->tiltpos[0]-float(viewport[0])/2.0f)/(float(viewport[0]));
721
float ty = float(this->tiltpos[1]-float(viewport[1])/2.0f)/(float(viewport[1]));
722
if (aspect > 1.0f) tx *= aspect;
724
this->crossposition->translation.setValue(SbVec3f(tx, ty, 0));
726
float sx = (1.0f/float(viewport[0])) * 15.0f;
727
float sy = (1.0f/float(viewport[1])) * 15.0f;
728
if (aspect > 1.0f) sx *= aspect;
730
this->crossscale->scaleFactor.setValue(SbVec3f(sx, sy, 0));
735
SoQtFlyViewerP::superimposition_cb(void * closure, SoAction * action)
737
assert(closure != NULL);
738
((SoQtFlyViewerP *) closure)->superimpositionevent(action);
742
SoQtFlyViewerP::updateSpeedIndicator(void)
744
assert(this->sgeometry != NULL);
746
SbVec3f * points = this->sgeometry->point.startEditing();
748
if (points[10][0] == 0.0f)
749
this->smaxspeedswitch->whichChild.setValue(SO_SWITCH_ALL);
750
if (points[14][0] == 0.0f)
751
this->scurrentspeedswitch->whichChild.setValue(SO_SWITCH_ALL);
752
points[10][0] = this->maxspeed / (SOQT_MAX_SPEED / 0.8f);
753
points[11][0] = this->maxspeed / (SOQT_MAX_SPEED / 0.8f);
754
points[14][0] = this->currentspeed / (SOQT_MAX_SPEED / 0.8f);
755
points[15][0] = this->currentspeed / (SOQT_MAX_SPEED / 0.8f);
756
this->sgeometry->point.finishEditing();
758
if (this->maxspeed == 0.0f)
759
this->smaxspeedswitch->whichChild.setValue(SO_SWITCH_NONE);
760
if (this->currentspeed == 0.0f)
761
this->scurrentspeedswitch->whichChild.setValue(SO_SWITCH_NONE);
764
float SoQtFlyViewerP::calculateChangeInTime()
767
thisrender.setToTimeOfDay();
771
if (this->currentspeed == 0.0f)
772
this->lastrender->setValue(thisrender.getValue() - 0.01);
774
t = float(thisrender.getValue() - this->lastrender->getValue()) * 10.0f;
781
void SoQtFlyViewerP::updateCurrentSpeed( float dt )
783
float curveSpeedReductionFactor =
784
1.0f - (this->pan_increment * this->pan_increment
785
+ this->tilt_increment * this->tilt_increment);
787
// NOTE: I don't believe that this boundary condition could ever
788
// happen. 20021022 rolvs
789
if( curveSpeedReductionFactor < 0 )
790
curveSpeedReductionFactor = 0;
792
this->currentspeed +=
793
(((this->currentspeed +
794
this->maxspeed * curveSpeedReductionFactor) / 2.0f) -
795
this->currentspeed) * dt;
798
void SoQtFlyViewerP::updateCameraPosition( SoCamera * camera,
802
assert( camera != NULL );
804
SbRotation orientation = camera->orientation.getValue();
806
camera->orientation.getValue().multVec( SbVec3f(0,0,-1), dir );
808
camera->position.setValue(camera->position.getValue() +
809
dir * (current_speed * dt ));
812
void SoQtFlyViewerP::updateCameraOrientation( SoCamera * camera,
817
assert( camera != NULL );
818
// FIXME: Make sure that the angle between direction and up-vector
819
// stays larger than zero, or else it gets 'locked' in an undefined
820
// state and starts to act weird. This should probably be done in
821
// parent class. 20021017 rolvs
822
PUBLIC( this )->tiltCamera( d_tilt*dt );
824
camera->orientation = camera->orientation.getValue() *
825
SbRotation( PUBLIC(this)->getUpDirection(), d_pan*dt );
829
SoQtFlyViewerP::incrementMaxSpeed()
831
this->max_speed_factor++;
837
SoQtFlyViewerP::decrementMaxSpeed()
839
this->max_speed_factor--;
844
void SoQtFlyViewerP::updateSpeedScalingFactor()
846
SoNode *n = PUBLIC(this)->getSceneGraph();
848
return; // Scenegraph not set yet?
850
SoGetBoundingBoxAction bbact( PUBLIC(this)->getViewportRegion() );
853
SbBox3f bbox = bbact.getBoundingBox();
854
float bbox_diagonal = (bbox.getMax() - bbox.getMin()).length();
856
// FIXME: It should be possible to create a simple scaling function,
857
// based on some logaritmic evaluation. 20021017 rolvs.
858
if( bbox_diagonal>100 )
859
this->speed_scaling_factor = 1.0f; // log(bbox_diagonal);
860
else if( bbox_diagonal>10 && bbox_diagonal < 100 )
861
this->speed_scaling_factor = 0.4f;
862
else if( bbox_diagonal>1 && bbox_diagonal<10 )
863
this->speed_scaling_factor = 0.3f;
864
else if( bbox_diagonal>0.1 && bbox_diagonal<1)
865
this->speed_scaling_factor = 0.1f;
867
this->speed_scaling_factor = 0.1f*bbox_diagonal;
870
void SoQtFlyViewerP::stopMoving()
874
max_speed_factor = 0;
877
void SoQtFlyViewerP::updateMaxSpeed()
879
if( this->max_speed_factor == 0 ){
884
// FIXME: Move this methodcall so that it is called only
885
// once. (e.g. when scene graph is set) 20021021 rolvs
886
this->updateSpeedScalingFactor();
889
this->max_speed_factor
890
* float(pow( SOQT_INC_FACTOR, abs( this->max_speed_factor ) ))
891
* this->speed_scaling_factor;
893
if( this->maxspeed > SOQT_MAX_SPEED )
894
this->maxspeed = SOQT_MAX_SPEED;
895
else if( this->maxspeed < -1*SOQT_MAX_SPEED )
896
this->maxspeed = -1*SOQT_MAX_SPEED;
901
// Set cursor graphics according to mode.
903
SoQtFlyViewerP::updateCursorRepresentation(void)
905
if (!PUBLIC(this)->isCursorEnabled()) {
906
PUBLIC(this)->setComponentCursor(SoQtCursor::getBlankCursor());
910
switch (this->viewermode) {
911
case SoQtFlyViewerP::FLYING:
912
PUBLIC(this)->setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT));
915
case SoQtFlyViewerP::WAITING_FOR_SEEK:
916
PUBLIC(this)->setComponentCursor(SoQtCursor(SoQtCursor::CROSSHAIR));
919
case SoQtFlyViewerP::WAITING_FOR_UP_PICK:
920
PUBLIC(this)->setComponentCursor(SoQtCursor(SoQtCursor::UPARROW));
923
case SoQtFlyViewerP::TILTING:
924
PUBLIC(this)->setComponentCursor(SoQtCursor::getPanCursor());
928
assert(0 && "unknown mode");
933
#endif // DOXYGEN_SKIP_THIS
935
// ************************************************************************
937
SOQT_OBJECT_SOURCE(SoQtFlyViewer);
939
// ************************************************************************
944
SoQtFlyViewer::SoQtFlyViewer(QWidget * parent,
947
SoQtFullViewer::BuildFlag flag,
948
SoQtViewer::Type type)
949
: inherited(parent, name, embed, flag, type, FALSE)
951
PRIVATE(this) = new SoQtFlyViewerP(this);
952
PRIVATE(this)->constructor(TRUE);
955
// ************************************************************************
958
Protected constructor, used by viewer components derived from the
961
SoQtFlyViewer::SoQtFlyViewer(QWidget * parent,
962
const char * const name,
964
SoQtFullViewer::BuildFlag flag,
965
SoQtViewer::Type type,
967
: inherited(parent, name, embed, flag, type, FALSE)
969
PRIVATE(this) = new SoQtFlyViewerP(this);
970
PRIVATE(this)->constructor(build);
973
// ************************************************************************
978
SoQtFlyViewer::~SoQtFlyViewer()
980
if (PRIVATE(this)->superimposition != NULL) {
981
this->removeSuperimposition(PRIVATE(this)->superimposition);
982
PRIVATE(this)->superimposition->unref();
983
PRIVATE(this)->superimposition = NULL;
985
delete PRIVATE(this);
988
// ************************************************************************
992
SoQtFlyViewer::setViewing(SbBool enable)
994
if (enable != this->isViewing())
995
PRIVATE(this)->stopMoving();
997
inherited::setViewing(enable);
998
this->setSuperimpositionEnabled(PRIVATE(this)->superimposition, enable);
999
this->scheduleRedraw();
1002
// ************************************************************************
1006
SoQtFlyViewer::resetToHomePosition(void)
1008
PRIVATE(this)->stopMoving();
1009
inherited::resetToHomePosition();
1012
// ************************************************************************
1016
SoQtFlyViewer::viewAll(void)
1018
PRIVATE(this)->stopMoving();
1019
inherited::viewAll();
1022
// ************************************************************************
1026
SoQtFlyViewer::setCamera(SoCamera * camera)
1028
PRIVATE(this)->stopMoving();
1030
inherited::setCamera(camera);
1031
// FIXME: do something with up-direction?
1034
// ************************************************************************
1038
SoQtFlyViewer::setCursorEnabled(SbBool enable)
1040
inherited::setCursorEnabled(enable);
1041
PRIVATE(this)->updateCursorRepresentation();
1044
// ************************************************************************
1048
SoQtFlyViewer::setCameraType(SoType type)
1050
PRIVATE(this)->stopMoving();
1051
inherited::setCameraType(type);
1052
// FIXME: what else? 20010907 mortene.
1055
// ************************************************************************
1059
SoQtFlyViewer::getDefaultWidgetName(void) const
1061
static const char defaultWidgetName[] = "SoQtFlyViewer";
1062
return defaultWidgetName;
1065
// ************************************************************************
1069
SoQtFlyViewer::getDefaultTitle(void) const
1071
static const char defaultTitle[] = "Fly Viewer";
1072
return defaultTitle;
1075
// ************************************************************************
1079
SoQtFlyViewer::getDefaultIconTitle(void) const
1081
static const char defaultIconTitle[] = "Fly Viewer";
1082
return defaultIconTitle;
1085
// ************************************************************************
1087
// Documented in superclass.
1089
SoQtFlyViewer::processSoEvent(const SoEvent * const event)
1091
// FIXME: Refactor the event-handling so that it uses the same
1092
// strategy as in SoQtExaminerViewer, where the event-handler
1093
// only checks the state and the mode from that. 20021016 rolvs.
1095
// Let the end-user toggle between camera-interaction mode
1096
// ("viewing") and scenegraph-interaction mode with ALT key(s).
1097
// FIXME: Allow this to be handled by processKeyboardEvent?
1099
if (event->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
1100
SoKeyboardEvent * ke = (SoKeyboardEvent *)event;
1101
switch (ke->getKey()) {
1102
case SoKeyboardEvent::LEFT_ALT:
1103
case SoKeyboardEvent::RIGHT_ALT:
1104
if (this->isViewing() && (ke->getState() == SoButtonEvent::DOWN)) {
1105
this->setViewing(FALSE);
1108
else if (!this->isViewing() && (ke->getState() == SoButtonEvent::UP)) {
1109
this->setViewing(TRUE);
1117
// We're in "interact" mode (ie *not* the camera modification mode),
1118
// so don't handle the event here. It should either be forwarded to
1119
// the scenegraph, or caught by SoQtViewer::processSoEvent() if
1120
// it's an ESC press (to switch modes).
1121
if (!this->isViewing()) { return inherited::processSoEvent(event); }
1123
// Events when in "ready-to-seek" mode are ignored, except those
1124
// which influence the seek mode itself -- these are handled further
1125
// up the inheritance hierarchy.
1126
if (this->isSeekMode()) { return inherited::processSoEvent(event); }
1128
// FIXME: There is more parts of the code in
1129
// SoQt*FlyViewer::processEvent that should go in to the
1130
// processKeyboardEvent function; to be fixed later.
1133
// Keyboard handling
1134
if (event->isOfType(SoKeyboardEvent::getClassTypeId())) {
1136
PRIVATE(this)->processKeyboardEvent( (SoKeyboardEvent*)event );
1141
// Else: Do nothing, and proceed as usual
1144
// Mousebutton handling
1145
// See FIXME and comment for keyboardhandler.
1146
else if (event->isOfType(SoMouseButtonEvent::getClassTypeId())) {
1147
// FIXME: only for fly mode
1148
const SoMouseButtonEvent * const me =
1149
(const SoMouseButtonEvent *const) event;
1150
SbBool result = PRIVATE( this )->processMouseButtonEvent( me );
1155
else if (event->isOfType(SoLocation2Event::getClassTypeId())) {
1156
const SoLocation2Event * const le =
1157
(const SoLocation2Event * const) event;
1158
SbBool result = PRIVATE( this )->processLocation2Event( le );
1163
return inherited::processSoEvent(event);
1166
// ************************************************************************
1170
SoQtFlyViewer::setSeekMode(SbBool enable)
1172
// Note: this method is almost identical to the setSeekMode() in the
1173
// SoQtExaminerViewer, so migrate any changes.
1176
if (enable == this->isSeekMode()) {
1177
SoDebugError::postWarning("SoQtFlyViewer::setSeekMode",
1178
"seek mode already %sset", enable ? "" : "un");
1181
#endif // SOQT_DEBUG
1183
// FIXME: what if we're in the middle of a seek already? 20010910 mortene.
1184
// larsa - either stop the seek (on false) or reset timer to two new secs
1186
inherited::setSeekMode(enable);
1187
PRIVATE(this)->setMode(enable ? SoQtFlyViewerP::WAITING_FOR_SEEK :
1188
SoQtFlyViewerP::FLYING);
1191
// ************************************************************************
1195
SoQtFlyViewer::actualRedraw(void)
1197
if (!this->isViewing()) {
1198
inherited::actualRedraw();
1202
switch (PRIVATE(this)->getMode()) {
1203
case SoQtFlyViewerP::FLYING:
1205
float dt = PRIVATE(this)->calculateChangeInTime();
1206
PRIVATE(this)->updateCurrentSpeed( dt );
1208
PRIVATE(this)->updateSpeedIndicator();
1211
thisrender.setToTimeOfDay();
1213
if (PRIVATE(this)->currentspeed != 0.0f) {
1214
float t = float(thisrender.getValue() -
1215
PRIVATE(this)->lastrender->getValue()) * 2.0f;
1217
SoCamera * camera = this->getCamera();
1219
if (camera){ // could be a sceneless viewer
1220
PRIVATE(this)->updateCameraPosition
1222
PRIVATE(this)->currentspeed*
1223
PRIVATE(this)->speed_scaling_factor,
1225
PRIVATE(this)->updateCameraOrientation
1227
PRIVATE(this)->tilt_increment,
1228
PRIVATE(this)->pan_increment,
1234
inherited::actualRedraw();
1236
PRIVATE(this)->lastrender->setValue(thisrender.getValue());
1238
if (PRIVATE(this)->currentspeed != 0.0f ||
1239
PRIVATE(this)->maxspeed != 0.0f)
1240
this->scheduleRedraw();
1244
inherited::actualRedraw();
1249
// ************************************************************************
1253
SoQtFlyViewer::rightWheelMotion(float value)
1255
PRIVATE(this)->dolly(value - this->getRightWheelValue());
1256
inherited::rightWheelMotion(value);
1259
// ************************************************************************
1263
SoQtFlyViewer::afterRealizeHook(void)
1265
PRIVATE(this)->updateCursorRepresentation();
1266
inherited::afterRealizeHook();
1269
// ************************************************************************