Merge pull request #9446 from Rexbas/navigation-animation

Gui: Refactor navigation animations
This commit is contained in:
Yorik van Havre
2023-09-25 18:15:43 +02:00
committed by GitHub
15 changed files with 677 additions and 355 deletions

View File

@@ -833,6 +833,8 @@ SET(View3D_CPP_SRCS
View3DPy.cpp
View3DViewerPy.cpp
NaviCube.cpp
NavigationAnimator.cpp
NavigationAnimation.cpp
)
SET(View3D_SRCS
${View3D_CPP_SRCS}
@@ -855,6 +857,8 @@ SET(View3D_SRCS
CoinRiftWidget.h
View3DViewerPy.h
NaviCube.h
NavigationAnimator.h
NavigationAnimation.h
)
SOURCE_GROUP("View3D" FILES ${View3D_SRCS})

View File

@@ -91,7 +91,7 @@ void DemoMode::reset()
view->getViewer()->stopAnimating();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/View");
hGrp->Notify("UseAutoRotation");
hGrp->Notify("UseNavigationAnimations");
}
void DemoMode::accept()
@@ -272,8 +272,9 @@ void DemoMode::startAnimation(Gui::View3DInventor* view)
{
if (!view->getViewer()->isAnimationEnabled())
view->getViewer()->setAnimationEnabled(true);
view->getViewer()->startAnimating(getDirection(view),
getSpeed(ui->speedSlider->value()));
view->getViewer()->startSpinningAnimation(getDirection(view),
getSpeed(ui->speedSlider->value()));
}
void DemoMode::onTimerCheckToggled(bool on)

View File

@@ -0,0 +1,145 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <Rexbas@proton.me> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#include "NavigationAnimation.h"
#include <Inventor/nodes/SoCamera.h>
using namespace Gui;
NavigationAnimation::NavigationAnimation(NavigationStyle* navigation)
: navigation(navigation), started(false)
{}
void NavigationAnimation::startAnimation(QAbstractAnimation::DeletionPolicy policy)
{
started = true;
QAbstractAnimation::start(policy);
}
void NavigationAnimation::updateCurrentValue(const QVariant& value)
{
if (!started) {
return;
}
update(value);
}
void NavigationAnimation::stopAnimation()
{
QAbstractAnimation::stop();
}
FixedTimeAnimation::FixedTimeAnimation(NavigationStyle* navigation, const SbRotation& orientation,
const SbVec3f& rotationCenter, const SbVec3f& translation,
int duration)
: NavigationAnimation(navigation)
, targetOrientation(orientation)
, targetTranslation(translation)
, rotationCenter(rotationCenter)
{
setDuration(duration);
setStartValue(0.0);
setEndValue(duration * 1.0);
}
void FixedTimeAnimation::initialize()
{
prevAngle = 0;
prevTranslation = SbVec3f(0, 0, 0);
// Find an axis and angle to rotate from the camera orientation to the target orientation using post-multiplication
SbVec3f rotationAxisPost;
float angle;
SbRotation(navigation->getCamera()->orientation.getValue().inverse() * targetOrientation).getValue(rotationAxisPost, angle);
if (angle > M_PI) {
angle -= 2 * M_PI;
}
// Convert post-multiplication axis to a pre-multiplication axis
navigation->getCamera()->orientation.getValue().inverse().multVec(rotationAxisPost, rotationAxis);
angularVelocity = angle / duration();
linearVelocity = targetTranslation / duration();
}
/**
* @param value The elapsed time
*/
void FixedTimeAnimation::update(const QVariant& value)
{
float angle = value.toFloat() * angularVelocity;
SbVec3f translation = value.toFloat() * linearVelocity;
SbRotation rotation(rotationAxis, angle - prevAngle);
navigation->reorientCamera(navigation->getCamera(), rotation, rotationCenter);
navigation->getCamera()->position = navigation->getCamera()->position.getValue() + translation - prevTranslation;
prevAngle = angle;
prevTranslation = translation;
}
/**
* @param navigation The navigation style
* @param axis The rotation axis in screen coordinates
* @param velocity The angular velocity in radians per second
*/
SpinningAnimation::SpinningAnimation(NavigationStyle* navigation, const SbVec3f& axis,
float velocity)
: NavigationAnimation(navigation)
, rotationAxis(axis)
{
setDuration((2 * M_PI / velocity) * 1000.0);
setStartValue(0.0);
setEndValue(2 * M_PI);
setLoopCount(-1);
}
void SpinningAnimation::initialize()
{
prevAngle = 0;
navigation->setViewing(true);
navigation->setViewingMode(NavigationStyle::SPINNING);
}
/**
* @param value The angle in radians
*/
void SpinningAnimation::update(const QVariant& value)
{
SbRotation deltaRotation = SbRotation(rotationAxis, value.toFloat() - prevAngle);
navigation->reorientCamera(navigation->getCamera(), deltaRotation);
prevAngle = value.toFloat();
}
void SpinningAnimation::stopAnimation()
{
NavigationAnimation::stopAnimation();
if (navigation->getViewingMode() != NavigationStyle::SPINNING) {
return;
}
navigation->setViewingMode(navigation->isViewing() ? NavigationStyle::IDLE : NavigationStyle::INTERACT);
}

View File

@@ -0,0 +1,96 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <Rexbas@proton.me> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef GUI_NAVIGATIONANIMATION_H
#define GUI_NAVIGATIONANIMATION_H
#include "NavigationStyle.h"
#include <Inventor/SbRotation.h>
#include <Inventor/SbVec3f.h>
#include <QVariantAnimation>
namespace Gui
{
class GuiExport NavigationAnimation : protected QVariantAnimation
{
public:
explicit NavigationAnimation(NavigationStyle* navigation);
protected:
NavigationStyle* navigation;
virtual void initialize() = 0;
virtual void update(const QVariant& value) = 0;
virtual void stopAnimation();
private:
bool started;
void startAnimation(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped);
void updateCurrentValue(const QVariant& value) override;
friend class NavigationAnimator;
};
class GuiExport FixedTimeAnimation : public NavigationAnimation
{
public:
explicit FixedTimeAnimation(NavigationStyle* navigation, const SbRotation& orientation,
const SbVec3f& rotationCenter, const SbVec3f& translation,
int duration);
private:
float angularVelocity; // [rad/ms]
SbVec3f linearVelocity; // [/ms]
SbRotation targetOrientation;
SbVec3f targetTranslation;
float prevAngle;
SbVec3f prevTranslation;
SbVec3f rotationCenter;
SbVec3f rotationAxis;
void initialize() override;
void update(const QVariant& value) override;
};
class GuiExport SpinningAnimation : public NavigationAnimation
{
public:
explicit SpinningAnimation(NavigationStyle* navigation, const SbVec3f& axis, float velocity);
private:
SbVec3f rotationAxis;
float prevAngle;
void initialize() override;
void update(const QVariant& value) override;
void stopAnimation() override;
};
} // namespace Gui
#endif // GUI_NAVIGATIONANIMATION_H

View File

@@ -0,0 +1,99 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <Rexbas@proton.me> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#include "NavigationAnimator.h"
#include "NavigationAnimation.h"
#include <QEventLoop>
using namespace Gui;
NavigationAnimator::NavigationAnimator()
: activeAnimation(nullptr)
{}
NavigationAnimator::~NavigationAnimator()
{
stop();
}
/**
* @brief Start an animation
*
* @param animation The animation to start
*/
void NavigationAnimator::start(const std::shared_ptr<NavigationAnimation>& animation)
{
stop();
activeAnimation = animation;
activeAnimation->initialize();
connect(activeAnimation.get(), &NavigationAnimation::finished, this, &NavigationAnimator::reset);
activeAnimation->startAnimation();
}
/**
* @brief Start an animation and wait for it to finish
*
* @param animation The animation to start
* @return True if the animation finished, false if interrupted
*/
bool NavigationAnimator::startAndWait(const std::shared_ptr<NavigationAnimation>& animation)
{
stop();
bool finished = true;
QEventLoop loop;
loop.connect(animation.get(), &NavigationAnimation::finished,
[&loop, &finished, &animation]() { // clazy:exclude=lambda-in-connect
if (animation->state() == QAbstractAnimation::State::Running) {
finished = false;
}
loop.quit();
});
start(animation);
loop.exec();
return finished;
}
/**
* @brief Stops an active animation
*/
void NavigationAnimator::stop()
{
if (activeAnimation != nullptr && activeAnimation->state() != QAbstractAnimation::State::Stopped) {
Q_EMIT activeAnimation->finished();
}
}
/**
* @brief Stops the animation and releases ownership of the animation
*
* Is called when the animation finished() signal is received which is triggered when the animation
* is finished or when the animation is interrupted by NavigationAnimator::stop()
*/
void NavigationAnimator::reset() {
activeAnimation->started = false;
activeAnimation->stopAnimation();
activeAnimation.reset();
}

View File

@@ -0,0 +1,55 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <Rexbas@proton.me> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef GUI_NAVIGATIONANIMATOR_H
#define GUI_NAVIGATIONANIMATOR_H
#include "NavigationStyle.h"
#include <QObject>
#include <memory>
namespace Gui
{
class NavigationAnimation;
class GuiExport NavigationAnimator : public QObject
{
Q_OBJECT
public:
NavigationAnimator();
~NavigationAnimator();
void start(const std::shared_ptr<NavigationAnimation>& animation);
bool startAndWait(const std::shared_ptr<NavigationAnimation>& animation);
void stop();
private Q_SLOTS:
void reset();
private:
std::shared_ptr<NavigationAnimation> activeAnimation;
};
} // namespace Gui
#endif // GUI_NAVIGATIONANIMATOR_H

View File

@@ -45,40 +45,13 @@
#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;
@@ -184,25 +157,19 @@ 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)
{
PRIVATE(this) = new NavigationStyleP();
PRIVATE(this)->animsensor = new SoTimerSensor(NavigationStyleP::viewAnimationCB, this);
this->rotationCenterMode = NavigationStyle::RotationCenterMode::ScenePointAtCursor
| NavigationStyle::RotationCenterMode::FocalPointAtCursor;
initialize();
}
NavigationStyle::~NavigationStyle()
{
finalize();
if (PRIVATE(this)->animsensor->isScheduled())
PRIVATE(this)->animsensor->unschedule();
delete PRIVATE(this)->animsensor;
delete PRIVATE(this);
delete this->animator;
}
NavigationStyle& NavigationStyle::operator = (const NavigationStyle& ns)
@@ -222,12 +189,15 @@ 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->spinRotation.setValue(SbVec3f(0, 0, -1), 0);
this->rotationCenterFound = false;
// FIXME: use a smaller sphere than the default one to have a larger
// area close to the borders that gives us "z-axis rotation"?
@@ -353,171 +323,71 @@ SbBool NavigationStyle::lookAtPoint(const SbVec2s screenpos)
SbVec3f hitpoint;
hitpoint = picked->getPoint();
lookAtPoint(hitpoint);
this->rotationCenterFound = false;
translateCamera(hitpoint - getFocalPoint());
return true;
}
void NavigationStyle::lookAtPoint(const SbVec3f& pos)
SoCamera* NavigationStyle::getCamera() const
{
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;
}
return this->viewer->getCamera();
}
void NavigationStyle::setCameraOrientation(const SbRotation& rot, SbBool moveToCenter)
void NavigationStyle::setCameraOrientation(const SbRotation& orientation, SbBool moveToCenter)
{
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
if (!cam)
SoCamera* camera = getCamera();
if (!camera)
return;
// 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;
animator->stop();
SbVec3f focalPoint = getFocalPoint();
SbVec3f translation(0, 0, 0);
if (moveToCenter) {
SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion());
action.apply(viewer->getSceneGraph());
SbBox3f box = action.getBoundingBox();
if (!box.isEmpty()) {
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();
translation = box.getCenter() - focalPoint;
}
}
// avoid to interfere with spinning (fixes #3101462)
if (this->isAnimating())
this->stopAnimating();
if (PRIVATE(this)->animsensor->isScheduled()) {
PRIVATE(this)->animsensor->unschedule();
this->interactiveCountDec();
}
// Start an animation or set the pose directly
if (isAnimationEnabled()) {
// 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;
}
viewer->startAnimation(orientation, focalPoint, translation);
}
else {
// 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;
// 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;
}
}
void NavigationStyleP::viewAnimationCB(void * data, SoSensor * sensor)
void NavigationStyle::translateCamera(const SbVec3f& translation)
{
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;
SoCamera* camera = getCamera();
if (!camera)
return;
SbVec3f direction;
cam->orientation.setValue(slerp);
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
cam->position = focalpoint - cam->focalDistance.getValue() * direction;
animator->stop();
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;
}
// 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;
}
}
@@ -604,29 +474,41 @@ 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 * cam, const SbRotation & rot)
void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation)
{
if (!cam)
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) {
return;
// 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 (cam->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
cam->focalDistance = static_cast<SoOrthographicCamera*>(cam)->height;
}
// 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;
// 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();
// Fix issue with near clipping in orthogonal view
if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
camera->focalDistance = static_cast<SoOrthographicCamera*>(camera)->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;
}
void NavigationStyle::panCamera(SoCamera * cam, float aspectratio, const SbPlane & panplane,
@@ -684,7 +566,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);
PRIVATE(this)->rotationCenterFound = false;
this->rotationCenterFound = false;
}
/** Dependent on the camera type this will either shrink or expand the
@@ -695,6 +577,9 @@ 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();
@@ -862,14 +747,14 @@ void NavigationStyle::doRotate(SoCamera * camera, float angle, const SbVec2f& po
SbVec3f NavigationStyle::getRotationCenter(SbBool& found) const
{
found = PRIVATE(this)->rotationCenterFound;
return PRIVATE(this)->rotationCenter;
found = this->rotationCenterFound;
return this->rotationCenter;
}
void NavigationStyle::setRotationCenter(const SbVec3f& cnt)
{
PRIVATE(this)->rotationCenter = cnt;
PRIVATE(this)->rotationCenterFound = true;
this->rotationCenter = cnt;
this->rotationCenterFound = true;
}
SbVec3f NavigationStyle::getFocalPoint() const
@@ -901,8 +786,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 (PRIVATE(this)->rotationCenterMode && PRIVATE(this)->rotationCenterFound) {
SbVec3f hitpoint = PRIVATE(this)->rotationCenter;
if (this->rotationCenterMode && this->rotationCenterFound) {
SbVec3f hitpoint = this->rotationCenter;
// set to the given position
SbVec3f direction;
@@ -929,7 +814,7 @@ void NavigationStyle::spin(const SbVec2f & pointerpos)
r.invert();
this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r);
if (PRIVATE(this)->rotationCenterMode && PRIVATE(this)->rotationCenterFound) {
if (this->rotationCenterMode && this->rotationCenterFound) {
float ratio = vp.getViewportAspectRatio();
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(vp.getViewportAspectRatio());
SbPlane panplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
@@ -1015,7 +900,7 @@ SbBool NavigationStyle::doSpin()
float radians;
rot.getValue(axis, radians);
if ((radians > 0.01f) && (deltatime < 0.300)) {
this->spinRotation = rot;
viewer->startSpinningAnimation(axis, radians * 5);
return true;
}
}
@@ -1030,14 +915,14 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
this->localPos = ev->getPosition();
// mode is WindowCenter
if (!PRIVATE(this)->rotationCenterMode) {
if (!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 (PRIVATE(this)->rotationCenterMode & NavigationStyle::RotationCenterMode::ScenePointAtCursor) {
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::ScenePointAtCursor) {
SoRayPickAction rpaction(viewer->getSoRenderManager()->getViewportRegion());
rpaction.setPoint(this->localPos);
rpaction.setRadius(viewer->getPickRadius());
@@ -1051,7 +936,7 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
}
// mode is FocalPointAtCursor or a ScenePointAtCursor failed
if (PRIVATE(this)->rotationCenterMode & NavigationStyle::RotationCenterMode::FocalPointAtCursor) {
if (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();
@@ -1072,7 +957,7 @@ void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
}
// mode is BoundingBoxCenter or a ScenePointAtCursor failed
if (PRIVATE(this)->rotationCenterMode & NavigationStyle::RotationCenterMode::BoundingBoxCenter) {
if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::BoundingBoxCenter) {
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
float ratio = vp.getViewportAspectRatio();
@@ -1128,20 +1013,6 @@ 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)
@@ -1168,7 +1039,7 @@ void
NavigationStyle::setAnimationEnabled(const SbBool enable)
{
this->spinanimatingallowed = enable;
if (!enable && this->isAnimating()) { this->stopAnimating(); }
if (!enable && this->isAnimating()) { animator->stop(); }
}
/*!
@@ -1191,52 +1062,29 @@ SbBool NavigationStyle::isAnimating() const
return this->currentmode == NavigationStyle::SPINNING;
}
/*!
* 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)
NavigationAnimator* NavigationStyle::getAnimator() const
{
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);
return this->animator;
}
void NavigationStyle::setSensitivity(float val)
{
PRIVATE(this)->sensitivity = val;
this->sensitivity = val;
}
float NavigationStyle::getSensitivity() const
{
return PRIVATE(this)->sensitivity;
return this->sensitivity;
}
void NavigationStyle::setResetCursorPosition(SbBool on)
{
PRIVATE(this)->resetcursorpos = on;
this->resetcursorpos = on;
}
SbBool NavigationStyle::isResetCursorPosition() const
{
return PRIVATE(this)->resetcursorpos;
return this->resetcursorpos;
}
void NavigationStyle::setZoomInverted(SbBool on)
@@ -1266,12 +1114,12 @@ SbBool NavigationStyle::isZoomAtCursor() const
void NavigationStyle::setRotationCenterMode(NavigationStyle::RotationCenterModes mode)
{
PRIVATE(this)->rotationCenterMode = mode;
this->rotationCenterMode = mode;
}
NavigationStyle::RotationCenterModes NavigationStyle::getRotationCenterMode() const
{
return PRIVATE(this)->rotationCenterMode;
return this->rotationCenterMode;
}
void NavigationStyle::startSelection(AbstractMouseSelection* mouse)
@@ -1415,6 +1263,7 @@ 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();
@@ -1428,15 +1277,18 @@ 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;

View File

@@ -52,6 +52,7 @@ class SbSphereSheetProjector;
namespace Gui {
class View3DInventorViewer;
class NavigationAnimator;
class AbstractMouseSelection;
/**
@@ -122,9 +123,8 @@ public:
void setAnimationEnabled(const SbBool enable);
SbBool isAnimationEnabled() const;
void startAnimating(const SbVec3f& axis, float velocity);
void stopAnimating();
SbBool isAnimating() const;
NavigationAnimator* getAnimator() const;
void setSensitivity(float);
float getSensitivity() const;
@@ -144,11 +144,14 @@ public:
void setRotationCenter(const SbVec3f& cnt);
SbVec3f getFocalPoint() const;
void updateAnimation();
void redraw();
void setCameraOrientation(const SbRotation& rot, SbBool moveTocenter=false);
void lookAtPoint(const SbVec3f&);
SoCamera* getCamera() const;
void setCameraOrientation(const SbRotation& orientation, SbBool moveToCenter = false);
void translateCamera(const SbVec3f& translation);
void reorientCamera(SoCamera* camera, const SbRotation& rotation);
void reorientCamera(SoCamera* camera, const SbRotation& rotation, const SbVec3f& rotationCenter);
void boxZoom(const SbBox2s& box);
virtual void viewAll();
@@ -173,6 +176,9 @@ public:
void setOrbitStyle(OrbitStyle style);
OrbitStyle getOrbitStyle() const;
SbBool isViewing() const;
void setViewing(SbBool);
SbVec3f getRotationCenter(SbBool&) const;
protected:
@@ -183,15 +189,12 @@ protected:
void interactiveCountDec();
int getInteractiveCount() const;
SbBool isViewing() const;
void setViewing(SbBool);
SbBool isSeekMode() const;
void setSeekMode(SbBool enable);
SbBool seekToPoint(const SbVec2s screenpos);
void seekToPoint(const SbVec3f& scenepos);
SbBool lookAtPoint(const SbVec2s screenpos);
void reorientCamera(SoCamera * camera, const SbRotation & rot);
void panCamera(SoCamera * camera,
float vpaspect,
const SbPlane & panplane,
@@ -233,13 +236,13 @@ protected:
} log;
View3DInventorViewer* viewer{nullptr};
NavigationAnimator* animator;
ViewerMode currentmode;
SoMouseButtonEvent mouseDownConsumedEvent;
SbVec2f lastmouseposition;
SbVec2s globalPos;
SbVec2s localPos;
SbPlane panningplane;
SbTime prevRedrawTime;
SbTime centerTime;
SbBool lockrecenter;
SbBool menuenabled;
@@ -261,13 +264,17 @@ protected:
SbBool spinanimatingallowed;
int spinsamplecounter;
SbRotation spinincrement;
SbRotation spinRotation;
SbSphereSheetProjector * spinprojector;
//@}
private:
struct NavigationStyleP* pimpl;
friend struct NavigationStyleP;
friend class NavigationAnimator;
SbVec3f rotationCenter;
SbBool rotationCenterFound;
NavigationStyle::RotationCenterModes rotationCenterMode;
float sensitivity;
SbBool resetcursorpos;
};
/** Sub-classes of this class appear in the preference dialog where users can

View File

@@ -32,7 +32,8 @@
<FCBool Name="ShowFPS" Value="0"/>
<FCBool Name="ShowNaviCube" Value="1"/>
<FCBool Name="ShowSelectionBoundingBox" Value="0"/>
<FCBool Name="UseAutoRotation" Value="0"/>
<FCBool Name="UseNavigationAnimations" Value="1"/>
<FCFloat Name="AnimationDuration" Value="0.25"/>
<FCBool Name="UseVBO" Value="0"/>
<FCFloat Name="ViewScalingFactor" Value="1.0"/>
<FCBool Name="ZoomAtCursor" Value="1"/>

View File

@@ -86,7 +86,8 @@ void DlgSettingsNavigation::saveSettings()
ui->checkBoxDisableTilt->onSave();
ui->checkBoxShowRotationCenter->onSave();
ui->spinBoxZoomStep->onSave();
ui->checkBoxUseAutoRotation->onSave();
ui->checkBoxNavigationAnimations->onSave();
ui->spinBoxAnimationDuration->onSave();
ui->qspinNewDocScale->onSave();
ui->prefStepByTurn->onSave();
ui->naviCubeCorner->onSave();
@@ -110,7 +111,7 @@ void DlgSettingsNavigation::saveSettings()
hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/NaviCube");
if (ui->naviCubeFontName->currentIndex()) {
hGrp->SetASCII("FontString", ui->naviCubeFontName->currentText().toLatin1());
hGrp->SetASCII("FontString", ui->naviCubeFontName->currentText().toLatin1());
} else {
hGrp->RemoveASCII("FontString");
}
@@ -123,7 +124,8 @@ void DlgSettingsNavigation::loadSettings()
ui->checkBoxDisableTilt->onRestore();
ui->checkBoxShowRotationCenter->onRestore();
ui->spinBoxZoomStep->onRestore();
ui->checkBoxUseAutoRotation->onRestore();
ui->checkBoxNavigationAnimations->onRestore();
ui->spinBoxAnimationDuration->onRestore();
ui->qspinNewDocScale->onRestore();
ui->prefStepByTurn->onRestore();
ui->naviCubeCorner->onRestore();
@@ -182,7 +184,7 @@ void DlgSettingsNavigation::loadSettings()
QStringList familyNames = QFontDatabase::families(QFontDatabase::Any);
#endif
ui->naviCubeFontName->addItems(familyNames);
hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/NaviCube");
int indexFamilyNames = familyNames.indexOf(

View File

@@ -473,27 +473,91 @@ The value is the diameter of the sphere to fit on the screen.</string>
</widget>
</item>
<item row="5" column="0">
<widget class="Gui::PrefCheckBox" name="checkBoxUseAutoRotation">
<widget class="Gui::PrefCheckBox" name="checkBoxNavigationAnimations">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Enable animated rotations</string>
<string>Enable navigation animations</string>
</property>
<property name="text">
<string>Enable animation</string>
<string>Enable navigation animations</string>
</property>
<property name="checked">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseAutoRotation</cstring>
<cstring>UseNavigationAnimations</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>View</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="navigationAnimationsLabel">
<property name="toolTip">
<string>Duration of navigation animations that have a fixed duration</string>
</property>
<property name="text">
<string>Animation duration</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="Gui::PrefSpinBox" name="spinBoxAnimationDuration">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>The duration of navigation animations in milliseconds</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>50</number>
</property>
<property name="value">
<number>250</number>
</property>
<property name="prefEntry" stdset="0">
<cstring>AnimationDuration</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>View</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="Gui::PrefCheckBox" name="checkBoxZoomAtCursor">
<property name="toolTip">
@@ -516,7 +580,7 @@ The value is the diameter of the sphere to fit on the screen.</string>
<item row="6" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string> Zoom step</string>
<string>Zoom step</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>

View File

@@ -118,6 +118,8 @@
#include "ViewProvider.h"
#include "ViewProviderDocumentObject.h"
#include "ViewProviderLink.h"
#include "NavigationAnimator.h"
#include "NavigationAnimation.h"
FC_LOG_LEVEL_INIT("3DViewer",true,true)
@@ -202,8 +204,8 @@ while the progress bar is running.
class Gui::ViewerEventFilter : public QObject
{
public:
ViewerEventFilter() = default;
~ViewerEventFilter() override = default;
ViewerEventFilter() {}
~ViewerEventFilter() override {}
bool eventFilter(QObject* obj, QEvent* event) override {
// Bug #0000607: Some mice also support horizontal scrolling which however might
@@ -245,8 +247,8 @@ public:
class SpaceNavigatorDevice : public Quarter::InputDevice {
public:
SpaceNavigatorDevice() = default;
~SpaceNavigatorDevice() override = default;
SpaceNavigatorDevice() {}
~SpaceNavigatorDevice() override {}
const SoEvent* translateEvent(QEvent* event) override {
if (event->type() == Spaceball::MotionEvent::MotionEventType) {
@@ -2235,8 +2237,6 @@ void View3DInventorViewer::renderScene()
drawSingleBackground(col);
glra->apply(this->backgroundroot);
navigation->updateAnimation();
if (!this->shading) {
state->push();
SoLightModelElement::set(state, selectionRoot, SoLightModelElement::BASE_COLOR);
@@ -2754,9 +2754,9 @@ void View3DInventorViewer::pubSeekToPoint(const SbVec3f& pos)
this->seekToPoint(pos);
}
void View3DInventorViewer::setCameraOrientation(const SbRotation& rot, SbBool moveTocenter)
void View3DInventorViewer::setCameraOrientation(const SbRotation& orientation, SbBool moveToCenter)
{
navigation->setCameraOrientation(rot, moveTocenter);
navigation->setCameraOrientation(orientation, moveToCenter);
}
void View3DInventorViewer::setCameraType(SoType t)
@@ -2777,54 +2777,19 @@ void View3DInventorViewer::setCameraType(SoType t)
}
}
namespace Gui {
class CameraAnimation : public QVariantAnimation
{
SoCamera* camera;
SbRotation startRot, endRot;
SbVec3f startPos, endPos;
public:
CameraAnimation(SoCamera* camera, const SbRotation& rot, const SbVec3f& pos)
: camera(camera), endRot(rot), endPos(pos)
{
startPos = camera->position.getValue();
startRot = camera->orientation.getValue();
}
~CameraAnimation() override = default;
protected:
void updateCurrentValue(const QVariant & value) override
{
int steps = endValue().toInt();
int curr = value.toInt();
float s = static_cast<float>(curr)/static_cast<float>(steps);
SbVec3f curpos = startPos * (1.0f-s) + endPos * s;
SbRotation currot = SbRotation::slerp(startRot, endRot, s);
camera->orientation.setValue(currot);
camera->position.setValue(curpos);
}
};
}
void View3DInventorViewer::moveCameraTo(const SbRotation& rot, const SbVec3f& pos, int steps, int ms)
void View3DInventorViewer::moveCameraTo(const SbRotation& orientation, const SbVec3f& position)
{
SoCamera* cam = this->getSoRenderManager()->getCamera();
if (!cam)
SoCamera* camera = getCamera();
if (!camera)
return;
CameraAnimation anim(cam, rot, pos);
anim.setDuration(Base::clamp<int>(ms,0,5000));
anim.setStartValue(static_cast<int>(0));
anim.setEndValue(steps);
if (isAnimationEnabled()) {
startAnimation(
orientation, camera->position.getValue(), position - camera->position.getValue(), true);
}
QEventLoop loop;
QObject::connect(&anim, &CameraAnimation::finished, &loop, &QEventLoop::quit);
anim.start();
loop.exec(QEventLoop::ExcludeUserInputEvents);
cam->orientation.setValue(rot);
cam->position.setValue(pos);
camera->orientation.setValue(orientation);
camera->position.setValue(position);
}
void View3DInventorViewer::animatedViewAll(int steps, int ms)
@@ -3106,18 +3071,49 @@ SbBool View3DInventorViewer::isAnimating() const
return navigation->isAnimating();
}
/*!
* Starts programmatically the viewer in animation mode. The given axis direction
* is always in screen coordinates, not in world coordinates.
/**
* @brief Change the camera pose with an animation
*
* @param orientation The new orientation
* @param rotationCenter The rotation center
* @param translation An additional translation on top of the translation caused by the rotation around the rotation center
*/
void View3DInventorViewer::startAnimating(const SbVec3f& axis, float velocity)
void View3DInventorViewer::startAnimation(const SbRotation& orientation,
const SbVec3f& rotationCenter, const SbVec3f& translation, bool wait)
{
navigation->startAnimating(axis, velocity);
// Currently starts a FixedTimeAnimation. If there is going to be an additional animation like
// FixedVelocityAnimation, check the animation type from a parameter and start the right animation
int duration = App::GetApplication()
.GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
->GetInt("AnimationDuration", 250);
auto animation = std::make_shared<FixedTimeAnimation>(
navigation, orientation, rotationCenter, translation, duration);
if (wait) {
navigation->getAnimator()->startAndWait(animation);
}
else {
navigation->getAnimator()->start(animation);
}
}
/**
* @brief Start an infinite spin animation
*
* @param axis The rotation axis in screen coordinates
* @param velocity The angular velocity in radians per second
*/
void View3DInventorViewer::startSpinningAnimation(const SbVec3f& axis, float velocity)
{
auto animation = std::make_shared<SpinningAnimation>(navigation, axis, velocity);
navigation->getAnimator()->start(animation);
}
void View3DInventorViewer::stopAnimating()
{
navigation->stopAnimating();
navigation->getAnimator()->stop();
}
void View3DInventorViewer::setPopupMenuEnabled(const SbBool on)

View File

@@ -164,7 +164,9 @@ public:
void setPopupMenuEnabled(const SbBool on);
SbBool isPopupMenuEnabled() const;
void startAnimating(const SbVec3f& axis, float velocity);
void startAnimation(const SbRotation& orientation, const SbVec3f& rotationCenter,
const SbVec3f& translation, bool wait = false);
void startSpinningAnimation(const SbVec3f& axis, float velocity);
void stopAnimating();
SbBool isAnimating() const;
@@ -373,9 +375,9 @@ public:
* \a true the reorientation is animated, otherwise its directly
* set.
*/
void setCameraOrientation(const SbRotation& rot, SbBool moveTocenter=false);
void setCameraOrientation(const SbRotation& orientation, SbBool moveToCenter = false);
void setCameraType(SoType t) override;
void moveCameraTo(const SbRotation& rot, const SbVec3f& pos, int steps, int ms);
void moveCameraTo(const SbRotation& orientation, const SbVec3f& position);
/**
* Zooms the viewport to the size of the bounding box.
*/

View File

@@ -777,10 +777,8 @@ Py::Object View3DInventorPy::getCameraOrientation()
Py::Object View3DInventorPy::viewPosition(const Py::Tuple& args)
{
PyObject* p=nullptr;
int steps = 20;
int ms = 30;
if (!PyArg_ParseTuple(args.ptr(), "|O!ii",&Base::PlacementPy::Type,&p,&steps,&ms))
PyObject* p = nullptr;
if (!PyArg_ParseTuple(args.ptr(), "|O!", &Base::PlacementPy::Type, &p))
throw Py::Exception();
if (p) {
@@ -791,7 +789,7 @@ Py::Object View3DInventorPy::viewPosition(const Py::Tuple& args)
rot.getValue(q0,q1,q2,q3);
getView3DIventorPtr()->getViewer()->moveCameraTo(
SbRotation((float)q0, (float)q1, (float)q2, (float)q3),
SbVec3f((float)pos.x, (float)pos.y, (float)pos.z), steps, ms);
SbVec3f((float)pos.x, (float)pos.y, (float)pos.z));
}
SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
@@ -810,11 +808,11 @@ Py::Object View3DInventorPy::viewPosition(const Py::Tuple& args)
Py::Object View3DInventorPy::startAnimating(const Py::Tuple& args)
{
float x,y,z;
float x, y, z;
float velocity;
if (!PyArg_ParseTuple(args.ptr(), "ffff", &x,&y,&z,&velocity))
if (!PyArg_ParseTuple(args.ptr(), "ffff", &x, &y, &z, &velocity))
throw Py::Exception();
getView3DIventorPtr()->getViewer()->startAnimating(SbVec3f(x,y,z),velocity);
getView3DIventorPtr()->getViewer()->startSpinningAnimation(SbVec3f(x, y, z), velocity);
return Py::None();
}

View File

@@ -74,7 +74,7 @@ void View3DSettings::applySettings()
OnChange(*hGrp,"CornerCoordSystem");
OnChange(*hGrp,"CornerCoordSystemSize");
OnChange(*hGrp,"ShowAxisCross");
OnChange(*hGrp,"UseAutoRotation");
OnChange(*hGrp,"UseNavigationAnimations");
OnChange(*hGrp,"Gradient");
OnChange(*hGrp,"RadialGradient");
OnChange(*hGrp,"BackgroundColor");
@@ -287,9 +287,9 @@ void View3DSettings::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M
_viewer->setAxisCross(rGrp.GetBool("ShowAxisCross", false));
}
}
else if (strcmp(Reason,"UseAutoRotation") == 0) {
else if (strcmp(Reason,"UseNavigationAnimations") == 0) {
for (auto _viewer : _viewers) {
_viewer->setAnimationEnabled(rGrp.GetBool("UseAutoRotation", false));
_viewer->setAnimationEnabled(rGrp.GetBool("UseNavigationAnimations", true));
}
}
else if (strcmp(Reason,"Gradient") == 0 || strcmp(Reason,"RadialGradient") == 0) {