Revert "Gui: Refactor navigation animations"

This commit is contained in:
Yorik van Havre
2023-09-26 19:44:16 +02:00
committed by GitHub
parent 097b60a612
commit f1fb45960d
15 changed files with 352 additions and 674 deletions

View File

@@ -45,13 +45,40 @@
#include "Application.h"
#include "MenuManager.h"
#include "MouseSelection.h"
#include "NavigationAnimator.h"
#include "NavigationAnimation.h"
#include "SoMouseWheelEvent.h"
#include "View3DInventorViewer.h"
using namespace Gui;
namespace Gui {
struct NavigationStyleP {
int animationsteps;
int animationdelta;
SbVec3f focal1, focal2;
SbVec3f rotationCenter;
SbBool rotationCenterFound;
NavigationStyle::RotationCenterModes rotationCenterMode;
SbRotation endRotation;
SoTimerSensor * animsensor;
float sensitivity;
SbBool resetcursorpos;
NavigationStyleP()
{
this->animationsteps = 0;
this->animationdelta = 0;
this->animsensor = nullptr;
this->sensitivity = 2.0f;
this->resetcursorpos = false;
this->rotationCenterFound = false;
this->rotationCenterMode = NavigationStyle::RotationCenterMode::ScenePointAtCursor |
NavigationStyle::RotationCenterMode::FocalPointAtCursor;
}
static void viewAnimationCB(void * data, SoSensor * sensor);
};
}
class FCSphereSheetProjector : public SbSphereSheetProjector {
using inherited = SbSphereSheetProjector;
@@ -157,19 +184,25 @@ const Base::Type& NavigationStyleEvent::style() const
return t;
}
#define PRIVATE(ptr) (ptr->pimpl)
#define PUBLIC(ptr) (ptr->pub)
TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStyle,Base::BaseClass)
NavigationStyle::NavigationStyle() : viewer(nullptr), mouseSelection(nullptr)
{
this->rotationCenterMode = NavigationStyle::RotationCenterMode::ScenePointAtCursor
| NavigationStyle::RotationCenterMode::FocalPointAtCursor;
PRIVATE(this) = new NavigationStyleP();
PRIVATE(this)->animsensor = new SoTimerSensor(NavigationStyleP::viewAnimationCB, this);
initialize();
}
NavigationStyle::~NavigationStyle()
{
finalize();
delete this->animator;
if (PRIVATE(this)->animsensor->isScheduled())
PRIVATE(this)->animsensor->unschedule();
delete PRIVATE(this)->animsensor;
delete PRIVATE(this);
}
NavigationStyle& NavigationStyle::operator = (const NavigationStyle& ns)
@@ -189,15 +222,12 @@ void NavigationStyle::setViewer(View3DInventorViewer* view)
void NavigationStyle::initialize()
{
this->animator = new NavigationAnimator();
this->sensitivity = 2.0f;
this->resetcursorpos = false;
this->currentmode = NavigationStyle::IDLE;
this->prevRedrawTime = SbTime::getTimeOfDay();
this->spinanimatingallowed = true;
this->spinsamplecounter = 0;
this->spinincrement = SbRotation::identity();
this->rotationCenterFound = false;
this->spinRotation.setValue(SbVec3f(0, 0, -1), 0);
// FIXME: use a smaller sphere than the default one to have a larger
// area close to the borders that gives us "z-axis rotation"?
@@ -323,71 +353,171 @@ SbBool NavigationStyle::lookAtPoint(const SbVec2s screenpos)
SbVec3f hitpoint;
hitpoint = picked->getPoint();
this->rotationCenterFound = false;
translateCamera(hitpoint - getFocalPoint());
lookAtPoint(hitpoint);
return true;
}
SoCamera* NavigationStyle::getCamera() const
void NavigationStyle::lookAtPoint(const SbVec3f& pos)
{
return this->viewer->getCamera();
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
if (!cam)
return;
PRIVATE(this)->rotationCenterFound = false;
// Find global coordinates of focal point.
SbVec3f direction;
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
PRIVATE(this)->focal1 = cam->position.getValue() +
cam->focalDistance.getValue() * direction;
PRIVATE(this)->focal2 = pos;
// avoid to interfere with spinning (fixes #3101462)
if (this->isAnimating())
this->stopAnimating();
if (PRIVATE(this)->animsensor->isScheduled()) {
PRIVATE(this)->animsensor->unschedule();
this->interactiveCountDec();
}
if (isAnimationEnabled()) {
SbRotation cam_rot = cam->orientation.getValue();
// get the amount of movement
SbVec3f dir1 = direction, dir2;
dir2 = pos - cam->position.getValue();
dir2.normalize();
SbRotation rot(dir1, dir2);
float val = 0.5f*(1.0f + dir1.dot(dir2)); // value in range [0,1]
int div = (int)(val * 20.0f);
int steps = 20-div; // do it with max. 20 steps
// check whether a movement is required
if (steps > 0) {
PRIVATE(this)->endRotation = cam_rot;
this->spinRotation = cam_rot;
PRIVATE(this)->animationsteps = 5;
PRIVATE(this)->animationdelta = std::max<int>(100/steps, 5);
PRIVATE(this)->animsensor->setBaseTime(SbTime::getTimeOfDay());
PRIVATE(this)->animsensor->schedule();
this->interactiveCountInc();
}
else {
// set to the given position
SbVec3f direction;
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = pos - cam->focalDistance.getValue() * direction;
}
}
else {
// set to the given position
SbVec3f direction;
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = pos - cam->focalDistance.getValue() * direction;
}
}
void NavigationStyle::setCameraOrientation(const SbRotation& orientation, SbBool moveToCenter)
void NavigationStyle::setCameraOrientation(const SbRotation& rot, SbBool moveToCenter)
{
SoCamera* camera = getCamera();
if (!camera)
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
if (!cam)
return;
animator->stop();
SbVec3f focalPoint = getFocalPoint();
SbVec3f translation(0, 0, 0);
// Find global coordinates of focal point.
SbVec3f direction;
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
PRIVATE(this)->focal1 = cam->position.getValue() +
cam->focalDistance.getValue() * direction;
PRIVATE(this)->focal2 = PRIVATE(this)->focal1;
if (moveToCenter) {
SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
action.apply(viewer->getSceneGraph());
SbBox3f box = action.getBoundingBox();
if (!box.isEmpty()) {
translation = box.getCenter() - focalPoint;
rot.multVec(SbVec3f(0, 0, -1), direction);
//float s = (this->focal1 - box.getCenter()).dot(direction);
//this->focal2 = box.getCenter() + s * direction;
// setting the center of the overall bounding box as the future focal point
// seems to be a satisfactory solution
PRIVATE(this)->focal2 = box.getCenter();
}
}
// Start an animation or set the pose directly
// avoid to interfere with spinning (fixes #3101462)
if (this->isAnimating())
this->stopAnimating();
if (PRIVATE(this)->animsensor->isScheduled()) {
PRIVATE(this)->animsensor->unschedule();
this->interactiveCountDec();
}
if (isAnimationEnabled()) {
viewer->startAnimation(orientation, focalPoint, translation);
// get the amount of movement
SbVec3f dir1, dir2;
SbRotation cam_rot = cam->orientation.getValue();
cam_rot.multVec(SbVec3f(0, 0, -1), dir1);
rot.multVec(SbVec3f(0, 0, -1), dir2);
float val = 0.5f*(1.0f + dir1.dot(dir2)); // value in range [0,1]
int div = (int)(val * 20.0f);
int steps = 20-div; // do it with max. 20 steps
// check whether a movement is required
if (steps > 0) {
PRIVATE(this)->endRotation = rot; // this is the final camera orientation
this->spinRotation = cam_rot;
PRIVATE(this)->animationsteps = 5;
PRIVATE(this)->animationdelta = std::max<int>(100/steps, 5);
PRIVATE(this)->animsensor->setBaseTime(SbTime::getTimeOfDay());
PRIVATE(this)->animsensor->schedule();
this->interactiveCountInc();
}
else {
// due to possible round-off errors make sure that the
// exact orientation is set
cam->orientation.setValue(rot);
cam->position = PRIVATE(this)->focal2 - cam->focalDistance.getValue() * direction;
}
}
else {
// Distance from rotation center to camera position in camera coordinate system
SbVec3f rotationCenterDistanceCam = camera->focalDistance.getValue() * SbVec3f(0, 0, 1);
// Set to the given orientation
camera->orientation = orientation;
// Distance from rotation center to new camera position in global coordinate system
SbVec3f newRotationCenterDistance;
camera->orientation.getValue().multVec(rotationCenterDistanceCam, newRotationCenterDistance);
// Reposition camera so the rotation center stays in the same place
// Optionally add translation to move to center
camera->position = focalPoint + newRotationCenterDistance + translation;
// set to the given rotation
cam->orientation.setValue(rot);
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = PRIVATE(this)->focal2 - cam->focalDistance.getValue() * direction;
}
}
void NavigationStyle::translateCamera(const SbVec3f& translation)
void NavigationStyleP::viewAnimationCB(void * data, SoSensor * sensor)
{
SoCamera* camera = getCamera();
if (!camera)
return;
Q_UNUSED(sensor);
auto that = static_cast<NavigationStyle*>(data);
if (PRIVATE(that)->animationsteps > 0) {
// here the camera rotates from the current rotation to a given
// rotation (e.g. the standard views). To get this movement animated
// we calculate an interpolated rotation and update the view after
// each step
float step = std::min<float>((float)PRIVATE(that)->animationsteps/100.0f, 1.0f);
SbRotation slerp = SbRotation::slerp(that->spinRotation, PRIVATE(that)->endRotation, step);
SbVec3f focalpoint = (1.0f-step)*PRIVATE(that)->focal1 + step*PRIVATE(that)->focal2;
SoCamera* cam = that->viewer->getSoRenderManager()->getCamera();
if (!cam) // no camera
return;
animator->stop();
SbVec3f direction;
cam->orientation.setValue(slerp);
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = focalpoint - cam->focalDistance.getValue() * direction;
// Start an animation or set the pose directly
if (isAnimationEnabled()) {
viewer->startAnimation(camera->orientation.getValue(), SbVec3f(0, 0, 0), translation);
}
else {
camera->position = camera->position.getValue() + translation;
PRIVATE(that)->animationsteps += PRIVATE(that)->animationdelta;
if (PRIVATE(that)->animationsteps > 100) {
// now we have reached the end of the movement
PRIVATE(that)->animationsteps=0;
PRIVATE(that)->animsensor->unschedule();
that->interactiveCountDec();
// set to the actual given rotation
cam->orientation.setValue(PRIVATE(that)->endRotation);
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = PRIVATE(that)->focal2 - cam->focalDistance.getValue() * direction;
}
}
}
@@ -474,41 +604,29 @@ void NavigationStyle::viewAll()
}
}
/** Rotate the camera by the given amount, then reposition it so we're still pointing at the same
* focal point
/** Rotate the camera by the given amount, then reposition it so we're
* still pointing at the same focal point.
*/
void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation)
void NavigationStyle::reorientCamera(SoCamera * cam, const SbRotation & rot)
{
reorientCamera(camera, rotation, getFocalPoint());
}
/** Rotate the camera by the given amount, then reposition it so the rotation center stays in the
* same place
*/
void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation, const SbVec3f& rotationCenter)
{
if (!camera) {
if (!cam)
return;
}
// Distance from rotation center to camera position in camera coordinate system
SbVec3f rotationCenterDistanceCam;
camera->orientation.getValue().inverse().multVec(camera->position.getValue() - rotationCenter, rotationCenterDistanceCam);
// Set new orientation value by accumulating the new rotation
camera->orientation = rotation * camera->orientation.getValue();
// Find global coordinates of focal point.
SbVec3f direction;
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
SbVec3f focalpoint = cam->position.getValue() +
cam->focalDistance.getValue() * direction;
// Set new orientation value by accumulating the new rotation.
cam->orientation = rot * cam->orientation.getValue();
// Fix issue with near clipping in orthogonal view
if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
camera->focalDistance = static_cast<SoOrthographicCamera*>(camera)->height;
if (cam->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
cam->focalDistance = static_cast<SoOrthographicCamera*>(cam)->height;
}
// Distance from rotation center to new camera position in global coordinate system
SbVec3f newRotationCenterDistance;
camera->orientation.getValue().multVec(rotationCenterDistanceCam, newRotationCenterDistance);
// Reposition camera so the rotation center stays in the same place
camera->position = rotationCenter + newRotationCenterDistance;
// Reposition camera so we are still pointing at the same old focal point.
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = focalpoint - cam->focalDistance.getValue() * direction;
}
void NavigationStyle::panCamera(SoCamera * cam, float aspectratio, const SbPlane & panplane,
@@ -566,7 +684,7 @@ void NavigationStyle::panToCenter(const SbPlane & pplane, const SbVec2f & currpo
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
float ratio = vp.getViewportAspectRatio();
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, pplane, SbVec2f(0.5,0.5), currpos);
this->rotationCenterFound = false;
PRIVATE(this)->rotationCenterFound = false;
}
/** Dependent on the camera type this will either shrink or expand the
@@ -577,9 +695,6 @@ void NavigationStyle::zoom(SoCamera * cam, float diffvalue)
{
if (!cam) // can happen for empty scenegraph
return;
animator->stop();
SoType t = cam->getTypeId();
SbName tname = t.getName();
@@ -747,14 +862,14 @@ void NavigationStyle::doRotate(SoCamera * camera, float angle, const SbVec2f& po
SbVec3f NavigationStyle::getRotationCenter(SbBool& found) const
{
found = this->rotationCenterFound;
return this->rotationCenter;
found = PRIVATE(this)->rotationCenterFound;
return PRIVATE(this)->rotationCenter;
}
void NavigationStyle::setRotationCenter(const SbVec3f& cnt)
{
this->rotationCenter = cnt;
this->rotationCenterFound = true;
PRIVATE(this)->rotationCenter = cnt;
PRIVATE(this)->rotationCenterFound = true;
}
SbVec3f NavigationStyle::getFocalPoint() const
@@ -786,8 +901,8 @@ void NavigationStyle::spin(const SbVec2f & pointerpos)
lastpos[0] = float(this->log.position[1][0]) / float(std::max((int)(glsize[0]-1), 1));
lastpos[1] = float(this->log.position[1][1]) / float(std::max((int)(glsize[1]-1), 1));
if (this->rotationCenterMode && this->rotationCenterFound) {
SbVec3f hitpoint = this->rotationCenter;
if (PRIVATE(this)->rotationCenterMode && PRIVATE(this)->rotationCenterFound) {
SbVec3f hitpoint = PRIVATE(this)->rotationCenter;
// set to the given position
SbVec3f direction;
@@ -814,7 +929,7 @@ void NavigationStyle::spin(const SbVec2f & pointerpos)
r.invert();
this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r);
if (this->rotationCenterMode && this->rotationCenterFound) {
if (PRIVATE(this)->rotationCenterMode && PRIVATE(this)->rotationCenterFound) {
float ratio = vp.getViewportAspectRatio();
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(vp.getViewportAspectRatio());
SbPlane panplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
@@ -900,7 +1015,7 @@ SbBool NavigationStyle::doSpin()
float radians;
rot.getValue(axis, radians);
if ((radians > 0.01f) && (deltatime < 0.300)) {
viewer->startSpinningAnimation(axis, radians * 5);
this->spinRotation = rot;
return true;
}
}
@@ -915,14 +1030,14 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
this->localPos = ev->getPosition();
// mode is WindowCenter
if (!this->rotationCenterMode) {
if (!PRIVATE(this)->rotationCenterMode) {
setRotationCenter(getFocalPoint());
}
//Option to get point on model (slow) or always on focal plane (fast)
//
// mode is ScenePointAtCursor to get exact point if possible
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::ScenePointAtCursor) {
if (PRIVATE(this)->rotationCenterMode & NavigationStyle::RotationCenterMode::ScenePointAtCursor) {
SoRayPickAction rpaction(viewer->getSoRenderManager()->getViewportRegion());
rpaction.setPoint(this->localPos);
rpaction.setRadius(viewer->getPickRadius());
@@ -936,7 +1051,7 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
}
// mode is FocalPointAtCursor or a ScenePointAtCursor failed
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::FocalPointAtCursor) {
if (PRIVATE(this)->rotationCenterMode & NavigationStyle::RotationCenterMode::FocalPointAtCursor) {
// get the intersection point of the ray and the focal plane
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
float ratio = vp.getViewportAspectRatio();
@@ -957,7 +1072,7 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
}
// mode is BoundingBoxCenter or a ScenePointAtCursor failed
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::BoundingBoxCenter) {
if (PRIVATE(this)->rotationCenterMode & NavigationStyle::RotationCenterMode::BoundingBoxCenter) {
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
float ratio = vp.getViewportAspectRatio();
@@ -1013,6 +1128,20 @@ void NavigationStyle::moveCursorPosition()
}
}
void NavigationStyle::updateAnimation()
{
SbTime now = SbTime::getTimeOfDay();
double secs = now.getValue() - prevRedrawTime.getValue();
this->prevRedrawTime = now;
if (this->isAnimating()) {
// here the camera rotates around a fix axis
SbRotation deltaRotation = this->spinRotation;
deltaRotation.scaleAngle(secs * 5.0);
this->reorientCamera(viewer->getSoRenderManager()->getCamera(), deltaRotation);
}
}
void NavigationStyle::redraw()
{
if (mouseSelection)
@@ -1039,7 +1168,7 @@ void
NavigationStyle::setAnimationEnabled(const SbBool enable)
{
this->spinanimatingallowed = enable;
if (!enable && this->isAnimating()) { animator->stop(); }
if (!enable && this->isAnimating()) { this->stopAnimating(); }
}
/*!
@@ -1062,29 +1191,52 @@ SbBool NavigationStyle::isAnimating() const
return this->currentmode == NavigationStyle::SPINNING;
}
NavigationAnimator* NavigationStyle::getAnimator() const
/*!
* Starts programmatically the viewer in animation mode. The given axis direction
* is always in screen coordinates, not in world coordinates.
*/
void NavigationStyle::startAnimating(const SbVec3f& axis, float velocity)
{
return this->animator;
if (!isAnimationEnabled())
return;
this->prevRedrawTime = SbTime::getTimeOfDay();
this->spinincrement = SbRotation::identity();
SbRotation rot;
rot.setValue(axis, velocity);
this->setViewing(true);
this->setViewingMode(NavigationStyle::SPINNING);
this->spinRotation = rot;
}
void NavigationStyle::stopAnimating()
{
if (this->currentmode != NavigationStyle::SPINNING) {
return;
}
this->setViewingMode(this->isViewing() ?
NavigationStyle::IDLE : NavigationStyle::INTERACT);
}
void NavigationStyle::setSensitivity(float val)
{
this->sensitivity = val;
PRIVATE(this)->sensitivity = val;
}
float NavigationStyle::getSensitivity() const
{
return this->sensitivity;
return PRIVATE(this)->sensitivity;
}
void NavigationStyle::setResetCursorPosition(SbBool on)
{
this->resetcursorpos = on;
PRIVATE(this)->resetcursorpos = on;
}
SbBool NavigationStyle::isResetCursorPosition() const
{
return this->resetcursorpos;
return PRIVATE(this)->resetcursorpos;
}
void NavigationStyle::setZoomInverted(SbBool on)
@@ -1114,12 +1266,12 @@ SbBool NavigationStyle::isZoomAtCursor() const
void NavigationStyle::setRotationCenterMode(NavigationStyle::RotationCenterModes mode)
{
this->rotationCenterMode = mode;
PRIVATE(this)->rotationCenterMode = mode;
}
NavigationStyle::RotationCenterModes NavigationStyle::getRotationCenterMode() const
{
return this->rotationCenterMode;
return PRIVATE(this)->rotationCenterMode;
}
void NavigationStyle::startSelection(AbstractMouseSelection* mouse)
@@ -1263,7 +1415,6 @@ void NavigationStyle::setViewingMode(const ViewerMode newmode)
case DRAGGING:
// Set up initial projection point for the projector object when
// first starting a drag operation.
animator->stop();
viewer->showRotationCenter(true);
this->spinprojector->project(this->lastmouseposition);
this->interactiveCountInc();
@@ -1277,18 +1428,15 @@ void NavigationStyle::setViewingMode(const ViewerMode newmode)
break;
case PANNING:
animator->stop();
pan(viewer->getSoRenderManager()->getCamera());
this->interactiveCountInc();
break;
case ZOOMING:
animator->stop();
this->interactiveCountInc();
break;
case BOXZOOM:
animator->stop();
this->interactiveCountInc();
break;