Merge pull request #9446 from Rexbas/navigation-animation
Gui: Refactor navigation animations
This commit is contained in:
@@ -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})
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
145
src/Gui/NavigationAnimation.cpp
Normal file
145
src/Gui/NavigationAnimation.cpp
Normal 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);
|
||||
}
|
||||
96
src/Gui/NavigationAnimation.h
Normal file
96
src/Gui/NavigationAnimation.h
Normal 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
|
||||
99
src/Gui/NavigationAnimator.cpp
Normal file
99
src/Gui/NavigationAnimator.cpp
Normal 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();
|
||||
}
|
||||
55
src/Gui/NavigationAnimator.h
Normal file
55
src/Gui/NavigationAnimator.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user