Skip to content

Commit

Permalink
Gui: Refactor navigation animations
Browse files Browse the repository at this point in the history
- Animations are played through an Animator
- Animations now have a fixed duration
- The animation duration can be changed in the preferences
- Fix animations when using the two arrows above the NaviCube
  • Loading branch information
Rexbas committed Apr 30, 2023
1 parent b5a548e commit 06be04a
Show file tree
Hide file tree
Showing 12 changed files with 503 additions and 212 deletions.
4 changes: 4 additions & 0 deletions src/Gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,8 @@ SET(View3D_CPP_SRCS
View3DPy.cpp
View3DViewerPy.cpp
NaviCube.cpp
NavigationAnimator.cpp
NavigationAnimation.cpp
)
SET(View3D_SRCS
${View3D_CPP_SRCS}
Expand All @@ -844,6 +846,8 @@ SET(View3D_SRCS
CoinRiftWidget.h
View3DViewerPy.h
NaviCube.h
NavigationAnimator.h
NavigationAnimation.h
)
SOURCE_GROUP("View3D" FILES ${View3D_SRCS})

Expand Down
2 changes: 1 addition & 1 deletion src/Gui/DemoMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions src/Gui/DlgSettingsNavigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ void DlgSettingsNavigation::saveSettings()
ui->checkBoxInvertZoom->onSave();
ui->checkBoxDisableTilt->onSave();
ui->spinBoxZoomStep->onSave();
ui->checkBoxUseAutoRotation->onSave();
ui->checkBoxNavigationAnimations->onSave();
ui->spinBoxAnimationDuration->onSave();
ui->qspinNewDocScale->onSave();
ui->prefStepByTurn->onSave();
ui->naviCubeCorner->onSave();
Expand Down Expand Up @@ -120,7 +121,8 @@ void DlgSettingsNavigation::loadSettings()
ui->checkBoxInvertZoom->onRestore();
ui->checkBoxDisableTilt->onRestore();
ui->spinBoxZoomStep->onRestore();
ui->checkBoxUseAutoRotation->onRestore();
ui->checkBoxNavigationAnimations->onRestore();
ui->spinBoxAnimationDuration->onRestore();
ui->qspinNewDocScale->onRestore();
ui->prefStepByTurn->onRestore();
ui->naviCubeCorner->onRestore();
Expand Down
74 changes: 69 additions & 5 deletions src/Gui/DlgSettingsNavigation.ui
Original file line number Diff line number Diff line change
Expand Up @@ -469,27 +469,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>
</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="label">
<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">
<item>
<widget class="Gui::PrefDoubleSpinBox" name="spinBoxAnimationDuration">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>The duration of navigation animations in seconds</string>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>0.250000000000000</double>
</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">
<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">
Expand All @@ -512,7 +576,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>
Expand Down
107 changes: 107 additions & 0 deletions src/Gui/NavigationAnimation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <rexbasie@gmail.com> *
* *
* 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 <App/Application.h>
#include "View3DInventorViewer.h"

using namespace Gui;

NavigationAnimation::NavigationAnimation()
{
animationDuration = App::GetApplication()
.GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
->GetFloat("AnimationDuration", 0.25f);
}

void NavigationAnimation::reset(const SoCamera* camera)
{
targetOrientation = camera->orientation.getValue();
targetTranslation = SbVec3f(0, 0, 0);
totalTranslation = SbVec3f(0, 0, 0);
}

void NavigationAnimation::setDuration(float duration)
{
animationDuration = duration;
}

void NavigationAnimation::setTargetOrientation(const SbRotation& orientation)
{
targetOrientation = orientation;
}

void NavigationAnimation::translate(SbVec3f translation)
{
targetTranslation = translation;
}

void NavigationAnimation::initialize(const NavigationStyle* navigation)
{
// Remember the start time of the animation
startTime = SbTime::getTimeOfDay();

cameraStartOrientation = navigation->getCamera()->orientation.getValue();

// Get rotation center
rotationCenter = navigation->getFocalPoint();

// Find an axis and angle to rotate from the camera orientation to the target orientation
float angle;
SbRotation(navigation->getCamera()->orientation.getValue().inverse() * targetOrientation).getValue(rotationAxis, angle);
if (angle > M_PI) {
angle -= 2 * M_PI;
}

angularVelocity = angle / animationDuration;
linearVelocity = targetTranslation / animationDuration;
}

void NavigationAnimation::animate(NavigationStyle* navigation)
{
// Calculate time since start of animation
float activeDuration = (SbTime::getTimeOfDay() - startTime).getValue();

// Calculate the angle
float angle = (activeDuration >= animationDuration ? animationDuration : activeDuration) * angularVelocity;
SbRotation rotation(rotationAxis, angle);

// Calculate the translation delta
SbVec3f translationDelta = (activeDuration >= animationDuration ? animationDuration : activeDuration) * linearVelocity - totalTranslation;

SbRotation newOrientation;
if (activeDuration >= animationDuration) {
// Animation is finished, set exact orientation and unschedule animation
newOrientation = targetOrientation;
navigation->getAnimator()->stop();
}
else {
newOrientation = cameraStartOrientation * rotation;
}
navigation->setCameraOrientation(newOrientation, rotationCenter, false, false, false);

// Apply translation
navigation->translateCamera(translationDelta, false, false);
totalTranslation += translationDelta;
}
66 changes: 66 additions & 0 deletions src/Gui/NavigationAnimation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <rexbasie@gmail.com> *
* *
* 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 <Inventor/SbRotation.h>
#include <Inventor/SbVec3f.h>
#include <Inventor/nodes/SoCamera.h>
#include "NavigationAnimator.h"

namespace Gui
{

class GuiExport NavigationAnimation
{
public:
NavigationAnimation();
void reset(const SoCamera* camera);
void setDuration(float duration);
void setTargetOrientation(const SbRotation& orientation);
void translate(SbVec3f translation);

private:
SbTime startTime;
float animationDuration; // [s]
float angularVelocity; // [rad/s]
SbVec3f linearVelocity; // [/s]

SbRotation targetOrientation;
SbVec3f targetTranslation;
SbVec3f totalTranslation;

SbVec3f rotationCenter;
SbVec3f rotationAxis;
SbRotation cameraStartOrientation;

friend class NavigationAnimator;

void initialize(const NavigationStyle* navigation);
void animate(NavigationStyle* navigation);
};

} // namespace Gui

#endif // GUI_NAVIGATIONANIMATION_H
66 changes: 66 additions & 0 deletions src/Gui/NavigationAnimator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Bas Ruigrok (Rexbas) <rexbasie@gmail.com> *
* *
* 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 "View3DInventorViewer.h"

using namespace Gui;

NavigationAnimator::NavigationAnimator(NavigationStyle* navigation) : navigation(navigation), animation(nullptr)
{
sensor = new SoTimerSensor(NavigationAnimator::animateCB, navigation);
sensor->setInterval(SbTime(1 / 60.0)); // Animate at 60 Hz
}

NavigationAnimator::~NavigationAnimator()
{
stop();
delete sensor;
}

void NavigationAnimator::start(NavigationAnimation* animation)
{
this->animation = animation;
this->animation->initialize(navigation);
if (!sensor->isScheduled()) {
sensor->schedule();
navigation->interactiveCountInc();
}
}

void NavigationAnimator::stop()
{
if (sensor->isScheduled()) {
sensor->unschedule();
navigation->interactiveCountDec();
}
}

void NavigationAnimator::animateCB(void* data, SoSensor* sensor)
{
Q_UNUSED(sensor);
auto navigation = static_cast<NavigationStyle*>(data);
navigation->getAnimator()->animation->animate(navigation);
}
Loading

0 comments on commit 06be04a

Please sign in to comment.