23
#include "PreCompiled.h"
25
# include <Inventor/SbViewportRegion.h>
26
# include <Inventor/SoPickedPoint.h>
27
# include <Inventor/actions/SoGetBoundingBoxAction.h>
28
# include <Inventor/errors/SoDebugError.h>
29
# include <Inventor/nodes/SoSeparator.h>
30
# include <Inventor/nodes/SoCamera.h>
31
# include <Inventor/nodes/SoOrthographicCamera.h>
32
# include <Inventor/nodes/SoPerspectiveCamera.h>
33
# include <Inventor/projectors/SbSphereSheetProjector.h>
35
# include <QActionGroup>
36
# include <QApplication>
42
#include <App/Application.h>
44
#include "NavigationStyle.h"
45
#include "Application.h"
46
#include "MenuManager.h"
47
#include "MouseSelection.h"
48
#include "NavigationAnimator.h"
49
#include "NavigationAnimation.h"
50
#include "SoMouseWheelEvent.h"
51
#include "View3DInventorViewer.h"
55
class FCSphereSheetProjector : public SbSphereSheetProjector {
56
using inherited = SbSphereSheetProjector;
65
FCSphereSheetProjector(const SbSphere & sph, const SbBool orienttoeye = true)
66
: SbSphereSheetProjector(sph, orienttoeye)
70
void setViewVolume (const SbViewVolume &vol) override
72
inherited::setViewVolume(vol);
75
void setWorkingSpace (const SbMatrix &space) override
78
this->worldToScreen = space.inverse();
81
SbVec3f project(const SbVec2f &point) override
83
return inherited::project(point);
86
SbRotation getRotation(const SbVec3f &point1, const SbVec3f &point2) override
88
SbRotation rot = inherited::getRotation(point1, point2);
89
if (orbit == Turntable) {
90
return getTurntable(rot, point1, point2);
92
if (orbit == FreeTurntable) {
93
return getFreeTurntable(point1, point2);
99
void setOrbitStyle(OrbitStyle style)
104
OrbitStyle getOrbitStyle() const
110
SbRotation getTurntable(SbRotation rot, const SbVec3f &point1, const SbVec3f &point2) const
115
rot.getValue(axis, angle);
116
SbVec3f dif = point1 - point2;
117
if (fabs(dif[1]) > fabs(dif[0])) {
118
SbVec3f xaxis(1,0,0);
122
rot.setValue(xaxis, angle);
125
SbVec3f zaxis(0,0,1);
126
this->worldToScreen.multDirMatrix(zaxis, zaxis);
137
rot.setValue(zaxis, angle);
143
SbRotation getFreeTurntable(const SbVec3f &point1, const SbVec3f &point2) const
148
SbVec3f dif = point1 - point2;
150
SbVec3f zaxis(1,0,0);
151
zrot.setValue(zaxis, dif[1]);
153
SbVec3f xaxis(0,0,1);
154
this->worldToScreen.multDirMatrix(xaxis, xaxis);
155
xrot.setValue(xaxis, -dif[0]);
161
SbMatrix worldToScreen;
162
OrbitStyle orbit{Trackball};
165
NavigationStyleEvent::NavigationStyleEvent(const Base::Type& s)
166
: QEvent(QEvent::User), t(s)
170
NavigationStyleEvent::~NavigationStyleEvent() = default;
172
const Base::Type& NavigationStyleEvent::style() const
177
TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStyle,Base::BaseClass)
179
NavigationStyle::NavigationStyle() : viewer(nullptr), mouseSelection(nullptr)
181
this->rotationCenterMode = NavigationStyle::RotationCenterMode::ScenePointAtCursor
182
| NavigationStyle::RotationCenterMode::FocalPointAtCursor;
186
NavigationStyle::~NavigationStyle()
189
delete this->animator;
192
NavigationStyle& NavigationStyle::operator = (const NavigationStyle& ns)
194
this->panningplane = ns.panningplane;
195
this->menuenabled = ns.menuenabled;
196
this->animationEnabled = ns.animationEnabled;
197
this->spinningAnimationEnabled = ns.spinningAnimationEnabled;
198
static_cast<FCSphereSheetProjector*>(this->spinprojector)->setOrbitStyle
199
(static_cast<FCSphereSheetProjector*>(ns.spinprojector)->getOrbitStyle());
203
void NavigationStyle::setViewer(View3DInventorViewer* view)
208
void NavigationStyle::initialize()
210
this->animator = new NavigationAnimator();
212
this->sensitivity = 2.0f;
213
this->resetcursorpos = false;
214
this->currentmode = NavigationStyle::IDLE;
215
this->animationEnabled = true;
216
this->spinningAnimationEnabled = false;
217
this->spinsamplecounter = 0;
218
this->spinincrement = SbRotation::identity();
219
this->rotationCenterFound = false;
224
this->spinprojector = new FCSphereSheetProjector(SbSphere(SbVec3f(0, 0, 0), 0.8f));
226
volume.ortho(-1, 1, -1, 1, -1, 1);
227
this->spinprojector->setViewVolume(volume);
230
this->log.position = new SbVec2s [ 16 ];
231
this->log.time = new SbTime [ 16 ];
232
this->log.historysize = 0;
234
this->menuenabled = true;
235
this->button1down = false;
236
this->button2down = false;
237
this->button3down = false;
238
this->ctrldown = false;
239
this->shiftdown = false;
240
this->altdown = false;
241
this->invertZoom = App::GetApplication().GetParameterGroupByPath
242
("User parameter:BaseApp/Preferences/View")->GetBool("InvertZoom",true);
243
this->zoomAtCursor = App::GetApplication().GetParameterGroupByPath
244
("User parameter:BaseApp/Preferences/View")->GetBool("ZoomAtCursor",true);
245
this->zoomStep = App::GetApplication().GetParameterGroupByPath
246
("User parameter:BaseApp/Preferences/View")->GetFloat("ZoomStep",0.2f);
247
long mode = App::GetApplication().GetParameterGroupByPath
248
("User parameter:BaseApp/Preferences/View")->GetInt("RotationMode", 1);
250
setRotationCenterMode(NavigationStyle::RotationCenterMode::WindowCenter);
252
else if (mode == 1) {
253
setRotationCenterMode(NavigationStyle::RotationCenterMode::ScenePointAtCursor |
254
NavigationStyle::RotationCenterMode::FocalPointAtCursor);
256
else if (mode == 2) {
257
setRotationCenterMode(NavigationStyle::RotationCenterMode::ScenePointAtCursor |
258
NavigationStyle::RotationCenterMode::BoundingBoxCenter);
261
this->hasDragged = false;
262
this->hasPanned = false;
263
this->hasZoomed = false;
266
void NavigationStyle::finalize()
268
delete this->spinprojector;
269
delete[] this->log.position;
270
delete[] this->log.time;
273
void NavigationStyle::interactiveCountInc()
275
viewer->interactiveCountInc();
278
void NavigationStyle::interactiveCountDec()
280
viewer->interactiveCountDec();
283
int NavigationStyle::getInteractiveCount() const
285
return viewer->getInteractiveCount();
288
void NavigationStyle::setOrbitStyle(NavigationStyle::OrbitStyle style)
290
auto projector = static_cast<FCSphereSheetProjector*>(this->spinprojector);
291
projector->setOrbitStyle(FCSphereSheetProjector::OrbitStyle(style));
294
NavigationStyle::OrbitStyle NavigationStyle::getOrbitStyle() const
296
auto projector = static_cast<FCSphereSheetProjector*>(this->spinprojector);
297
return NavigationStyle::OrbitStyle(projector->getOrbitStyle());
300
SbBool NavigationStyle::isViewing() const
302
return viewer->isViewing();
305
void NavigationStyle::setViewing(SbBool enable)
307
viewer->setViewing(enable);
310
SbBool NavigationStyle::isSeekMode() const
312
return viewer->isSeekMode();
315
void NavigationStyle::setSeekMode(SbBool enable)
317
viewer->setSeekMode(enable);
320
SbBool NavigationStyle::seekToPoint(const SbVec2s screenpos)
322
return viewer->seekToPoint(screenpos);
325
void NavigationStyle::seekToPoint(const SbVec3f& scenepos)
327
viewer->seekToPoint(scenepos);
330
void NavigationStyle::lookAtPoint(const SbVec2s screenpos)
332
const SoCamera* camera = viewer->getCamera();
337
SoRayPickAction rpaction(viewer->getViewportRegion());
338
rpaction.setPoint(screenpos);
339
rpaction.setRadius(viewer->getPickRadius());
340
rpaction.apply(viewer->getSoRenderManager()->getSceneGraph());
342
const SoPickedPoint* picked = rpaction.getPickedPoint();
347
point = picked->getPoint();
350
const SbViewportRegion& vp = viewer->getViewportRegion();
351
const float aspectratio = vp.getViewportAspectRatio();
352
SbViewVolume vv = camera->getViewVolume(aspectratio);
355
if (aspectratio < 1.0) {
356
vv.scale(1.0 / aspectratio);
360
vv.projectPointToLine(normalizePixelPos(screenpos), line);
361
panningplane.intersect(line, point);
367
void NavigationStyle::lookAtPoint(const SbVec3f& position)
369
this->rotationCenterFound = false;
370
translateCamera(position - getFocalPoint());
373
SoCamera* NavigationStyle::getCamera() const
375
return this->viewer->getCamera();
378
void NavigationStyle::setCameraOrientation(const SbRotation& orientation, SbBool moveToCenter)
380
SoCamera* camera = getCamera();
386
SbVec3f focalPoint = getFocalPoint();
387
SbVec3f translation(0, 0, 0);
390
SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
391
action.apply(viewer->getSceneGraph());
392
SbBox3f box = action.getBoundingBox();
393
if (!box.isEmpty()) {
394
translation = box.getCenter() - focalPoint;
399
if (isAnimationEnabled()) {
400
viewer->startAnimation(orientation, focalPoint, translation);
404
SbVec3f rotationCenterDistanceCam = camera->focalDistance.getValue() * SbVec3f(0, 0, 1);
407
camera->orientation = orientation;
410
SbVec3f newRotationCenterDistance;
411
camera->orientation.getValue().multVec(rotationCenterDistanceCam, newRotationCenterDistance);
415
camera->position = focalPoint + newRotationCenterDistance + translation;
419
void NavigationStyle::translateCamera(const SbVec3f& translation)
421
SoCamera* camera = getCamera();
428
if (isAnimationEnabled()) {
429
viewer->startAnimation(camera->orientation.getValue(), SbVec3f(0, 0, 0), translation);
432
camera->position = camera->position.getValue() + translation;
436
void NavigationStyle::boxZoom(const SbBox2s& box)
438
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
441
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
442
SbViewVolume vv = cam->getViewVolume(vp.getViewportAspectRatio());
444
short sizeX{},sizeY{};
445
box.getSize(sizeX, sizeY);
446
SbVec2s size = vp.getViewportSizePixels();
450
if (sizeX == 0 && sizeY == 0)
454
short xmin{},xmax{},ymin{},ymax{};
455
box.getBounds(xmin,ymin,xmax,ymax);
456
const SbVec2f center((float) ((xmin+xmax)/2) / (float) std::max((int)(size[0] - 1), 1),
457
(float) (size[1]-(ymin+ymax)/2) / (float) std::max((int)(size[1] - 1), 1));
459
SbPlane plane = vv.getPlane(cam->focalDistance.getValue());
460
panCamera(cam,vp.getViewportAspectRatio(),plane, SbVec2f(0.5,0.5), center);
463
float scaleX = (float)sizeX/(float)size[0];
464
float scaleY = (float)sizeY/(float)size[1];
465
float scale = std::max<float>(scaleX, scaleY);
466
if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
467
float height = static_cast<SoOrthographicCamera*>(cam)->height.getValue() * scale;
468
static_cast<SoOrthographicCamera*>(cam)->height = height;
470
else if (cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
471
float height = static_cast<SoPerspectiveCamera*>(cam)->heightAngle.getValue() / 2.0f;
472
height = 2.0f * atan(tan(height) * scale);
473
static_cast<SoPerspectiveCamera*>(cam)->heightAngle = height;
477
void NavigationStyle::viewAll()
480
SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
481
action.apply(viewer->getSceneGraph());
482
SbBox3f box = action.getBoundingBox();
487
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
491
SbViewVolume vol = cam->getViewVolume();
492
if (vol.ulf == vol.llf)
494
SbVec2f s = vol.projectBox(box);
495
SbVec2s size = viewer->getSoRenderManager()->getSize();
497
SbVec3f pt1, pt2, pt3, tmp;
498
vol.projectPointToLine( SbVec2f(0.0f,0.0f), pt1, tmp );
499
vol.projectPointToLine( SbVec2f(s[0],0.0f), pt2, tmp );
500
vol.projectPointToLine( SbVec2f(0.0f,s[1]), pt3, tmp );
502
float cam_width = (pt2-pt1).length();
503
float cam_height = (pt3-pt1).length();
506
cam_height = 1.08f * std::max<float>((cam_width*(float)size[1])/(float)size[0],cam_height);
508
float aspect = cam->aspectRatio.getValue();
510
if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
511
auto ocam = static_cast<SoOrthographicCamera *>(cam);
513
ocam->height = cam_height / aspect;
515
ocam->height = cam_height;
519
#if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403)
520
void NavigationStyle::findBoundingSphere() {
522
SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
523
action.apply(viewer->getSceneGraph());
524
boundingSphere.circumscribe(action.getBoundingBox());
531
void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation)
533
reorientCamera(camera, rotation, getFocalPoint());
539
void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation, const SbVec3f& rotationCenter)
546
SbVec3f rotationCenterDistanceCam;
547
camera->orientation.getValue().inverse().multVec(camera->position.getValue() - rotationCenter, rotationCenterDistanceCam);
550
camera->orientation = rotation * camera->orientation.getValue();
553
SbVec3f newRotationCenterDistance;
554
camera->orientation.getValue().multVec(rotationCenterDistanceCam, newRotationCenterDistance);
557
camera->position = rotationCenter + newRotationCenterDistance;
559
#if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403)
561
if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
565
camera->orientation.getValue().inverse().multVec(boundingSphere.getCenter() - camera->position.getValue(), center);
568
camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), dir);
572
float repositionDistance = -center.getValue()[2] - boundingSphere.getRadius();
573
camera->position = camera->position.getValue() + repositionDistance * dir;
574
camera->nearDistance = 0;
575
camera->farDistance = 2 * boundingSphere.getRadius() + 1;
576
camera->focalDistance = camera->focalDistance.getValue() - repositionDistance;
581
void NavigationStyle::panCamera(SoCamera * cam, float aspectratio, const SbPlane & panplane,
582
const SbVec2f & currpos, const SbVec2f & prevpos)
586
if (currpos == prevpos)
591
SbViewVolume vv = cam->getViewVolume(aspectratio);
594
if(aspectratio < 1.0)
595
vv.scale(1.0 / aspectratio);
598
vv.projectPointToLine(currpos, line);
599
SbVec3f current_planept;
600
panplane.intersect(line, current_planept);
601
vv.projectPointToLine(prevpos, line);
603
panplane.intersect(line, old_planept);
607
cam->position = cam->position.getValue() - (current_planept - old_planept);
609
if (this->currentmode != NavigationStyle::IDLE) {
614
void NavigationStyle::setupPanningPlane(const SoCamera* camera)
620
this->panningplane = SbPlane(SbVec3f(0, 0, 1), 0);
623
const SbViewportRegion& vp = viewer->getViewportRegion();
624
const float aspectratio = vp.getViewportAspectRatio();
625
SbViewVolume vv = camera->getViewVolume(aspectratio);
628
if (aspectratio < 1.0) {
629
vv.scale(1.0 / aspectratio);
632
this->panningplane = vv.getPlane(camera->focalDistance.getValue());
640
void NavigationStyle::zoom(SoCamera * cam, float diffvalue)
647
SoType t = cam->getTypeId();
648
SbName tname = t.getName();
651
auto multiplicator = float(exp(diffvalue));
653
if (t.isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
660
auto oc = static_cast<SoOrthographicCamera *>(cam);
661
oc->height = oc->height.getValue() * multiplicator;
668
if (!t.isDerivedFrom(SoPerspectiveCamera::getClassTypeId()) &&
669
tname != "FrustumCamera") {
679
const float oldfocaldist = cam->focalDistance.getValue();
680
const float newfocaldist = oldfocaldist * multiplicator;
683
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
685
const SbVec3f oldpos = cam->position.getValue();
686
const SbVec3f newpos = oldpos + (newfocaldist - oldfocaldist) * -direction;
702
const float distorigo = newpos.length();
705
if (distorigo > float(sqrt(FLT_MAX))) {
709
cam->position = newpos;
710
cam->focalDistance = newfocaldist;
714
if (this->currentmode != NavigationStyle::IDLE) {
721
void NavigationStyle::zoomByCursor(const SbVec2f & thispos, const SbVec2f & prevpos)
725
float value = (thispos[1] - prevpos[1]) * 10.0f;
726
if (this->invertZoom)
728
zoom(viewer->getSoRenderManager()->getCamera(), value);
731
void NavigationStyle::zoomIn()
733
zoom(viewer->getSoRenderManager()->getCamera(), -this->zoomStep);
736
void NavigationStyle::zoomOut()
738
zoom(viewer->getSoRenderManager()->getCamera(), this->zoomStep);
744
int NavigationStyle::getDelta() const
749
void NavigationStyle::doZoom(SoCamera* camera, int wheeldelta, const SbVec2f& pos)
751
float value = this->zoomStep * wheeldelta / float(getDelta());
752
if (this->invertZoom)
754
doZoom(camera, value, pos);
761
void NavigationStyle::doZoom(SoCamera* camera, float logfactor, const SbVec2f& pos)
765
if (fabs(logfactor)>4.0)
767
SbBool zoomAtCur = this->zoomAtCursor;
769
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
770
float ratio = vp.getViewportAspectRatio();
771
SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio());
772
SbPlane panplane = vv.getPlane(camera->focalDistance.getValue());
773
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, SbVec2f(0.5,0.5), pos);
776
zoom(camera, logfactor);
779
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
780
float ratio = vp.getViewportAspectRatio();
781
SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio());
782
SbPlane panplane = vv.getPlane(camera->focalDistance.getValue());
783
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, pos, SbVec2f(0.5,0.5));
787
if (!rotationCenterMode) {
788
viewer->changeRotationCenterPosition(getFocalPoint());
790
#if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403)
791
findBoundingSphere();
797
void NavigationStyle::doRotate(SoCamera * camera, float angle, const SbVec2f& pos)
799
SbBool zoomAtCur = this->zoomAtCursor;
801
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
802
float ratio = vp.getViewportAspectRatio();
803
SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio());
804
SbPlane panplane = vv.getPlane(camera->focalDistance.getValue());
805
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, SbVec2f(0.5,0.5), pos);
808
SbRotation rotcam = camera->orientation.getValue();
811
rotcam.multVec(SbVec3f(0,0,-1),vdir);
813
SbRotation drot(vdir,angle);
814
camera->orientation.setValue(rotcam * drot);
817
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
818
float ratio = vp.getViewportAspectRatio();
819
SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio());
820
SbPlane panplane = vv.getPlane(camera->focalDistance.getValue());
821
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, pos, SbVec2f(0.5,0.5));
826
SbVec3f NavigationStyle::getRotationCenter(SbBool& found) const
828
found = this->rotationCenterFound;
829
return this->rotationCenter;
832
void NavigationStyle::setRotationCenter(const SbVec3f& cnt)
834
this->rotationCenter = cnt;
835
this->rotationCenterFound = true;
838
SbVec3f NavigationStyle::getFocalPoint() const
840
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
846
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
847
SbVec3f focal = cam->position.getValue() +
848
cam->focalDistance.getValue() * direction;
855
void NavigationStyle::spin(const SbVec2f & pointerpos)
857
if (this->log.historysize < 2)
859
assert(this->spinprojector);
861
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
862
SbVec2s glsize(vp.getViewportSizePixels());
864
lastpos[0] = float(this->log.position[1][0]) / float(std::max((int)(glsize[0]-1), 1));
865
lastpos[1] = float(this->log.position[1][1]) / float(std::max((int)(glsize[1]-1), 1));
867
if (this->rotationCenterMode && this->rotationCenterFound) {
868
SbVec3f hitpoint = this->rotationCenter;
872
viewer->getSoRenderManager()->getCamera()->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
873
viewer->getSoRenderManager()->getCamera()->position = hitpoint - viewer->getSoRenderManager()->getCamera()->focalDistance.getValue() * direction;
878
viewer->getSoRenderManager()->getCamera()->orientation.getValue().getValue(mat);
879
this->spinprojector->setWorkingSpace(mat);
881
this->spinprojector->project(lastpos);
883
this->spinprojector->projectAndGetRotation(pointerpos, r);
884
float sensitivity = getSensitivity();
885
if (sensitivity > 1.0f) {
888
r.getValue(axis, radians);
889
radians = sensitivity * radians;
890
r.setValue(axis, radians);
893
this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r);
895
if (this->rotationCenterMode && this->rotationCenterFound) {
896
float ratio = vp.getViewportAspectRatio();
897
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(vp.getViewportAspectRatio());
898
SbPlane panplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
900
posn[0] = float(this->localPos[0]) / float(std::max((int)(glsize[0]-1), 1));
901
posn[1] = float(this->localPos[1]) / float(std::max((int)(glsize[1]-1), 1));
902
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, posn, SbVec2f(0.5,0.5));
908
SbVec3f dummy_axis, newaxis;
909
float acc_angle{}, newangle{};
910
this->spinincrement.getValue(dummy_axis, acc_angle);
911
acc_angle *= this->spinsamplecounter;
912
r.getValue(newaxis, newangle);
913
acc_angle += newangle;
915
this->spinsamplecounter++;
916
acc_angle /= this->spinsamplecounter;
918
this->spinincrement.setValue(newaxis, acc_angle);
923
if (this->spinsamplecounter > 3) this->spinsamplecounter = 3;
925
if (this->currentmode != NavigationStyle::IDLE) {
940
void NavigationStyle::spin_simplified(SoCamera* cam, SbVec2f curpos, SbVec2f prevpos)
942
assert(this->spinprojector);
944
if (this->rotationCenterMode && this->rotationCenterFound) {
945
SbVec3f hitpoint = this->rotationCenter;
949
viewer->getSoRenderManager()->getCamera()->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
950
viewer->getSoRenderManager()->getCamera()->position = hitpoint - viewer->getSoRenderManager()->getCamera()->focalDistance.getValue() * direction;
955
viewer->getSoRenderManager()->getCamera()->orientation.getValue().getValue(mat);
956
this->spinprojector->setWorkingSpace(mat);
958
this->spinprojector->project(prevpos);
960
this->spinprojector->projectAndGetRotation(curpos, r);
961
float sensitivity = getSensitivity();
962
if (sensitivity > 1.0f) {
965
r.getValue(axis, radians);
966
radians = sensitivity * radians;
967
r.setValue(axis, radians);
970
this->reorientCamera(cam, r);
972
if (this->rotationCenterMode && this->rotationCenterFound) {
973
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
974
SbVec2s glsize(vp.getViewportSizePixels());
976
float ratio = vp.getViewportAspectRatio();
977
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(vp.getViewportAspectRatio());
978
SbPlane panplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
980
posn[0] = float(this->localPos[0]) / float(std::max((int)(glsize[0]-1), 1));
981
posn[1] = float(this->localPos[1]) / float(std::max((int)(glsize[1]-1), 1));
982
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, posn, SbVec2f(0.5,0.5));
988
SbBool NavigationStyle::doSpin()
990
if (this->log.historysize >= 3) {
991
SbTime stoptime = (SbTime::getTimeOfDay() - this->log.time[0]);
992
if (isSpinningAnimationEnabled() && stoptime.getValue() < 0.100) {
993
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
994
const SbVec2s glsize(vp.getViewportSizePixels());
995
SbVec3f from = this->spinprojector->project(SbVec2f(float(this->log.position[2][0]) / float(std::max(glsize[0]-1, 1)),
996
float(this->log.position[2][1]) / float(std::max(glsize[1]-1, 1))));
997
SbVec3f to = this->spinprojector->project(this->lastmouseposition);
998
SbRotation rot = this->spinprojector->getRotation(from, to);
1000
SbTime delta = (this->log.time[0] - this->log.time[2]);
1001
double deltatime = delta.getValue();
1003
rot.scaleAngle(float(0.200 / deltatime));
1007
rot.getValue(axis, radians);
1008
if ((radians > 0.01f) && (deltatime < 0.300)) {
1009
viewer->startSpinningAnimation(axis, radians * 5);
1018
void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
1020
this->globalPos.setValue(QCursor::pos().x(), QCursor::pos().y());
1021
this->localPos = ev->getPosition();
1024
if (!this->rotationCenterMode) {
1025
setRotationCenter(getFocalPoint());
1031
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::ScenePointAtCursor) {
1032
SoRayPickAction rpaction(viewer->getSoRenderManager()->getViewportRegion());
1033
rpaction.setPoint(this->localPos);
1034
rpaction.setRadius(viewer->getPickRadius());
1035
rpaction.apply(viewer->getSoRenderManager()->getSceneGraph());
1037
SoPickedPoint * picked = rpaction.getPickedPoint();
1039
setRotationCenter(picked->getPoint());
1045
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::FocalPointAtCursor) {
1047
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
1048
float ratio = vp.getViewportAspectRatio();
1050
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
1053
SbViewVolume vv = cam->getViewVolume(ratio);
1056
SbVec2f currpos = ev->getNormalizedPosition(vp);
1057
vv.projectPointToLine(currpos, line);
1058
SbVec3f current_planept;
1059
SbPlane panplane = vv.getPlane(cam->focalDistance.getValue());
1060
panplane.intersect(line, current_planept);
1062
setRotationCenter(current_planept);
1066
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::BoundingBoxCenter) {
1067
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
1068
float ratio = vp.getViewportAspectRatio();
1070
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
1075
SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
1076
action.apply(viewer->objectGroup);
1077
SbBox3f boundingBox = action.getBoundingBox();
1078
SbVec3f boundingBoxCenter = boundingBox.getCenter();
1079
setRotationCenter(boundingBoxCenter);
1084
SbViewVolume vv = cam->getViewVolume(ratio);
1085
vv.projectToScreen(boundingBoxCenter, boundingBoxCenter);
1086
SbVec2s size = vp.getViewportSizePixels();
1087
auto tox = static_cast<short>(boundingBoxCenter[0] * size[0]);
1088
auto toy = static_cast<short>(boundingBoxCenter[1] * size[1]);
1089
this->localPos.setValue(tox, toy);
1093
SbVec2f NavigationStyle::normalizePixelPos(SbVec2s pixpos)
1095
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
1096
const SbVec2s size(vp.getViewportSizePixels());
1097
return {(float) pixpos[0] / (float) std::max((int)(size[0] - 1), 1),
1098
(float) pixpos[1] / (float) std::max((int)(size[1] - 1), 1)};
1101
SbVec2f NavigationStyle::normalizePixelPos(SbVec2f pixpos)
1103
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
1104
const SbVec2s size(vp.getViewportSizePixels());
1105
return {pixpos[0] / (float) std::max((int)(size[0] - 1), 1),
1106
pixpos[1] / (float) std::max((int)(size[1] - 1), 1)};
1109
void NavigationStyle::moveCursorPosition()
1111
if (!isResetCursorPosition())
1114
QPoint cpos = QCursor::pos();
1115
if (abs(cpos.x()-globalPos[0]) > 10 ||
1116
abs(cpos.y()-globalPos[1]) > 10) {
1117
QCursor::setPos(globalPos[0], globalPos[1]-1);
1118
this->log.position[0] = localPos;
1123
SbBool NavigationStyle::handleEventInForeground(const SoEvent* const e)
1125
SoHandleEventAction action(viewer->getSoRenderManager()->getViewportRegion());
1127
action.setPickRadius(viewer->getPickRadius());
1128
action.apply(viewer->foregroundroot);
1129
return action.isHandled();
1137
void NavigationStyle::setAnimationEnabled(const SbBool enable)
1139
animationEnabled = enable;
1140
if (!enable && isAnimating()) {
1150
void NavigationStyle::setSpinningAnimationEnabled(const SbBool enable)
1152
spinningAnimationEnabled = enable;
1153
if (!enable && isSpinning()) {
1161
SbBool NavigationStyle::isAnimationEnabled() const
1163
return animationEnabled;
1169
SbBool NavigationStyle::isSpinningAnimationEnabled() const
1171
return animationEnabled && spinningAnimationEnabled;
1177
SbBool NavigationStyle::isAnimating() const
1179
return animator->isAnimating();
1185
SbBool NavigationStyle::isSpinning() const
1187
return currentmode == NavigationStyle::SPINNING;
1190
void NavigationStyle::startAnimating(const std::shared_ptr<NavigationAnimation>& animation, bool wait) const
1193
animator->startAndWait(animation);
1196
animator->start(animation);
1200
void NavigationStyle::stopAnimating() const
1205
void NavigationStyle::setSensitivity(float val)
1207
this->sensitivity = val;
1210
float NavigationStyle::getSensitivity() const
1212
return this->sensitivity;
1215
void NavigationStyle::setResetCursorPosition(SbBool on)
1217
this->resetcursorpos = on;
1220
SbBool NavigationStyle::isResetCursorPosition() const
1222
return this->resetcursorpos;
1225
void NavigationStyle::setZoomInverted(SbBool on)
1227
this->invertZoom = on;
1230
SbBool NavigationStyle::isZoomInverted() const
1232
return this->invertZoom;
1235
void NavigationStyle::setZoomStep(float val)
1237
this->zoomStep = val;
1240
void NavigationStyle::setZoomAtCursor(SbBool on)
1242
this->zoomAtCursor = on;
1245
SbBool NavigationStyle::isZoomAtCursor() const
1247
return this->zoomAtCursor;
1250
void NavigationStyle::setRotationCenterMode(NavigationStyle::RotationCenterModes mode)
1252
this->rotationCenterMode = mode;
1255
NavigationStyle::RotationCenterModes NavigationStyle::getRotationCenterMode() const
1257
return this->rotationCenterMode;
1260
void NavigationStyle::startSelection(AbstractMouseSelection* mouse)
1265
if (mouseSelection) {
1266
SoDebugError::postWarning("NavigationStyle::startSelection",
1267
"Set new mouse selection while an old is still active.");
1270
mouseSelection = mouse;
1271
mouseSelection->grabMouseModel(viewer);
1274
void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode)
1284
mouseSelection = new PolyPickerSelection();
1287
mouseSelection = new RectangleSelection();
1290
mouseSelection = new RubberbandSelection();
1293
mouseSelection = new BoxZoomSelection();
1296
mouseSelection = new PolyClipSelection();
1303
mouseSelection->grabMouseModel(viewer);
1306
void NavigationStyle::abortSelection()
1309
if (mouseSelection) {
1310
mouseSelection->releaseMouseModel(true);
1311
delete mouseSelection;
1312
mouseSelection = nullptr;
1316
void NavigationStyle::stopSelection()
1319
if (mouseSelection) {
1320
mouseSelection->releaseMouseModel();
1321
delete mouseSelection;
1322
mouseSelection = nullptr;
1326
SbBool NavigationStyle::isSelecting() const
1328
return (mouseSelection ? true : false);
1331
const std::vector<SbVec2s>& NavigationStyle::getPolygon(SelectionRole* role) const
1334
*role = this->selectedRole;
1340
void NavigationStyle::addToLog(const SbVec2s pos, const SbTime time)
1344
assert (this->log.size > 2 && "mouse log too small!");
1346
if (this->log.historysize > 0 && pos == this->log.position[0]) {
1350
int lastidx = this->log.historysize;
1352
if (lastidx == this->log.size) { lastidx--; }
1354
assert(lastidx < this->log.size);
1355
for (int i = lastidx; i > 0; i--) {
1356
this->log.position[i] = this->log.position[i-1];
1357
this->log.time[i] = this->log.time[i-1];
1360
this->log.position[0] = pos;
1361
this->log.time[0] = time;
1362
if (this->log.historysize < this->log.size)
1363
this->log.historysize += 1;
1368
void NavigationStyle::clearLog()
1370
this->log.historysize = 0;
1373
void NavigationStyle::syncModifierKeys(const SoEvent * const ev)
1377
if (this->ctrldown != ev->wasCtrlDown()) {
1378
this->ctrldown = ev->wasCtrlDown();
1380
if (this->shiftdown != ev->wasShiftDown()) {
1381
this->shiftdown = ev->wasShiftDown();
1383
if (this->altdown != ev->wasAltDown()) {
1384
this->altdown = ev->wasAltDown();
1390
void NavigationStyle::setViewingMode(const ViewerMode newmode)
1392
const ViewerMode oldmode = this->currentmode;
1393
if (newmode == oldmode) {
1396
if (newmode == NavigationStyle::DRAGGING && rotationCenterFound) {
1397
viewer->changeRotationCenterPosition(rotationCenter);
1403
if (newmode == NavigationStyle::IDLE) {
1414
viewer->showRotationCenter(true);
1416
#if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403)
1417
findBoundingSphere();
1420
this->spinprojector->project(this->lastmouseposition);
1421
this->interactiveCountInc();
1426
this->interactiveCountInc();
1427
viewer->getSoRenderManager()->scheduleRedraw();
1432
setupPanningPlane(viewer->getSoRenderManager()->getCamera());
1433
this->interactiveCountInc();
1438
this->interactiveCountInc();
1443
this->interactiveCountInc();
1453
viewer->showRotationCenter(false);
1458
this->interactiveCountDec();
1465
viewer->setCursorRepresentation(newmode);
1466
this->currentmode = newmode;
1469
int NavigationStyle::getViewingMode() const
1471
return (int)this->currentmode;
1474
SbBool NavigationStyle::processEvent(const SoEvent * const ev)
1478
if (mouseSelection) {
1479
int hd=mouseSelection->handleEvent(ev,viewer->getSoRenderManager()->getViewportRegion());
1480
if (hd==AbstractMouseSelection::Continue||
1481
hd==AbstractMouseSelection::Restart) {
1484
else if (hd==AbstractMouseSelection::Finish) {
1485
pcPolygon = mouseSelection->getPositions();
1486
selectedRole = mouseSelection->selectedRole();
1487
delete mouseSelection;
1488
mouseSelection = nullptr;
1490
return NavigationStyle::processSoEvent(ev);
1492
else if (hd==AbstractMouseSelection::Cancel) {
1494
delete mouseSelection;
1495
mouseSelection = nullptr;
1497
return NavigationStyle::processSoEvent(ev);
1501
const ViewerMode curmode = this->currentmode;
1503
SbBool processed = false;
1504
processed = this->processSoEvent(ev);
1507
if ((curmode == NavigationStyle::SELECTION || curmode == NavigationStyle::IDLE)
1509
if (SoMouseButtonEvent::isButtonReleaseEvent(ev, SoMouseButtonEvent::BUTTON1)) {
1510
if (!ev->wasCtrlDown()) {
1511
Gui::Selection().clearSelection();
1519
SbBool NavigationStyle::processSoEvent(const SoEvent * const ev)
1521
bool processed = false;
1522
bool offeredtoViewerEventBase = false;
1525
if (ev->isOfType(SoMouseWheelEvent::getClassTypeId())) {
1526
auto const event = static_cast<const SoMouseWheelEvent *>(ev);
1527
processed = processWheelEvent(event);
1528
viewer->processSoEventBase(ev);
1529
offeredtoViewerEventBase = true;
1532
if (!processed && !offeredtoViewerEventBase) {
1533
processed = viewer->processSoEventBase(ev);
1539
void NavigationStyle::syncWithEvent(const SoEvent * const ev)
1544
if (this->isSeekMode()) {
1548
const SoType type(ev->getTypeId());
1552
syncModifierKeys(ev);
1555
if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
1556
auto const event = static_cast<const SoKeyboardEvent *>(ev);
1557
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
1558
switch (event->getKey()) {
1559
case SoKeyboardEvent::LEFT_CONTROL:
1560
case SoKeyboardEvent::RIGHT_CONTROL:
1561
this->ctrldown = press;
1563
case SoKeyboardEvent::LEFT_SHIFT:
1564
case SoKeyboardEvent::RIGHT_SHIFT:
1565
this->shiftdown = press;
1567
case SoKeyboardEvent::LEFT_ALT:
1568
case SoKeyboardEvent::RIGHT_ALT:
1569
this->altdown = press;
1577
if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
1578
auto const event = static_cast<const SoMouseButtonEvent *>(ev);
1579
const int button = event->getButton();
1580
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
1584
case SoMouseButtonEvent::BUTTON1:
1585
this->button1down = press;
1587
case SoMouseButtonEvent::BUTTON2:
1588
this->button2down = press;
1590
case SoMouseButtonEvent::BUTTON3:
1591
this->button3down = press;
1599
SbBool NavigationStyle::processMotionEvent(const SoMotion3Event * const ev)
1601
SoCamera * const camera = viewer->getSoRenderManager()->getCamera();
1605
SbViewVolume volume(camera->getViewVolume());
1606
SbVec3f center(volume.getSightPoint(camera->focalDistance.getValue()));
1607
float scale(volume.getWorldToScreenScale(center, 1.0));
1608
float translationFactor = scale * .0001;
1610
SbVec3f dir = ev->getTranslation();
1612
if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){
1613
auto oCam = static_cast<SoOrthographicCamera *>(camera);
1614
oCam->scaleHeight(1.0 + (dir[2] * 0.0001));
1618
SbRotation newRotation(ev->getRotation() * camera->orientation.getValue());
1619
SbVec3f newPosition, newDirection;
1620
newRotation.multVec(SbVec3f(0.0, 0.0, -1.0), newDirection);
1621
newPosition = center - (newDirection * camera->focalDistance.getValue());
1623
camera->orientation.setValue(newRotation);
1624
camera->orientation.getValue().multVec(dir,dir);
1625
camera->position = newPosition + (dir * translationFactor);
1630
SbBool NavigationStyle::processKeyboardEvent(const SoKeyboardEvent * const event)
1632
SbBool processed = false;
1633
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
1634
switch (event->getKey()) {
1635
case SoKeyboardEvent::LEFT_CONTROL:
1636
case SoKeyboardEvent::RIGHT_CONTROL:
1637
this->ctrldown = press;
1639
case SoKeyboardEvent::LEFT_SHIFT:
1640
case SoKeyboardEvent::RIGHT_SHIFT:
1641
this->shiftdown = press;
1643
case SoKeyboardEvent::LEFT_ALT:
1644
case SoKeyboardEvent::RIGHT_ALT:
1645
this->altdown = press;
1647
case SoKeyboardEvent::S:
1648
case SoKeyboardEvent::HOME:
1649
case SoKeyboardEvent::LEFT_ARROW:
1650
case SoKeyboardEvent::UP_ARROW:
1651
case SoKeyboardEvent::RIGHT_ARROW:
1652
case SoKeyboardEvent::DOWN_ARROW:
1653
if (!this->isViewing())
1654
this->setViewing(true);
1656
case SoKeyboardEvent::PAGE_UP:
1659
const SbVec2f posn = normalizePixelPos(event->getPosition());
1660
doZoom(viewer->getSoRenderManager()->getCamera(), getDelta(), posn);
1663
case SoKeyboardEvent::PAGE_DOWN:
1666
const SbVec2f posn = normalizePixelPos(event->getPosition());
1667
doZoom(viewer->getSoRenderManager()->getCamera(), -getDelta(), posn);
1677
SbBool NavigationStyle::processClickEvent(const SoMouseButtonEvent * const event)
1681
SbBool processed = false;
1682
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
1684
SbTime tmp = (event->getTime() - mouseDownConsumedEvent.getTime());
1685
float dci = (float)QApplication::doubleClickInterval()/1000.0f;
1687
if (tmp.getValue() < dci) {
1688
mouseDownConsumedEvent = *event;
1689
mouseDownConsumedEvent.setTime(event->getTime());
1693
mouseDownConsumedEvent.setTime(event->getTime());
1696
mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
1700
if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) {
1702
NavigationStyle::processSoEvent(&mouseDownConsumedEvent);
1703
mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
1710
SbBool NavigationStyle::processWheelEvent(const SoMouseWheelEvent * const event)
1712
const SbVec2s pos(event->getPosition());
1713
const SbVec2f posn = normalizePixelPos(pos);
1716
doZoom(viewer->getSoRenderManager()->getCamera(),
1717
event->getDelta(), posn);
1721
void NavigationStyle::setPopupMenuEnabled(const SbBool on)
1723
this->menuenabled = on;
1726
SbBool NavigationStyle::isPopupMenuEnabled() const
1728
return this->menuenabled;
1731
void NavigationStyle::openPopupMenu(const SbVec2s& position)
1736
Gui::Application::Instance->setupContextMenu("View", &view);
1738
auto contextMenu = new QMenu(viewer->getGLWidget());
1739
MenuManager::getInstance()->setupContextMenu(&view, *contextMenu);
1740
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
1742
auto navMenu = contextMenu->addMenu(QObject::tr("Navigation styles"));
1743
auto navMenuGroup = new QActionGroup(navMenu);
1746
const std::map<Base::Type, std::string> styles = UserNavigationStyle::getUserFriendlyNames();
1747
for (const auto &style : styles) {
1748
const QString name = QApplication::translate(style.first.getName(), style.second.c_str());
1749
QAction *item = navMenuGroup->addAction(name);
1750
navMenu->addAction(item);
1751
item->setCheckable(true);
1753
if (const Base::Type item_style = style.first; item_style != this->getTypeId()) {
1754
auto triggeredFun = [this, item_style](){
1755
QWidget *widget = viewer->getWidget();
1756
while (widget && !widget->inherits("Gui::View3DInventor"))
1757
widget = widget->parentWidget();
1760
QEvent *ns_event = new NavigationStyleEvent(item_style);
1761
QApplication::postEvent(widget, ns_event);
1764
item->connect(item, &QAction::triggered, triggeredFun);
1766
item->setChecked(true);
1769
contextMenu->popup(QCursor::pos());
1774
TYPESYSTEM_SOURCE_ABSTRACT(Gui::UserNavigationStyle,Gui::NavigationStyle)
1776
std::string UserNavigationStyle::userFriendlyName() const
1778
std::string name = this->getTypeId().getName();
1780
std::size_t pos = name.rfind("::");
1781
if (pos != std::string::npos)
1782
name = name.substr(pos + 2);
1785
pos = name.find("NavigationStyle");
1786
if (pos != std::string::npos)
1787
name = name.substr(0, pos);
1791
std::map<Base::Type, std::string> UserNavigationStyle::getUserFriendlyNames()
1793
std::map<Base::Type, std::string> names;
1794
std::vector<Base::Type> types;
1795
Base::Type::getAllDerivedFrom(UserNavigationStyle::getClassTypeId(), types);
1797
for (auto & type : types) {
1798
if (type != UserNavigationStyle::getClassTypeId()) {
1799
std::unique_ptr<UserNavigationStyle> inst(static_cast<UserNavigationStyle*>(type.createInstance()));
1801
names[type] = inst->userFriendlyName();