Move camera path code into core and refactor navigation code a bit

This commit is contained in:
Emma Broman
2021-06-21 14:04:21 +02:00
parent 6c50b2a134
commit 77bdfaefd6
73 changed files with 3476 additions and 292 deletions

View File

@@ -28,16 +28,18 @@
#include <openspace/engine/configuration.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
#include <QComboBox>
#include <QFile>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QStandardItemModel>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <random>
#include <QStandardItemModel>
using namespace openspace;

View File

@@ -26,6 +26,7 @@
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <ghoul/fmt.h>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QLabel>

View File

@@ -26,6 +26,7 @@
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <ghoul/fmt.h>
#include <QDialogButtonBox>
#include <QDoubleValidator>
#include <QEvent>

View File

@@ -0,0 +1,173 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___CAMERA___H__
#define __OPENSPACE_CORE___CAMERA___H__
#include <openspace/util/syncdata.h>
#include <ghoul/glm.h>
#include <mutex>
namespace openspace {
class SceneGraphNode;
/**
* This class still needs some more love. Suggested improvements:
* - Accessors should return constant references to double precision class members.
* - Remove the scaling variable (What is it used for?)
* - Remove the maxFov and sinMaxfov variables. Redundant since the fov is embedded
* within the perspective projection matrix.
* - Remove focusposition, part of the integration with the scale graph. The
* "focus position" should not be needed since we assume the camera is always
* positioned relative to its origin. When orbiting another object (not in origin),
* the focus position should probably be handled outside the camera class
* (interaction handler) since it does not affect the state of the camera
* (only how it interacts).
* - The class might need some more reasonable accessors depending on use cases.
* (up vector world space?)
* - Make clear which function returns a combined view matrix (things that are
* dependent on the separate sgct nodes).
*/
class Camera {
public:
/**
* Used to explicitly show which variables within the Camera class that are used
* for caching.
*/
template<typename T>
struct Cached {
T datum = T(0);
bool isDirty = true;
};
Camera() = default;
Camera(const Camera& o);
~Camera() = default;
// Mutators
void setPositionVec3(glm::dvec3 pos);
void setRotation(glm::dquat rotation);
void setScaling(float scaling);
void setMaxFov(float fov);
void setParent(SceneGraphNode* parent);
// Relative mutators
void rotate(glm::dquat rotation);
// Accessors
// Remove Vec3 from the name when psc is gone
const glm::dvec3& positionVec3() const;
glm::dvec3 eyePositionVec3() const;
const glm::dvec3& unsynchedPositionVec3() const;
const glm::dvec3& viewDirectionWorldSpace() const;
const glm::dvec3& lookUpVectorCameraSpace() const;
const glm::dvec3& lookUpVectorWorldSpace() const;
const glm::dmat4& viewRotationMatrix() const;
const glm::dmat4& viewScaleMatrix() const;
const glm::dquat& rotationQuaternion() const;
float maxFov() const;
float sinMaxFov() const;
SceneGraphNode* parent() const;
float scaling() const;
// @TODO this should simply be called viewMatrix!
// Or it needs to be changed so that it actually is combined. Right now it is
// only the view matrix that is the same for all SGCT cameras.
// Right now this function returns the actual combined matrix which makes some
// of the old calls to the function wrong..
const glm::dmat4& combinedViewMatrix() const;
void invalidateCache();
void serialize(std::ostream& os) const;
void deserialize(std::istream& is);
/**
* Handles SGCT's internal matrices. Also caches a calculated viewProjection
* matrix. This is the data that is different for different cameras within SGCT.
*/
class SgctInternal {
friend class Camera;
public:
void setSceneMatrix(glm::mat4 sceneMatrix);
void setViewMatrix(glm::mat4 viewMatrix);
void setProjectionMatrix(glm::mat4 projectionMatrix);
const glm::mat4& sceneMatrix() const;
const glm::mat4& viewMatrix() const;
const glm::mat4& projectionMatrix() const;
const glm::mat4& viewProjectionMatrix() const;
private:
SgctInternal() = default;
SgctInternal(const SgctInternal& o);
glm::mat4 _sceneMatrix = glm::mat4(1.f);
glm::mat4 _viewMatrix = glm::mat4(1.f);
glm::mat4 _projectionMatrix = glm::mat4(1.f);
mutable Cached<glm::mat4> _cachedViewProjectionMatrix;
mutable std::mutex _mutex;
} sgctInternal;
// @TODO use Camera::SgctInternal interface instead
// [[deprecated("Replaced by Camera::SgctInternal::viewMatrix()")]]
const glm::mat4& viewMatrix() const;
// [[deprecated("Replaced by Camera::SgctInternal::projectionMatrix()")]]
const glm::mat4& projectionMatrix() const;
// [[deprecated("Replaced by Camera::SgctInternal::viewProjectionMatrix()")]]
const glm::mat4& viewProjectionMatrix() const;
std::vector<Syncable*> getSyncables();
// Static constants
static const glm::dvec3 ViewDirectionCameraSpace;
static const glm::dvec3 UpDirectionCameraSpace;
private:
SyncData<glm::dvec3> _position = glm::dvec3(1.0, 1.0, 1.0);
SyncData<glm::dquat> _rotation = glm::dquat(glm::dvec3(1.0, 1.0, 1.0));
SyncData<float> _scaling = 1.f;
SceneGraphNode* _parent = nullptr;
// _focusPosition to be removed
glm::dvec3 _focusPosition = glm::dvec3(0.0);
float _maxFov = 0.f;
// Cached data
mutable Cached<glm::dvec3> _cachedViewDirection;
mutable Cached<glm::dvec3> _cachedLookupVector;
mutable Cached<glm::dmat4> _cachedViewRotationMatrix;
mutable Cached<glm::dmat4> _cachedViewScaleMatrix;
mutable Cached<glm::dmat4> _cachedCombinedViewMatrix;
mutable Cached<float> _cachedSinMaxFov;
mutable std::mutex _mutex;
};
} // namespace openspace
#endif // __OPENSPACE_CORE___CAMERA___H__

View File

@@ -0,0 +1,39 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___CAMERAPOSE___H__
#define __OPENSPACE_CORE___CAMERAPOSE___H__
#include <ghoul/glm.h>
namespace openspace {
struct CameraPose {
glm::dvec3 position = glm::dvec3(0.0);
glm::dquat rotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
};
} // namespace openspace
#endif // __OPENSPACE_CORE___CAMERAPOSE___H__

View File

@@ -26,7 +26,7 @@
#define __OPENSPACE_CORE___SESSIONRECORDING___H__
#include <openspace/interaction/externinteraction.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/scripting/lualibrary.h>
#include <vector>

View File

@@ -25,8 +25,8 @@
#ifndef __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__
#define __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__
#include <openspace/util/timeline.h>
#include <openspace/network/messagestructures.h>
#include <openspace/util/timeline.h>
#include <ghoul/glm.h>
#include <ghoul/misc/boolean.h>
#include <glm/gtx/quaternion.hpp>

View File

@@ -28,10 +28,12 @@
#include <openspace/documentation/documentation.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/util/mouse.h>
@@ -48,31 +50,14 @@ namespace openspace::scripting { struct LuaLibrary; }
namespace openspace::interaction {
struct JoystickInputStates;
struct NavigationState;
struct WebsocketInputStates;
class KeyframeNavigator;
class OrbitalNavigator;
class PathNavigator;
class NavigationHandler : public properties::PropertyOwner {
public:
struct NavigationState {
NavigationState() = default;
NavigationState(const ghoul::Dictionary& dictionary);
NavigationState(std::string anchor, std::string aim, std::string referenceFrame,
glm::dvec3 position, std::optional<glm::dvec3> up = std::nullopt,
double yaw = 0.0, double pitch = 0.0);
ghoul::Dictionary dictionary() const;
static documentation::Documentation Documentation();
std::string anchor;
std::string aim;
std::string referenceFrame;
glm::dvec3 position = glm::dvec3(0.0);
std::optional<glm::dvec3> up;
double yaw = 0.0;
double pitch = 0.0;
};
NavigationHandler();
~NavigationHandler();
@@ -80,11 +65,9 @@ public:
void deinitialize();
// Mutators
void setFocusNode(SceneGraphNode* node);
void resetCameraDirection();
void setNavigationStateNextFame(NavigationState state);
void setCamera(Camera* camera);
void setInterpolationTime(float durationInSeconds);
@@ -101,6 +84,7 @@ public:
const OrbitalNavigator& orbitalNavigator() const;
OrbitalNavigator& orbitalNavigator();
KeyframeNavigator& keyframeNavigator();
PathNavigator& pathNavigator();
bool isKeyFrameInteractionEnabled() const;
float interpolationTime() const;
@@ -154,7 +138,7 @@ public:
static scripting::LuaLibrary luaLibrary();
private:
void applyNavigationState(const NavigationHandler::NavigationState& ns);
void applyNavigationState(const NavigationState& ns);
bool _playbackModeEnabled = false;
@@ -164,6 +148,7 @@ private:
OrbitalNavigator _orbitalNavigator;
KeyframeNavigator _keyframeNavigator;
PathNavigator _pathNavigator;
std::optional<NavigationState> _pendingNavigationState;

View File

@@ -0,0 +1,59 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___NAVIGATIONSTATE___H__
#define __OPENSPACE_CORE___NAVIGATIONSTATE___H__
#include <openspace/documentation/documentation.h>
#include <optional>
namespace openspace {
struct CameraPose;
} // namespace openspace
namespace openspace::interaction {
struct NavigationState {
NavigationState() = default;
NavigationState(const ghoul::Dictionary& dictionary);
NavigationState(std::string anchor, std::string aim, std::string referenceFrame,
glm::dvec3 position, std::optional<glm::dvec3> up = std::nullopt,
double yaw = 0.0, double pitch = 0.0);
CameraPose cameraPose() const;
ghoul::Dictionary dictionary() const;
static documentation::Documentation Documentation();
std::string anchor;
std::string aim;
std::string referenceFrame;
glm::dvec3 position = glm::dvec3(0.0);
std::optional<glm::dvec3> up;
double yaw = 0.0;
double pitch = 0.0;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___NAVIGATIONSTATE___H__

View File

@@ -46,6 +46,7 @@
namespace openspace {
class SceneGraphNode;
class Camera;
struct CameraPose;
struct SurfacePositionHandle;
} // namespace
@@ -104,11 +105,6 @@ private:
glm::dquat globalRotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
};
struct CameraPose {
glm::dvec3 position = glm::dvec3(0.0);
glm::dquat rotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
};
using Displacement = std::pair<glm::dvec3, glm::dvec3>;
struct Friction : public properties::PropertyOwner {

View File

@@ -0,0 +1,83 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PATH___H__
#define __OPENSPACE_CORE___PATH___H__
#include <openspace/navigation/pathcurve.h>
#include <openspace/navigation/waypoint.h>
#include <optional>
#include <vector>
namespace openspace {
struct CameraPose;
} // namespace openspace
namespace openspace::interaction {
class Path {
public:
enum CurveType {
AvoidCollision,
Linear,
ZoomOutOverview
};
Path(Waypoint start, Waypoint end, CurveType type,
std::optional<double> duration = std::nullopt);
Waypoint startPoint() const;
Waypoint endPoint() const;
double duration() const;
double pathLength() const;
std::vector<glm::dvec3> controlPoints() const;
CameraPose traversePath(double dt);
std::string currentAnchor() const;
bool hasReachedEnd() const;
CameraPose interpolatedPose(double distance) const;
private:
glm::dquat interpolateRotation(double u) const;
double speedAlongPath(double traveledDistance);
Waypoint _start;
Waypoint _end;
double _duration;
CurveType _curveType;
std::unique_ptr<PathCurve> _curve;
double _speedFactorFromDuration = 1.0;
// Playback variables
double _traveledDistance = 0.0;
double _progressedTime = 0.0; // Time since playback started
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___PATH___H__

View File

@@ -0,0 +1,63 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PATHCREATOR___H__
#define __OPENSPACE_CORE___PATHCREATOR___H__
#include <openspace/navigation/path.h>
#include <ghoul/glm.h>
#include <ghoul/misc/dictionary.h>
namespace openspace { class SceneGraphNode; }
namespace openspace::interaction {
struct Waypoint;
class PathCreator {
public:
// Create a path from a dictionary containing the instruction
static Path createPath(const ghoul::Dictionary& dictionary,
Path::CurveType curveType);
private:
struct NodeInfo {
std::string identifier;
std::optional<glm::dvec3> position;
std::optional<double> height;
bool useTargetUpDirection;
};
static Waypoint waypointFromCamera();
static Waypoint computeDefaultWaypoint(const NodeInfo& info,
const Waypoint& startPoint);
// Test if the node lies within a given proximity radius of any relevant node
// in the scene
static SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node);
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___PATHCREATOR___H__

View File

@@ -0,0 +1,81 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PATHCURVE___H__
#define __OPENSPACE_CORE___PATHCURVE___H__
#include <ghoul/glm.h>
#include <vector>
namespace openspace::interaction {
struct Waypoint;
class PathCurve {
public:
virtual ~PathCurve() = 0;
const double length() const;
glm::dvec3 positionAt(double relativeDistance);
// Compute curve parameter u that matches the input arc length s
double curveParameter(double s);
virtual glm::dvec3 interpolate(double u);
std::vector<glm::dvec3> points();
protected:
// Precompute information related to the pspline parameters, that are
// needed for arc length reparameterization. Must be called after
// control point creation
void initializeParameterData();
double approximatedDerivative(double u, double h = 0.0001);
double arcLength(double limit = 1.0);
double arcLength(double lowerLimit, double upperLimit);
std::vector<glm::dvec3> _points;
unsigned int _nSegments;
std::vector<double> _curveParameterSteps; // per segment
std::vector<double> _lengthSums; // per segment
double _totalLength;
struct ParameterPair {
double u; // curve parameter
double s; // arc length parameter
};
std::vector<ParameterPair> _parameterSamples;
};
class LinearCurve : public PathCurve {
public:
LinearCurve(const Waypoint& start, const Waypoint& end);
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___PATHCURVE___H__

View File

@@ -0,0 +1,48 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___AVOIDCOLLISIONCURVE___H__
#define __OPENSPACE_CORE___AVOIDCOLLISIONCURVE___H__
#include <openspace/navigation/pathcurve.h>
namespace openspace { class SceneGraphNode; }
namespace openspace::interaction {
struct WayPoint;
class AvoidCollisionCurve : public PathCurve {
public:
AvoidCollisionCurve(const Waypoint& start, const Waypoint& end);
private:
void removeCollisions(int step = 0);
std::vector<SceneGraphNode*> _relevantNodes;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___AVOIDCOLLISIONCURVE___H__

View File

@@ -0,0 +1,41 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___ZOOMOUTOVERVIEWCURVE___H__
#define __OPENSPACE_CORE___ZOOMOUTOVERVIEWCURVE___H__
#include <openspace/navigation/pathcurve.h>
namespace openspace::interaction {
struct WayPoint;
class ZoomOutOverviewCurve : public PathCurve {
public:
ZoomOutOverviewCurve(const Waypoint& start, const Waypoint& end);
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___ZOOMOUTOVERVIEWCURVE___H__

View File

@@ -0,0 +1,83 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PATHHELPERFUNCTIONS___H__
#define __OPENSPACE_CORE___PATHHELPERFUNCTIONS___H__
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
namespace openspace::interaction::helpers {
// Make interpolator parameter t [0,1] progress only inside a subinterval
double shiftAndScale(double t, double newStart, double newEnd);
glm::dquat lookAtQuaternion(glm::dvec3 eye, glm::dvec3 center, glm::dvec3 up);
glm::dvec3 viewDirection(const glm::dquat& q);
bool lineSphereIntersection(glm::dvec3 linePoint1, glm::dvec3 linePoint2,
glm::dvec3 sphereCenter, double spehereRadius, glm::dvec3& intersectionPoint);
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r);
double simpsonsRule(double t0, double t1, int n, std::function<double(double)> f);
double fivePointGaussianQuadrature(double t0, double t1,
std::function<double(double)> f);
} // namespace openspace::interaction::helpers
namespace openspace::interaction::interpolation {
glm::dquat easedSlerp(const glm::dquat q1, const glm::dquat q2, double t);
// TODO: make all these into template functions.
// Alternatively, add cubicBezier interpolation in ghoul and only use
// ghoul's interpolator methods
// Centripetal version alpha = 0, uniform for alpha = 0.5 and chordal for alpha = 1
glm::dvec3 catmullRom(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3, double alpha = 0.5);
glm::dvec3 cubicBezier(double t, const glm::dvec3& cp1, const glm::dvec3& cp2,
const glm::dvec3& cp3, const glm::dvec3& cp4);
glm::dvec3 linear(double t, const glm::dvec3& cp1, const glm::dvec3& cp2);
glm::dvec3 hermite(double t, const glm::dvec3 &cp1, const glm::dvec3 &cp2,
const glm::dvec3 &tangent1, const glm::dvec3 &tangent2);
glm::dvec3 piecewiseCubicBezier(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots);
glm::dvec3 piecewiseLinear(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots);
} // namespace openspace::interaction::interpolation
#endif // __OPENSPACE_CORE___PATHHELPERFUNCTIONS___H__

View File

@@ -0,0 +1,121 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PATHNAVIGATOR___H__
#define __OPENSPACE_CORE___PATHNAVIGATOR___H__
#include <openspace/properties/propertyowner.h>
#include <openspace/navigation/path.h>
#include <openspace/properties/list/stringlistproperty.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <ghoul/glm.h>
#include <memory>
namespace openspace {
class Camera;
struct CameraPose;
class SceneGraphNode;
} // namespace openspace
namespace openspace::scripting { struct LuaLibrary; }
namespace openspace::interaction {
class Path;
class PathNavigator : public properties::PropertyOwner {
public:
enum StopBehavior {
None = 0,
Orbit
};
PathNavigator();
~PathNavigator();
// Accessors
Camera* camera() const;
const SceneGraphNode* anchor() const;
double speedScale() const;
bool hasCurrentPath() const;
bool hasFinished() const;
bool isPlayingPath() const;
void updateCamera(double deltaTime);
void createPath(const ghoul::Dictionary& dictionary);
void clearPath();
void startPath();
void abortPath();
void pausePath();
void continuePath();
// TODO: remove functions for debugging
std::vector<glm::dvec3> curvePositions(int nSteps) const;
std::vector<glm::dquat> curveOrientations(int nSteps) const;
std::vector<glm::dvec3> curveViewDirections(int nSteps) const;
std::vector<glm::dvec3> controlPoints() const;
double minValidBoundingSphere() const;
const std::vector<SceneGraphNode*>& relevantNodes();
/**
* \return The Lua library that contains all Lua functions available to affect the
* path navigation
*/
static scripting::LuaLibrary luaLibrary();
private:
void findRelevantNodes();
void removeRollRotation(CameraPose& pose, double deltaTime);
void applyStopBehavior(double deltaTime);
void orbitAnchorNode(double deltaTime);
std::unique_ptr<Path> _currentPath = nullptr;
bool _isPlaying = false;
properties::OptionProperty _defaultCurveOption;
properties::BoolProperty _includeRoll;
properties::FloatProperty _speedScale;
properties::FloatProperty _orbitSpeedFactor;
properties::BoolProperty _applyStopBehaviorWhenIdle;
properties::OptionProperty _stopBehavior;
properties::DoubleProperty _minValidBoundingSphere;
properties::StringListProperty _relevantNodeTags;
std::vector<SceneGraphNode*> _relevantNodes;
bool _hasInitializedRelevantNodes = false;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___PATHNAVIGATOR___H__

View File

@@ -0,0 +1,55 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___WAYPOINT___H__
#define __OPENSPACE_CORE___WAYPOINT___H__
#include <openspace/camera/camerapose.h>
#include <ghoul/glm.h>
namespace openspace { class SceneGraphNode; }
namespace openspace::interaction {
struct NavigationState;
struct Waypoint {
Waypoint() = default;
Waypoint(const glm::dvec3& pos, const glm::dquat& rot, const std::string& ref);
Waypoint(const NavigationState& ns);
static double findValidBoundingSphere(const SceneGraphNode* node);
glm::dvec3 position() const;
glm::dquat rotation() const;
SceneGraphNode* node() const;
CameraPose pose;
std::string nodeIdentifier;
double validBoundingSphere = 0.0; // to be able to handle nodes with faulty bounding spheres
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___WAYPOINT___H__

View File

@@ -26,9 +26,9 @@
#define __OPENSPACE_CORE___PROFILE___H__
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/util/keys.h>
#include <ghoul/glm.h>
#include <ghoul/misc/exception.h>
#include <optional>
#include <string>
@@ -37,6 +37,8 @@
namespace openspace {
namespace interaction { struct NavigationState; }
namespace scripting { struct LuaLibrary; }
class Profile {
@@ -127,8 +129,7 @@ public:
* and all of the property & asset changes that were made since startup.
*/
void saveCurrentSettingsToProfile(const properties::PropertyOwner& rootOwner,
std::string currentTime,
interaction::NavigationHandler::NavigationState navState);
std::string currentTime, interaction::NavigationState navState);
/// If the value passed to this function is 'true', the addAsset and removeAsset
/// functions will be no-ops instead

View File

@@ -25,8 +25,8 @@
#ifndef __OPENSPACE_CORE___SCRIPTSCHEDULER___H__
#define __OPENSPACE_CORE___SCRIPTSCHEDULER___H__
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/interaction/keyframenavigator.h>
#include <functional>
#include <queue>

View File

@@ -25,7 +25,7 @@
#ifndef __OPENSPACE_CORE___UPDATESTRUCTURES___H__
#define __OPENSPACE_CORE___UPDATESTRUCTURES___H__
#include <openspace/util/camera.h>
#include <openspace/camera/camera.h>
#include <openspace/util/time.h>
namespace openspace {

View File

@@ -26,7 +26,7 @@
#include <modules/globebrowsing/src/renderableglobe.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/camera.h>

View File

@@ -29,7 +29,7 @@
#include <modules/autonavigation/waypoint.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <openspace/util/camera.h>

View File

@@ -27,7 +27,7 @@
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/pathcreator.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>

View File

@@ -25,7 +25,7 @@
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___WAYPOINT___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___WAYPOINT___H__
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <ghoul/glm.h>
namespace openspace::pathnavigation {

View File

@@ -24,15 +24,15 @@
#include <modules/base/dashboard/dashboarditemangle.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>

View File

@@ -24,15 +24,15 @@
#include <modules/base/dashboard/dashboarditemdistance.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
#include <openspace/util/distanceconversion.h>
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>

View File

@@ -24,15 +24,14 @@
#include <modules/base/dashboard/dashboarditemvelocity.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
#include <openspace/util/distanceconversion.h>
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>

View File

@@ -27,8 +27,8 @@
#include <modules/base/basemodule.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/translation.h>

View File

@@ -28,7 +28,6 @@
#include <modules/exoplanets/tasks/exoplanetsdatapreparationtask.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/globalscallbacks.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/scene.h>

View File

@@ -37,8 +37,9 @@
#include <modules/globebrowsing/src/tileprovider.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globalscallbacks.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/factorymanager.h>
#include <ghoul/filesystem/filesystem.h>
@@ -597,7 +598,7 @@ void GlobeBrowsingModule::goToGeodetic3(const globebrowsing::RenderableGlobe& gl
Geodetic2{ geo3.geodetic2.lat + 0.001, geo3.geodetic2.lon }
);
interaction::NavigationHandler::NavigationState state;
interaction::NavigationState state;
state.anchor = globe.owner()->identifier();
state.referenceFrame = globe.owner()->identifier();
state.position = positionModelSpace;

View File

@@ -27,15 +27,15 @@
#include <modules/globebrowsing/src/layer.h>
#include <modules/globebrowsing/src/layergroup.h>
#include <modules/globebrowsing/src/layermanager.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <openspace/util/camera.h>
#include <openspace/util/updatestructures.h>
namespace openspace::globebrowsing::luascriptfunctions {

View File

@@ -29,8 +29,8 @@
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/distanceconversion.h>
#include <openspace/util/updatestructures.h>

View File

@@ -26,17 +26,14 @@
#include <modules/globebrowsing/globebrowsingmodule.h>
#include <modules/globebrowsing/src/renderableglobe.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/filesystem/filesystem.h>

View File

@@ -27,6 +27,7 @@
#include <openspace/properties/propertyowner.h>
#include <openspace/camera/camera.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
@@ -34,7 +35,6 @@
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/vector/vec2property.h>
#include <openspace/properties/vector/vec4property.h>
#include <openspace/util/camera.h>
#include <ghoul/glm.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/opengl/uniformcache.h>

View File

@@ -29,8 +29,8 @@
#include <openspace/engine/virtualpropertymanager.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/luaconsole.h>

View File

@@ -29,8 +29,8 @@
#include <modules/imgui/include/imgui_include.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>

View File

@@ -26,7 +26,6 @@
#include <modules/imgui/include/imgui_include.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/joystickinputstate.h>

View File

@@ -26,11 +26,11 @@
#include <modules/imgui/include/imgui_include.h>
#include <openspace/engine/globals.h>
#include <openspace/util/timemanager.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/network/messagestructures.h>
#include <openspace/util/timemanager.h>
#include <ghoul/fmt.h>

View File

@@ -28,8 +28,8 @@
#include <modules/imgui/include/imgui_include.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/scene.h>

View File

@@ -30,8 +30,8 @@
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/interaction/websocketinputstate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>

View File

@@ -30,7 +30,7 @@
#include <openspace/engine/globals.h>
#include <openspace/engine/virtualpropertymanager.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/query/query.h>
#include <openspace/rendering/luaconsole.h>

View File

@@ -28,9 +28,9 @@
#include <openspace/engine/globalscallbacks.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/interactionmonitor.h>
#include <openspace/navigation/navigationhandler.h>
#include <ghoul/logging/logmanager.h>
#include <fmt/format.h>

View File

@@ -26,6 +26,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/set_openspace_compile_settings.cmake)
set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/openspace.cpp
${OPENSPACE_BASE_DIR}/src/camera/camera.cpp
${OPENSPACE_BASE_DIR}/src/documentation/core_registration.cpp
${OPENSPACE_BASE_DIR}/src/documentation/documentation.cpp
${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp
@@ -49,11 +50,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/interaction/joystickcamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/keyframenavigator.cpp
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler.cpp
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp
${OPENSPACE_BASE_DIR}/src/interaction/scriptcamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording.cpp
@@ -67,6 +64,20 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/mission/mission.cpp
${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp
${OPENSPACE_BASE_DIR}/src/mission/missionmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/navigation/pathcurves/avoidcollisioncurve.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathcurves/zoomoutoverviewcurve.cpp
${OPENSPACE_BASE_DIR}/src/navigation/keyframenavigator.cpp
${OPENSPACE_BASE_DIR}/src/navigation/navigationhandler.cpp
${OPENSPACE_BASE_DIR}/src/navigation/navigationhandler_lua.inl
${OPENSPACE_BASE_DIR}/src/navigation/navigationstate.cpp
${OPENSPACE_BASE_DIR}/src/navigation/orbitalnavigator.cpp
${OPENSPACE_BASE_DIR}/src/navigation/path.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathcreator.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathcurve.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathhelperfunctions.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathnavigator.cpp
${OPENSPACE_BASE_DIR}/src/navigation/pathnavigator_lua.inl
${OPENSPACE_BASE_DIR}/src/navigation/waypoint.cpp
${OPENSPACE_BASE_DIR}/src/network/parallelconnection.cpp
${OPENSPACE_BASE_DIR}/src/network/parallelpeer.cpp
${OPENSPACE_BASE_DIR}/src/network/parallelpeer_lua.inl
@@ -151,7 +162,6 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/scripting/systemcapabilitiesbinding.cpp
${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/camera.cpp
${OPENSPACE_BASE_DIR}/src/util/coordinateconversion.cpp
${OPENSPACE_BASE_DIR}/src/util/distanceconversion.cpp
${OPENSPACE_BASE_DIR}/src/util/factorymanager.cpp
@@ -195,6 +205,8 @@ if (APPLE)
endif ()
set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/json.h
${OPENSPACE_BASE_DIR}/include/openspace/camera/camera.h
${OPENSPACE_BASE_DIR}/include/openspace/camera/camerapose.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/core_registration.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationengine.h
@@ -222,10 +234,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickinputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickcamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keybindingmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyframenavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousecamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/externinteraction.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/scriptcamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.h
@@ -237,6 +246,18 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/interaction/tasks/convertrecformattask.h
${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h
${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathcurves/avoidcollisioncurve.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathcurves/zoomoutoverviewcurve.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/keyframenavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/navigationhandler.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/navigationstate.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/orbitalnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/path.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathcreator.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathcurve.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathhelperfunctions.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/pathnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/navigation/waypoint.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelpeer.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelserver.h
@@ -325,7 +346,6 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/scripting/systemcapabilitiesbinding.h
${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h
${OPENSPACE_BASE_DIR}/include/openspace/util/concurrentjobmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/util/concurrentjobmanager.inl
${OPENSPACE_BASE_DIR}/include/openspace/util/concurrentqueue.h

View File

@@ -22,7 +22,7 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/util/camera.h>
#include <openspace/camera/camera.h>
#include <sstream>

View File

@@ -28,12 +28,13 @@
#include <openspace/engine/logfactory.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/mission/mission.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/renderable.h>
@@ -59,9 +60,7 @@ namespace openspace {
void registerCoreClasses(documentation::DocumentationEngine& engine) {
engine.addDocumentation(LogFactoryDocumentation());
engine.addDocumentation(Mission::Documentation());
engine.addDocumentation(
interaction::NavigationHandler::NavigationState::Documentation()
);
engine.addDocumentation(interaction::NavigationState::Documentation());
engine.addDocumentation(Renderable::Documentation());
engine.addDocumentation(Rotation::Documentation());
engine.addDocumentation(Scale::Documentation());
@@ -89,6 +88,7 @@ void registerCoreClasses(scripting::ScriptEngine& engine) {
engine.addLibrary(Time::luaLibrary());
engine.addLibrary(interaction::KeybindingManager::luaLibrary());
engine.addLibrary(interaction::NavigationHandler::luaLibrary());
engine.addLibrary(interaction::PathNavigator::luaLibrary());
engine.addLibrary(interaction::SessionRecording::luaLibrary());
engine.addLibrary(interaction::ShortcutManager::luaLibrary());
engine.addLibrary(scripting::ScriptScheduler::luaLibrary());

View File

@@ -36,10 +36,10 @@
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/interaction/websocketinputstate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/rendering/dashboard.h>

View File

@@ -25,6 +25,7 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/openspace.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/core_registration.h>
#include <openspace/documentation/documentationengine.h>
#include <openspace/engine/configuration.h>
@@ -38,8 +39,8 @@
#include <openspace/interaction/interactionmonitor.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/dashboarditem.h>
@@ -60,7 +61,6 @@
#include <openspace/scene/scenelicensewriter.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/camera.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/spicemanager.h>

View File

@@ -25,15 +25,15 @@
#include <openspace/interaction/externinteraction.h>
#include <openspace/openspace.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
#include <openspace/util/timemanager.h>

View File

@@ -24,20 +24,20 @@
#include <openspace/interaction/sessionrecording.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/interaction/tasks/convertrecfileversiontask.h>
#include <openspace/interaction/tasks/convertrecformattask.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/util/camera.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/task.h>
#include <openspace/util/timemanager.h>

View File

@@ -22,13 +22,13 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
#include <openspace/util/timemanager.h>
#include <ghoul/logging/logmanager.h>

View File

@@ -22,16 +22,16 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/documentation/verifier.h>
#include <openspace/query/query.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
@@ -66,102 +66,12 @@ namespace {
"If this is set to 'true' the entire interaction is based off key frames rather "
"than using the mouse interaction."
};
struct [[codegen::Dictionary(NavigationHandler)]] Parameters {
// The identifier of the anchor node
std::string anchor;
// The identifier of the aim node, if used
std::optional<std::string> aim;
// The identifier of the scene graph node to use as reference frame. If not
// specified, this will be the same as the anchor
std::optional<std::string> referenceFrame;
// The position of the camera relative to the anchor node, expressed in meters in
// the specified reference frame
glm::dvec3 position;
// The up vector expressed in the coordinate system of the reference frame
std::optional<glm::dvec3> up;
// The yaw angle in radians. Positive angle means yawing camera to the right
std::optional<double> yaw;
// The pitch angle in radians. Positive angle means pitching camera upwards
std::optional<double> pitch;
};
#include "navigationhandler_codegen.cpp"
} // namespace
#include "navigationhandler_lua.inl"
namespace openspace::interaction {
ghoul::Dictionary NavigationHandler::NavigationState::dictionary() const {
constexpr const char* KeyAnchor = "Anchor";
constexpr const char* KeyAim = "Aim";
constexpr const char* KeyPosition = "Position";
constexpr const char* KeyUp = "Up";
constexpr const char* KeyYaw = "Yaw";
constexpr const char* KeyPitch = "Pitch";
constexpr const char* KeyReferenceFrame = "ReferenceFrame";
ghoul::Dictionary cameraDict;
cameraDict.setValue(KeyPosition, position);
cameraDict.setValue(KeyAnchor, anchor);
if (anchor != referenceFrame) {
cameraDict.setValue(KeyReferenceFrame, referenceFrame);
}
if (!aim.empty()) {
cameraDict.setValue(KeyAim, aim);
}
if (up.has_value()) {
cameraDict.setValue(KeyUp, *up);
if (std::abs(yaw) > Epsilon) {
cameraDict.setValue(KeyYaw, yaw);
}
if (std::abs(pitch) > Epsilon) {
cameraDict.setValue(KeyPitch, pitch);
}
}
return cameraDict;
}
NavigationHandler::NavigationState::NavigationState(const ghoul::Dictionary& dictionary) {
const Parameters p = codegen::bake<Parameters>(dictionary);
anchor = p.anchor;
position = p.position;
referenceFrame = p.referenceFrame.value_or(anchor);
aim = p.aim.value_or(aim);
if (p.up.has_value()) {
up = *p.up;
yaw = p.yaw.value_or(yaw);
pitch = p.pitch.value_or(pitch);
}
}
NavigationHandler::NavigationState::NavigationState(std::string anchor_, std::string aim_,
std::string referenceFrame_,
glm::dvec3 position_,
std::optional<glm::dvec3> up_,
double yaw_, double pitch_)
: anchor(std::move(anchor_))
, aim(std::move(aim_))
, referenceFrame(std::move(referenceFrame_))
, position(std::move(position_))
, up(std::move(up_))
, yaw(yaw_)
, pitch(pitch_)
{}
NavigationHandler::NavigationHandler()
: properties::PropertyOwner({ "NavigationHandler" })
, _disableMouseInputs(KeyDisableMouseInputInfo, false)
@@ -169,6 +79,7 @@ NavigationHandler::NavigationHandler()
, _useKeyFrameInteraction(KeyFrameInfo, false)
{
addPropertySubOwner(_orbitalNavigator);
addPropertySubOwner(_pathNavigator);
addProperty(_disableMouseInputs);
addProperty(_disableJoystickInputs);
@@ -210,8 +121,7 @@ void NavigationHandler::setCamera(Camera* camera) {
_orbitalNavigator.setCamera(camera);
}
void NavigationHandler::setNavigationStateNextFrame(
NavigationHandler::NavigationState state)
void NavigationHandler::setNavigationStateNextFrame(NavigationState state)
{
_pendingNavigationState = std::move(state);
}
@@ -228,6 +138,10 @@ KeyframeNavigator& NavigationHandler::keyframeNavigator() {
return _keyframeNavigator;
}
PathNavigator& NavigationHandler::pathNavigator() {
return _pathNavigator;
}
bool NavigationHandler::isKeyFrameInteractionEnabled() const {
return _useKeyFrameInteraction;
}
@@ -252,6 +166,9 @@ void NavigationHandler::updateCamera(double deltaTime) {
if (_useKeyFrameInteraction) {
_keyframeNavigator.updateCamera(*_camera, _playbackModeEnabled);
}
else if (_pathNavigator.isPlayingPath()) {
_pathNavigator.updateCamera(deltaTime);
}
else {
if (_disableJoystickInputs) {
std::fill(
@@ -264,67 +181,21 @@ void NavigationHandler::updateCamera(double deltaTime) {
_orbitalNavigator.updateCameraStateFromStates(deltaTime);
}
}
// If session recording (playback mode) was started in the midst of a camera path,
// abort the path
if (_playbackModeEnabled && _pathNavigator.isPlayingPath()) {
_pathNavigator.abortPath();
}
}
void NavigationHandler::applyNavigationState(const NavigationHandler::NavigationState& ns)
{
const SceneGraphNode* referenceFrame = sceneGraphNode(ns.referenceFrame);
const SceneGraphNode* anchor = sceneGraphNode(ns.anchor);
if (!anchor) {
LERROR(fmt::format(
"Could not find scene graph node '{}' used as anchor.", ns.referenceFrame
));
return;
}
if (!ns.aim.empty() && !sceneGraphNode(ns.aim)) {
LERROR(fmt::format(
"Could not find scene graph node '{}' used as aim.", ns.referenceFrame
));
return;
}
if (!referenceFrame) {
LERROR(fmt::format(
"Could not find scene graph node '{}' used as reference frame.",
ns.referenceFrame)
);
return;
}
const glm::dvec3 anchorWorldPosition = anchor->worldPosition();
const glm::dmat3 referenceFrameTransform = referenceFrame->worldRotationMatrix();
void NavigationHandler::applyNavigationState(const NavigationState& ns) {
_orbitalNavigator.setAnchorNode(ns.anchor);
_orbitalNavigator.setAimNode(ns.aim);
const SceneGraphNode* anchorNode = _orbitalNavigator.anchorNode();
const SceneGraphNode* aimNode = _orbitalNavigator.aimNode();
if (!aimNode) {
aimNode = anchorNode;
}
const glm::dvec3 cameraPositionWorld = anchorWorldPosition +
referenceFrameTransform * glm::dvec4(ns.position, 1.0);
glm::dvec3 up = ns.up.has_value() ?
glm::normalize(referenceFrameTransform * *ns.up) :
glm::dvec3(0.0, 1.0, 0.0);
// Construct vectors of a "neutral" view, i.e. when the aim is centered in view.
glm::dvec3 neutralView =
glm::normalize(aimNode->worldPosition() - cameraPositionWorld);
glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt(
glm::dvec3(0.0),
neutralView,
up
)));
glm::dquat pitchRotation = glm::angleAxis(ns.pitch, glm::dvec3(1.0, 0.0, 0.0));
glm::dquat yawRotation = glm::angleAxis(ns.yaw, glm::dvec3(0.0, -1.0, 0.0));
_camera->setPositionVec3(cameraPositionWorld);
_camera->setRotation(neutralCameraRotation * yawRotation * pitchRotation);
CameraPose pose = ns.cameraPose();
_camera->setPositionVec3(pose.position);
_camera->setRotation(pose.rotation);
_orbitalNavigator.clearPreviousState();
}
@@ -383,7 +254,7 @@ void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActio
_inputState.keyboardCallback(key, modifier, action);
}
NavigationHandler::NavigationState NavigationHandler::navigationState() const {
NavigationState NavigationHandler::navigationState() const {
const SceneGraphNode* referenceFrame = _orbitalNavigator.followingAnchorRotation() ?
_orbitalNavigator.anchorNode() :
sceneGraph()->root();
@@ -395,7 +266,7 @@ NavigationHandler::NavigationState NavigationHandler::navigationState() const {
return navigationState(*referenceFrame);
}
NavigationHandler::NavigationState NavigationHandler::navigationState(
NavigationState NavigationHandler::navigationState(
const SceneGraphNode& referenceFrame) const
{
const SceneGraphNode* anchor = _orbitalNavigator.anchorNode();
@@ -441,7 +312,7 @@ NavigationHandler::NavigationState NavigationHandler::navigationState(
void NavigationHandler::saveNavigationState(const std::string& filepath,
const std::string& referenceFrameIdentifier)
{
NavigationHandler::NavigationState state;
NavigationState state;
if (!referenceFrameIdentifier.empty()) {
const SceneGraphNode* referenceFrame = sceneGraphNode(referenceFrameIdentifier);
if (!referenceFrame) {
@@ -560,10 +431,6 @@ std::vector<std::string> NavigationHandler::joystickButtonCommand(int button) co
return _orbitalNavigator.joystickStates().buttonCommand(button);
}
documentation::Documentation NavigationHandler::NavigationState::Documentation() {
return codegen::doc<Parameters>("core_navigation_state");
}
scripting::LuaLibrary NavigationHandler::luaLibrary() {
return {
"navigation",

View File

@@ -22,8 +22,9 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <numeric>
#include <openspace/interaction/scriptcamerastates.h>
#include <openspace/navigation/navigationstate.h>
#include <numeric>
namespace openspace::luascriptfunctions {
@@ -53,7 +54,7 @@ int getNavigationState(lua_State* L) {
"lua::getNavigationState"
);
interaction::NavigationHandler::NavigationState state;
interaction::NavigationState state;
if (n == 1) {
const std::string referenceFrameIdentifier = ghoul::lua::value<std::string>(L, 1);
const SceneGraphNode* referenceFrame = sceneGraphNode(referenceFrameIdentifier);
@@ -124,7 +125,7 @@ int setNavigationState(lua_State* L) {
ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary);
openspace::documentation::TestResult r = openspace::documentation::testSpecification(
interaction::NavigationHandler::NavigationState::Documentation(),
interaction::NavigationState::Documentation(),
navigationStateDictionary
);

View File

@@ -0,0 +1,186 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/camera/camerapose.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
namespace {
constexpr const char* _loggerCat = "NavigationState";
const double Epsilon = 1E-7;
struct [[codegen::Dictionary(NavigationState)]] Parameters {
// The identifier of the anchor node
std::string anchor;
// The identifier of the aim node, if used
std::optional<std::string> aim;
// The identifier of the scene graph node to use as reference frame. If not
// specified, this will be the same as the anchor
std::optional<std::string> referenceFrame;
// The position of the camera relative to the anchor node, expressed in meters in
// the specified reference frame
glm::dvec3 position;
// The up vector expressed in the coordinate system of the reference frame
std::optional<glm::dvec3> up;
// The yaw angle in radians. Positive angle means yawing camera to the right
std::optional<double> yaw;
// The pitch angle in radians. Positive angle means pitching camera upwards
std::optional<double> pitch;
};
#include "navigationstate_codegen.cpp"
} // namespace
namespace openspace::interaction {
NavigationState::NavigationState(const ghoul::Dictionary& dictionary) {
const Parameters p = codegen::bake<Parameters>(dictionary);
anchor = p.anchor;
position = p.position;
referenceFrame = p.referenceFrame.value_or(anchor);
aim = p.aim.value_or(aim);
if (p.up.has_value()) {
up = *p.up;
yaw = p.yaw.value_or(yaw);
pitch = p.pitch.value_or(pitch);
}
}
NavigationState::NavigationState(std::string anchor_, std::string aim_,
std::string referenceFrame_, glm::dvec3 position_,
std::optional<glm::dvec3> up_,
double yaw_, double pitch_)
: anchor(std::move(anchor_))
, aim(std::move(aim_))
, referenceFrame(std::move(referenceFrame_))
, position(std::move(position_))
, up(std::move(up_))
, yaw(yaw_)
, pitch(pitch_)
{}
CameraPose NavigationState::cameraPose() const {
const SceneGraphNode* referenceFrameNode = sceneGraphNode(referenceFrame);
const SceneGraphNode* anchorNode = sceneGraphNode(anchor);
if (!anchorNode) {
LERROR(fmt::format(
"Could not find scene graph node '{}' used as anchor.", referenceFrame
));
return CameraPose();
}
if (!aim.empty() && !sceneGraphNode(aim)) {
LERROR(fmt::format(
"Could not find scene graph node '{}' used as aim.", referenceFrame
));
return CameraPose();
}
if (!referenceFrameNode) {
LERROR(fmt::format(
"Could not find scene graph node '{}' used as reference frame.",
referenceFrame)
);
return CameraPose();
}
CameraPose resultingPose;
const glm::dvec3 anchorWorldPosition = anchorNode->worldPosition();
const glm::dmat3 referenceFrameTransform = referenceFrameNode->worldRotationMatrix();
resultingPose.position = anchorWorldPosition +
glm::dvec3(referenceFrameTransform * glm::dvec4(position, 1.0));
glm::dvec3 upVector = up.has_value() ?
glm::normalize(referenceFrameTransform * up.value()) :
glm::dvec3(0.0, 1.0, 0.0);
// Construct vectors of a "neutral" view, i.e. when the aim is centered in view.
glm::dvec3 neutralView =
glm::normalize(anchorWorldPosition - resultingPose.position);
glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt(
glm::dvec3(0.0),
neutralView,
upVector
)));
glm::dquat pitchRotation = glm::angleAxis(pitch, glm::dvec3(1.f, 0.f, 0.f));
glm::dquat yawRotation = glm::angleAxis(yaw, glm::dvec3(0.f, -1.f, 0.f));
resultingPose.rotation = neutralCameraRotation * yawRotation * pitchRotation;
return resultingPose;
}
ghoul::Dictionary NavigationState::dictionary() const {
constexpr const char* KeyAnchor = "Anchor";
constexpr const char* KeyAim = "Aim";
constexpr const char* KeyPosition = "Position";
constexpr const char* KeyUp = "Up";
constexpr const char* KeyYaw = "Yaw";
constexpr const char* KeyPitch = "Pitch";
constexpr const char* KeyReferenceFrame = "ReferenceFrame";
ghoul::Dictionary cameraDict;
cameraDict.setValue(KeyPosition, position);
cameraDict.setValue(KeyAnchor, anchor);
if (anchor != referenceFrame) {
cameraDict.setValue(KeyReferenceFrame, referenceFrame);
}
if (!aim.empty()) {
cameraDict.setValue(KeyAim, aim);
}
if (up.has_value()) {
cameraDict.setValue(KeyUp, *up);
if (std::abs(yaw) > Epsilon) {
cameraDict.setValue(KeyYaw, yaw);
}
if (std::abs(pitch) > Epsilon) {
cameraDict.setValue(KeyPitch, pitch);
}
}
return cameraDict;
}
documentation::Documentation NavigationState::Documentation() {
return codegen::doc<Parameters>("core_navigation_state");
}
} // namespace openspace::interaction

View File

@@ -22,7 +22,8 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/camera/camerapose.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/updatestructures.h>
#include <openspace/query/query.h>
@@ -643,8 +644,7 @@ glm::dquat OrbitalNavigator::composeCameraRotation(
return decomposition.globalRotation * decomposition.localRotation;
}
Camera* OrbitalNavigator::camera() const
{
Camera* OrbitalNavigator::camera() const {
return _camera;
}
@@ -909,9 +909,8 @@ OrbitalNavigator::CameraRotationDecomposition
return { localCameraRotation, globalCameraRotation };
}
OrbitalNavigator::CameraPose OrbitalNavigator::followAim(CameraPose pose,
glm::dvec3 cameraToAnchor,
Displacement anchorToAim)
CameraPose OrbitalNavigator::followAim(CameraPose pose, glm::dvec3 cameraToAnchor,
Displacement anchorToAim)
{
CameraRotationDecomposition anchorDecomp =
decomposeCameraRotation(pose, pose.position + cameraToAnchor);

224
src/navigation/path.cpp Normal file
View File

@@ -0,0 +1,224 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/path.h>
#include <openspace/camera/camerapose.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/pathcurve.h>
#include <openspace/navigation/pathcurves/avoidcollisioncurve.h>
#include <openspace/navigation/pathcurves/zoomoutoverviewcurve.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/interpolator.h>
namespace {
constexpr const char* _loggerCat = "Path";
} // namespace
namespace openspace::interaction {
Path::Path(Waypoint start, Waypoint end, CurveType type,
std::optional<double> duration)
: _start(start), _end(end), _curveType(type)
{
switch (_curveType) {
case CurveType::AvoidCollision:
_curve = std::make_unique<AvoidCollisionCurve>(_start, _end);
break;
case CurveType::Linear:
_curve = std::make_unique<LinearCurve>(_start, _end);
break;
case CurveType::ZoomOutOverview:
_curve = std::make_unique<ZoomOutOverviewCurve>(_start, _end);
break;
default:
LERROR("Could not create curve. Type does not exist!");
throw ghoul::MissingCaseException();
}
const auto defaultDuration = [](double pathlength) {
const double speedScale =
global::navigationHandler->pathNavigator().speedScale();
return std::log(pathlength) / speedScale;
};
_duration = duration.value_or(defaultDuration(pathLength()));
// Compute speed factor to match the generated path length and duration, by
// traversing the path and computing how much faster/slower it should be
const int nSteps = 500;
const double dt = (_duration / nSteps) > 0.01 ? (_duration / nSteps) : 0.01;
while (!hasReachedEnd()) {
traversePath(dt);
}
_speedFactorFromDuration = _progressedTime / _duration;
// Reset playback variables
_traveledDistance = 0.0;
_progressedTime = 0.0;
}
Waypoint Path::startPoint() const { return _start; }
Waypoint Path::endPoint() const { return _end; }
double Path::duration() const { return _duration; }
double Path::pathLength() const { return _curve->length(); }
std::vector<glm::dvec3> Path::controlPoints() const {
return _curve->points();
}
CameraPose Path::traversePath(double dt) {
const double speed = _speedFactorFromDuration * speedAlongPath(_traveledDistance);
const double displacement = dt * speed;
_progressedTime += dt;
_traveledDistance += displacement;
return interpolatedPose(_traveledDistance);
}
std::string Path::currentAnchor() const {
bool pastHalfway = (_traveledDistance / pathLength()) > 0.5;
return (pastHalfway) ? _end.nodeIdentifier : _start.nodeIdentifier;
}
bool Path::hasReachedEnd() const {
return (_traveledDistance / pathLength()) >= 1.0;
}
CameraPose Path::interpolatedPose(double distance) const {
const double relativeDistance = distance / pathLength();
CameraPose cs;
cs.position = _curve->positionAt(relativeDistance);
cs.rotation = interpolateRotation(relativeDistance);
return cs;
}
glm::dquat Path::interpolateRotation(double t) const {
switch (_curveType) {
case CurveType::AvoidCollision:
case CurveType::Linear:
return interpolation::easedSlerp(_start.rotation(), _end.rotation(), t);
case CurveType::ZoomOutOverview:
{
const double t1 = 0.2;
const double t2 = 0.8;
const glm::dvec3 startPos = _curve->positionAt(0.0);
const glm::dvec3 endPos = _curve->positionAt(1.0);
const glm::dvec3 startNodePos = _start.node()->worldPosition();
const glm::dvec3 endNodePos = _end.node()->worldPosition();
glm::dvec3 lookAtPos;
if (t < t1) {
// Compute a position in front of the camera at the start orientation
const double inFrontDistance = glm::distance(startPos, startNodePos);
const glm::dvec3 viewDir = helpers::viewDirection(_start.rotation());
const glm::dvec3 inFrontOfStart = startPos + inFrontDistance * viewDir;
const double tScaled = ghoul::cubicEaseInOut(t / t1);
lookAtPos =
ghoul::interpolateLinear(tScaled, inFrontOfStart, startNodePos);
}
else if (t <= t2) {
const double tScaled = ghoul::cubicEaseInOut((t - t1) / (t2 - t1));
lookAtPos = ghoul::interpolateLinear(tScaled, startNodePos, endNodePos);
}
else if (t > t2) {
// Compute a position in front of the camera at the end orientation
const double inFrontDistance = glm::distance(endPos, endNodePos);
const glm::dvec3 viewDir = helpers::viewDirection(_end.rotation());
const glm::dvec3 inFrontOfEnd = endPos + inFrontDistance * viewDir;
const double tScaled = ghoul::cubicEaseInOut((t - t2) / (1.0 - t2));
lookAtPos = ghoul::interpolateLinear(tScaled, endNodePos, inFrontOfEnd);
}
// Handle up vector separately
glm::dvec3 startUp = _start.rotation() * glm::dvec3(0.0, 1.0, 0.0);
glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
double tUp = helpers::shiftAndScale(t, t1, t2);
tUp = ghoul::sineEaseInOut(tUp);
glm::dvec3 up = ghoul::interpolateLinear(tUp, startUp, endUp);
return helpers::lookAtQuaternion(_curve->positionAt(t), lookAtPos, up);
}
default:
throw ghoul::MissingCaseException();
}
}
double Path::speedAlongPath(double traveledDistance) {
const glm::dvec3 endNodePos = _end.node()->worldPosition();
const glm::dvec3 startNodePos = _start.node()->worldPosition();
const CameraPose prevPose = interpolatedPose(traveledDistance);
const double distanceToEndNode = glm::distance(prevPose.position, endNodePos);
const double distanceToStartNode = glm::distance(prevPose.position, startNodePos);
// Decide which is the closest node
SceneGraphNode* closestNode = _start.node();
glm::dvec3 closestPos = startNodePos;
if (distanceToEndNode < distanceToStartNode) {
closestPos = endNodePos;
closestNode = _end.node();
}
const double distanceToClosestNode = glm::distance(closestPos, prevPose.position);
double speed = distanceToClosestNode;
// Dampen speed in beginning of path
const double startUpDistance = 2.0 * _start.node()->boundingSphere();
if (traveledDistance < startUpDistance) {
speed *= traveledDistance / startUpDistance + 0.01;
}
// Dampen speed in end of path
// Note: this leads to problems when the full length of the path is really big
const double closeUpDistance = 2.0 * _end.node()->boundingSphere();
if (traveledDistance > (pathLength() - closeUpDistance)) {
const double remainingDistance = pathLength() - traveledDistance;
speed *= remainingDistance / closeUpDistance + 0.01;
}
// TODO: also dampen speed based on curvature, or make sure the curve has a rounder shape
// TODO: check for when path is shorter than the starUpDistance or closeUpDistance variables
return speed;
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,249 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/pathcreator.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* _loggerCat = "PathCreator";
constexpr const float Epsilon = 1e-5f;
// TODO: where should this documentation be?
struct [[codegen::Dictionary(PathInstruction)]] Parameters {
enum class Type {
Node,
NavigationState
};
Type type;
// The desired duration traversing the specified path segment should take
std::optional<float> duration;
// (Node): The target node of the camera path. Not optional for 'Node' instructions
std::optional<std::string> target;
// (Node): An optional position in relation to the target node, in model
// coordinates (meters)
std::optional<glm::dvec3> position;
// (Node): An optional height in relation to the target node, in meters
std::optional<double> height;
// (Node): If true, the up direction of the node is taken into account when
// computing the wayopoint for this instruction
std::optional<bool> useTargetUpDirection;
// (NavigationState): A navigation state that will be the target
// of this path segment
std::optional<ghoul::Dictionary> navigationState
[[codegen::reference("core_navigation_state")]];
// A navigation state that determines the start state for the camera path
std::optional<ghoul::Dictionary> startState
[[codegen::reference("core_navigation_state")]];
};
#include "pathcreator_codegen.cpp"
} // namespace
namespace openspace::interaction {
Path PathCreator::createPath(const ghoul::Dictionary& dictionary,
Path::CurveType curveType)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
std::optional<float> duration = p.duration;
bool hasStart = p.startState.has_value();
Waypoint startPoint = hasStart ? Waypoint(p.startState.value()) : waypointFromCamera();
// TODO: also handle curve type here
std::vector<Waypoint> waypoints;
switch (p.type) {
case Parameters::Type::NavigationState: {
if (!p.navigationState.has_value()) {
throw ghoul::RuntimeError("A navigation state is required");
}
const NavigationState navigationState =
NavigationState(p.navigationState.value());
waypoints = { Waypoint(navigationState) };
break;
}
case Parameters::Type::Node: {
if (!p.target.has_value()) {
throw ghoul::RuntimeError("A target node is required");
}
const std::string nodeIdentifier = p.target.value();
const SceneGraphNode* targetNode = sceneGraphNode(nodeIdentifier);
if (!targetNode) {
throw ghoul::RuntimeError(fmt::format(
"Could not find target node '{}'", nodeIdentifier
));
}
NodeInfo info {
nodeIdentifier,
p.position,
p.height,
p.useTargetUpDirection.value_or(false)
};
waypoints = { computeDefaultWaypoint(info, startPoint) };
break;
}
default: {
LERROR(fmt::format("Uknown instruciton type: {}", p.type));
throw ghoul::MissingCaseException();
}
}
// TODO: allow for an instruction to represent a list of waypoints
Waypoint waypointToAdd = waypoints[0];
return Path(startPoint, waypointToAdd, curveType, duration);
}
Waypoint PathCreator::waypointFromCamera() {
Camera* camera = global::navigationHandler->camera();
const glm::dvec3 pos = camera->positionVec3();
const glm::dquat rot = camera->rotationQuaternion();
const std::string node = global::navigationHandler->anchorNode()->identifier();
return Waypoint{ pos, rot, node };
}
Waypoint PathCreator::computeDefaultWaypoint(const NodeInfo& info,
const Waypoint& startPoint)
{
const SceneGraphNode* targetNode = sceneGraphNode(info.identifier);
if (!targetNode) {
LERROR(fmt::format("Could not find target node '{}'", info.identifier));
return Waypoint();
}
glm::dvec3 targetPos;
if (info.position.has_value()) {
// Note that the anchor and reference frame is our targetnode.
// The position in instruction is given is relative coordinates
targetPos = targetNode->worldPosition() +
targetNode->worldRotationMatrix() * info.position.value();
}
else {
const glm::dvec3 nodePos = targetNode->worldPosition();
const glm::dvec3 sunPos = glm::dvec3(0.0, 0.0, 0.0);
const SceneGraphNode* closeNode = findNodeNearTarget(targetNode);
glm::dvec3 stepDirection;
if (closeNode) {
// If the node is close to another node in the scene, make sure that the
// position is set to minimize risk of collision
stepDirection = glm::normalize(nodePos - closeNode->worldPosition());
}
else if (glm::length(sunPos - nodePos) < Epsilon) {
// Special case for when the target is the Sun. Assumption: want an overview of
// the solar system, and not stay in the orbital plane
stepDirection = glm::dvec3(0.0, 0.0, 1.0);
}
else {
// Go to a point that is being lit up by the sun, slightly offsetted from sun
// direction
const glm::dvec3 prevPos = startPoint.position();
const glm::dvec3 targetToPrev = prevPos - nodePos;
const glm::dvec3 targetToSun = sunPos - nodePos;
constexpr const float defaultPositionOffsetAngle = -30.f; // degrees
constexpr const float angle = glm::radians(defaultPositionOffsetAngle);
const glm::dvec3 axis = glm::normalize(glm::cross(targetToPrev, targetToSun));
const glm::dquat offsetRotation = angleAxis(static_cast<double>(angle), axis);
stepDirection = glm::normalize(offsetRotation * targetToSun);
}
const double radius = Waypoint::findValidBoundingSphere(targetNode);
const double defaultHeight = 2.0 * radius;
const double height = info.height.value_or(defaultHeight);
targetPos = nodePos + stepDirection * (radius + height);
}
glm::dvec3 up = global::navigationHandler->camera()->lookUpVectorWorldSpace();
if (info.useTargetUpDirection) {
// @TODO (emmbr 2020-11-17) For now, this is hardcoded to look good for Earth,
// which is where it matters the most. A better solution would be to make each
// sgn aware of its own 'up' and query
up = targetNode->worldRotationMatrix() * glm::dvec3(0.0, 0.0, 1.0);
}
const glm::dvec3 lookAtPos = targetNode->worldPosition();
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
return Waypoint(targetPos, targetRot, info.identifier);
}
SceneGraphNode* PathCreator::findNodeNearTarget(const SceneGraphNode* node) {
const std::vector<SceneGraphNode*>& relevantNodes =
global::navigationHandler->pathNavigator().relevantNodes();
for (SceneGraphNode* n : relevantNodes) {
if (n->identifier() == node->identifier()) {
continue;
}
constexpr const float proximityRadiusFactor = 3.f;
const float bs = static_cast<float>(n->boundingSphere());
const float proximityRadius = proximityRadiusFactor * bs;
const glm::dvec3 posInModelCoords =
glm::inverse(n->modelTransform()) * glm::dvec4(node->worldPosition(), 1.0);
bool isClose = helpers::isPointInsideSphere(
posInModelCoords,
glm::dvec3(0.0, 0.0, 0.0),
proximityRadius
);
if (isClose) {
return n;
}
}
return nullptr;
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,236 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/pathcurve.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
namespace {
constexpr const char* _loggerCat = "PathCurve";
constexpr const int NrSamplesPerSegment = 100;
} // namespace
namespace openspace::interaction {
PathCurve::~PathCurve() {}
const double PathCurve::length() const {
return _totalLength;
}
glm::dvec3 PathCurve::positionAt(double relativeDistance) {
const double u = curveParameter(relativeDistance * _totalLength);
return interpolate(u);
}
// Compute the curve parameter from an arc length value, using a combination of
// Newton's method and bisection. Source:
// https://www.geometrictools.com/Documentation/MovingAlongCurveSpecifiedSpeed.pdf
// Input s is a length value, in the range [0, _totalLength]
// Returns curve parameter in range [0, 1]
double PathCurve::curveParameter(double s) {
if (s <= 0.0) return 0.0;
if (s >= _totalLength) return 1.0;
unsigned int segmentIndex = 1;
while (s > _lengthSums[segmentIndex]) {
segmentIndex++;
}
const int startIndex = (segmentIndex - 1) * NrSamplesPerSegment;
const int endIndex = segmentIndex * NrSamplesPerSegment + 1;
const double segmentS = s - _lengthSums[segmentIndex - 1];
const double uMin = _curveParameterSteps[segmentIndex - 1];
const double uMax = _curveParameterSteps[segmentIndex];
// Use samples to find an initial guess for Newton's method
// Find first sample with s larger than input s
auto sampleIterator = std::upper_bound(
_parameterSamples.begin() + startIndex,
_parameterSamples.begin() + endIndex,
ParameterPair{ 0.0 , s }, // 0.0 is a dummy value for u
[](ParameterPair lhs, ParameterPair rhs) {
return lhs.s < rhs.s;
}
);
const ParameterPair& sample = *sampleIterator;
const ParameterPair& prevSample = *(sampleIterator - 1);
const double uPrev = prevSample.u;
const double sPrev = prevSample.s;
const double slope = (sample.u - uPrev) / (sample.s - sPrev);
double u = uPrev + slope * (s - sPrev);
constexpr const int maxIterations = 50;
// Initialize root bounding limits for bisection
double lower = uMin;
double upper = uMax;
for (int i = 0; i < maxIterations; ++i) {
double F = arcLength(uMin, u) - segmentS;
// The error we tolerate, in meters. Note that distances are very large
constexpr const double tolerance = 0.005;
if (std::abs(F) <= tolerance) {
return u;
}
// Generate a candidate for Newton's method
double dfdu = approximatedDerivative(u); // > 0
double uCandidate = u - F / dfdu;
// Update root-bounding interval and test candidate
if (F > 0) { // => candidate < u <= upper
upper = u;
u = (uCandidate <= lower) ? (upper + lower) / 2.0 : uCandidate;
}
else { // F < 0 => lower <= u < candidate
lower = u;
u = (uCandidate >= upper) ? (upper + lower) / 2.0 : uCandidate;
}
}
// No root was found based on the number of iterations and tolerance. However, it is
// safe to report the last computed u value, since it is within the segment interval
return u;
}
std::vector<glm::dvec3> PathCurve::points() {
return _points;
}
void PathCurve::initializeParameterData() {
_nSegments = static_cast<int>(_points.size() - 3);
ghoul_assert(_nSegments > 0, "Cannot have a curve with zero segments!");
_curveParameterSteps.clear();
_lengthSums.clear();
_parameterSamples.clear();
// Evenly space out parameter intervals
_curveParameterSteps.reserve(_nSegments + 1);
const double dt = 1.0 / _nSegments;
_curveParameterSteps.push_back(0.0);
for (unsigned int i = 1; i < _nSegments; i++) {
_curveParameterSteps.push_back(dt * i);
}
_curveParameterSteps.push_back(1.0);
// Arc lengths
_lengthSums.reserve(_nSegments + 1);
_lengthSums.push_back(0.0);
for (unsigned int i = 1; i <= _nSegments; i++) {
double u = _curveParameterSteps[i];
double uPrev = _curveParameterSteps[i - 1];
double length = arcLength(uPrev, u);
_lengthSums.push_back(_lengthSums[i - 1] + length);
}
_totalLength = _lengthSums.back();
// Compute a map of arc lengths s and curve parameters u, for reparameterization
_parameterSamples.reserve(NrSamplesPerSegment * _nSegments + 1);
const double uStep = 1.0 / (_nSegments * NrSamplesPerSegment);
for (unsigned int i = 0; i < _nSegments; i++) {
double uStart = _curveParameterSteps[i];
double sStart = _lengthSums[i];
for (int j = 0; j < NrSamplesPerSegment; ++j) {
double u = uStart + j * uStep;
double s = sStart + arcLength(uStart, u);
_parameterSamples.push_back({ u, s });
}
}
_parameterSamples.push_back({ 1.0, _totalLength });
}
double PathCurve::approximatedDerivative(double u, double h) {
if (u <= h) {
return (1.0 / h) * glm::length(interpolate(0.0 + h) - interpolate(0.0));
}
if (u >= 1.0 - h) {
return (1.0 / h) * glm::length(interpolate(1.0) - interpolate(1.0 - h));
}
return (0.5 / h) * glm::length(interpolate(u + h) - interpolate(u - h));
}
double PathCurve::arcLength(double limit) {
return arcLength(0.0, limit);
}
double PathCurve::arcLength(double lowerLimit, double upperLimit) {
return helpers::fivePointGaussianQuadrature(
lowerLimit,
upperLimit,
[this](double u) { return approximatedDerivative(u); }
);
}
glm::dvec3 PathCurve::interpolate(double u) {
ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable out of range [0, 1]");
if (u < 0.0) {
return _points[1];
}
if (u > 1.0) {
return *(_points.end() - 2);
}
std::vector<double>::iterator segmentEndIt =
std::lower_bound(_curveParameterSteps.begin(), _curveParameterSteps.end(), u);
const int index =
static_cast<int>((segmentEndIt - 1) - _curveParameterSteps.begin());
double segmentStart = _curveParameterSteps[index];
double segmentDuration = (_curveParameterSteps[index + 1] - segmentStart);
double uSegment = (u - segmentStart) / segmentDuration;
return interpolation::catmullRom(
uSegment,
_points[index],
_points[index + 1],
_points[index + 2],
_points[index + 3],
1.0 // chordal version
);
}
LinearCurve::LinearCurve(const Waypoint& start, const Waypoint& end) {
_points.push_back(start.position());
_points.push_back(start.position());
_points.push_back(end.position());
_points.push_back(end.position());
initializeParameterData();
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,190 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/pathcurves/avoidcollisioncurve.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
namespace {
constexpr const char* _loggerCat = "AvoidCollisionCurve";
constexpr const double CloseToNodeThresholdFactor = 5.0;
constexpr const double AvoidCollisionDistanceFactor = 3.0;
constexpr const double CollisionBufferSizeFactor = 1.0;
constexpr const int MaxAvoidCollisionSteps = 10;
} // namespace
namespace openspace::interaction {
AvoidCollisionCurve::AvoidCollisionCurve(const Waypoint& start, const Waypoint& end) {
_relevantNodes = global::navigationHandler->pathNavigator().relevantNodes();
const glm::dvec3 startNodeCenter = start.node()->worldPosition();
const glm::dvec3 endNodeCenter = end.node()->worldPosition();
const double startNodeRadius = start.validBoundingSphere;
const double endNodeRadius = end.validBoundingSphere;
const glm::dvec3 startViewDir = start.rotation() * glm::dvec3(0.0, 0.0, -1.0);
// Add control points for a catmull-rom spline, first and last will not be intersected
_points.push_back(start.position());
_points.push_back(start.position());
// Add an extra point to first go backwards if starting close to planet
glm::dvec3 nodeToStart = start.position() - startNodeCenter;
double distanceToStartNode = glm::length(nodeToStart);
if (distanceToStartNode < CloseToNodeThresholdFactor * startNodeRadius) {
double distance = startNodeRadius;
glm::dvec3 newPos = start.position() + distance * glm::normalize(nodeToStart);
_points.push_back(newPos);
}
// Add point for moving out if the end state is in opposite direction
glm::dvec3 startToEnd = end.position() - start.position();
double cosAngleToTarget = glm::dot(normalize(-startViewDir), normalize(startToEnd));
bool targetInOppositeDirection = cosAngleToTarget > 0.7;
if (targetInOppositeDirection) {
const glm::dquat midleRot = glm::slerp(start.rotation(), end.rotation(), 0.5);
const glm::dvec3 middleViewDir = midleRot * glm::dvec3(0.0, 0.0, -1.0);
const double stepOutDistance = 0.4 * glm::length(startToEnd);
glm::dvec3 newPos = start.position() + 0.2 * startToEnd -
stepOutDistance * glm::normalize(middleViewDir);
_points.push_back(newPos);
}
// Add an extra point to approach target
const glm::dvec3 nodeToEnd = end.position() - endNodeCenter;
const double distanceToEndNode = glm::length(nodeToEnd);
if (distanceToEndNode < CloseToNodeThresholdFactor * endNodeRadius) {
double distance = endNodeRadius;
glm::dvec3 newPos = end.position() + distance * glm::normalize(nodeToEnd);
_points.push_back(newPos);
}
_points.push_back(end.position());
_points.push_back(end.position());
// Create extra points to avoid collision
removeCollisions();
initializeParameterData();
}
// Try to reduce the risk of collision by approximating the curve with linear segments.
// If a collision happens, create a new point for the path to go through, in an attempt to
// avoid that collision
void AvoidCollisionCurve::removeCollisions(int step) {
if (step > MaxAvoidCollisionSteps) {
return;
}
const int nSegments = static_cast<int>( _points.size() - 3);
for (int i = 0; i < nSegments; ++i) {
const glm::dvec3 lineStart = _points[i + 1];
const glm::dvec3 lineEnd = _points[i + 2];
for (SceneGraphNode* node : _relevantNodes) {
// Do collision check in relative coordinates, to avoid huge numbers
const glm::dmat4 modelTransform = node->modelTransform();
glm::dvec3 p1 = glm::inverse(modelTransform) * glm::dvec4(lineStart, 1.0);
glm::dvec3 p2 = glm::inverse(modelTransform) * glm::dvec4(lineEnd, 1.0);
// Sphere to check for collision
double radius = node->boundingSphere();
glm::dvec3 center = glm::dvec3(0.0, 0.0, 0.0);
// Add a buffer to avoid passing too close to the node.
// Dont't add it if any point is inside the buffer
double buffer = CollisionBufferSizeFactor * node->boundingSphere();
bool p1IsInside = helpers::isPointInsideSphere(p1, center, radius + buffer);
bool p2IsInside = helpers::isPointInsideSphere(p2, center, radius + buffer);
if (!p1IsInside && !p2IsInside) {
radius += buffer;
}
glm::dvec3 intersectionPointModelCoords;
bool collision = helpers::lineSphereIntersection(
p1,
p2,
center,
radius,
intersectionPointModelCoords
);
if (collision) {
glm::dvec3 collisionPoint = modelTransform *
glm::dvec4(intersectionPointModelCoords, 1.0);
// before collision response, make sure none of the points are inside the node
bool isStartInsideNode = helpers::isPointInsideSphere(p1, center, radius);
bool isEndInsideNode = helpers::isPointInsideSphere(p2, center, radius);
if (isStartInsideNode || isEndInsideNode) {
LWARNING(fmt::format(
"Something went wrong! "
"At least one point in the path is inside node: {}",
node->identifier()
));
break;
}
// To avoid collision, take a step in an orhtogonal direction of the
// collision point and add a new point
const glm::dvec3 lineDirection = glm::normalize(lineEnd - lineStart);
const glm::dvec3 nodeCenter = node->worldPosition();
const glm::dvec3 collisionPointToCenter = nodeCenter - collisionPoint;
const glm::dvec3 parallell = glm::proj(collisionPointToCenter, lineDirection);
const glm::dvec3 orthogonal = collisionPointToCenter - parallell;
const double avoidCollisionDistance = AvoidCollisionDistanceFactor * radius;
glm::dvec3 extraKnot = collisionPoint -
avoidCollisionDistance * glm::normalize(orthogonal);
_points.insert(_points.begin() + i + 2, extraKnot);
step++;
removeCollisions(step);
break;
}
}
}
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,103 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/pathcurves/zoomoutoverviewcurve.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/navigation/waypoint.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
namespace {
constexpr const char* _loggerCat = "ZoomOutOverviewCurve";
} // namespace
namespace openspace::interaction {
// Go far out to get a view of both tagets, aimed to match lookAt orientation
ZoomOutOverviewCurve::ZoomOutOverviewCurve(const Waypoint& start, const Waypoint& end) {
const double startNodeRadius = start.validBoundingSphere;
const double endNodeRadius = end.validBoundingSphere;
const double endTangentsLengthFactor = 2.0;
const double startTangentLength = endTangentsLengthFactor * startNodeRadius;
const double endTangentLength = endTangentsLengthFactor * endNodeRadius;
const glm::dvec3 startNodePos = start.node()->worldPosition();
const glm::dvec3 endNodePos = end.node()->worldPosition();
const glm::dvec3 startTangentDir = normalize(start.position() - startNodePos);
const glm::dvec3 endTangentDir = normalize(end.position() - endNodePos);
// Start by going outwards
_points.push_back(start.position());
_points.push_back(start.position());
_points.push_back(start.position() + startTangentLength * startTangentDir);
// Zoom out
if (start.nodeIdentifier != end.nodeIdentifier) {
const glm::dvec3 n1 = startTangentDir;
const glm::dvec3 n2 = endTangentDir;
// Decide the step direction for the "overview point" based on the directions
// at the start and end of the path, to try to get a nice curve shape
glm::dvec3 goodStepDirection;
if (glm::dot(n1, n2) < 0.0) {
// Facing in different directions => step in direction of the cross product
goodStepDirection = glm::normalize(glm::cross(-n1, n2));
}
else {
goodStepDirection = glm::normalize(n1 + n2);
}
// Find a direction that is orthogonal to the line between the start and end position
const glm::dvec3 startPosToEndPos = end.position() - start.position();
const glm::dvec3 outwardStepVector =
0.5 * glm::length(startPosToEndPos) * goodStepDirection;
const glm::dvec3 projectedVec = glm::proj(outwardStepVector, startPosToEndPos);
const glm::dvec3 orthogonalComponent = outwardStepVector - projectedVec;
const glm::dvec3 stepDirection = glm::normalize(orthogonalComponent);
// Step half-way along the line between the position and then orthogonally
const glm::dvec3 extraKnot = start.position() + 0.5 * startPosToEndPos
+ 1.5 * glm::length(startPosToEndPos) * stepDirection;
_points.push_back(extraKnot);
}
// Closing in on end node
_points.push_back(end.position() + endTangentLength * endTangentDir);
_points.push_back(end.position());
_points.push_back(end.position());
initializeParameterData();
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,295 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/pathhelperfunctions.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/easing.h>
namespace {
constexpr const char* _loggerCat = "Helpers";
const double Epsilon = 1E-7;
} // namespace
namespace openspace::interaction::helpers {
// Shift and scale to a subinterval [start,end]
double shiftAndScale(double t, double start, double end) {
ghoul_assert(0.0 < start && start < end&& end < 1.0,
"Values must be 0.0 < start < end < 1.0!");
double tScaled = t / (end - start) - start;
return std::max(0.0, std::min(tScaled, 1.0));
}
glm::dquat lookAtQuaternion(glm::dvec3 eye, glm::dvec3 center, glm::dvec3 up) {
glm::dmat4 lookAtMat = glm::lookAt(eye, center, up);
return glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
}
glm::dvec3 viewDirection(const glm::dquat& q) {
return glm::normalize(q * glm::dvec3(0.0, 0.0, -1.0));
};
/*
* Calculate the intersection of a line and a sphere
* The line segment is defined from p1 to p2
* The sphere is of radius r and centered at sc
* There are potentially two points of intersection given by
* p = p1 + mu1 (p2 - p1)
* p = p1 + mu2 (p2 - p1)
* Source: http://paulbourke.net/geometry/circlesphere/raysphere.c
*/
bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 sc,
double r, glm::dvec3& intersectionPoint)
{
long double a, b, c;
glm::dvec3 dp = p2 - p1;
a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;
b = 2 * (dp.x * (p1.x - sc.x) + dp.y * (p1.y - sc.y) + dp.z * (p1.z - sc.z));
c = sc.x * sc.x + sc.y * sc.y + sc.z * sc.z;
c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
c -= 2 * (sc.x * p1.x + sc.y * p1.y + sc.z * p1.z);
c -= r * r;
long double intersectionTest = b * b - 4.0 * a * c;
// no intersection
if (std::abs(a) < Epsilon || intersectionTest < 0.0) {
return false;
}
else {
// only care about the first intersection point if we have two
const double t = (-b - std::sqrt(intersectionTest)) / (2.0 *a);
if (t <= Epsilon || t >= abs(1.0 - Epsilon)) return false;
intersectionPoint = p1 + t * dp;
return true;
}
}
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r) {
const glm::dvec3 v = c - p;
const long double squaredDistance = v.x * v.x + v.y * v.y + v.z * v.z;
const long double squaredRadius = r * r;
return (squaredDistance <= squaredRadius);
}
double simpsonsRule(double t0, double t1, int n, std::function<double(double)> f) {
const double h = (t1 - t0) / static_cast<double>(n);
const double endpoints = f(t0) + f(t1);
double times4 = 0.0;
double times2 = 0.0;
// weight 4
for (int i = 1; i < n; i += 2) {
double t = t0 + i * h;
times4 += f(t);
}
// weight 2
for (int i = 2; i < n; i += 2) {
double t = t0 + i * h;
times2 += f(t);
}
return (h / 3) * (endpoints + 4 * times4 + 2 * times2);
}
/*
* Approximate area under a function using 5-point Gaussian quadrature
* https://en.wikipedia.org/wiki/Gaussian_quadrature
*/
double fivePointGaussianQuadrature(double t0, double t1,
std::function<double(double)> f)
{
struct GaussLengendreCoefficient {
double abscissa; // xi
double weight; // wi
};
static constexpr GaussLengendreCoefficient coefficients[] = {
{ 0.0, 0.5688889 },
{ -0.5384693, 0.47862867 },
{ 0.5384693, 0.47862867 },
{ -0.90617985, 0.23692688 },
{ 0.90617985, 0.23692688 }
};
const double a = t0;
const double b = t1;
double sum = 0.0;
for (auto coefficient : coefficients) {
// change of interval to [a, b] from [-1, 1] (also 0.5 * (b - a) below)
double const t = 0.5 * ((b - a) * coefficient.abscissa + (b + a));
sum += f(t) * coefficient.weight;
}
return 0.5 * (b - a) * sum;
}
} // helpers
namespace openspace::interaction::interpolation {
glm::dquat easedSlerp(const glm::dquat q1, const glm::dquat q2, double t) {
double tScaled = helpers::shiftAndScale(t, 0.1, 0.9);
tScaled = ghoul::sineEaseInOut(tScaled);
return glm::slerp(q1, q2, tScaled);
}
// Based on implementation by Mika Rantanen
// https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
glm::dvec3 catmullRom(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3, double alpha)
{
glm::dvec3 m01, m02, m23, m13;
double t01 = pow(glm::distance(p0, p1), alpha);
double t12 = pow(glm::distance(p1, p2), alpha);
double t23 = pow(glm::distance(p2, p3), alpha);
m01 = (t01 > Epsilon) ? (p1 - p0) / t01 : glm::dvec3{};
m23 = (t23 > Epsilon) ? (p3 - p2) / t23 : glm::dvec3{};
m02 = (t01 + t12 > Epsilon) ? (p2 - p0) / (t01 + t12) : glm::dvec3{};
m13 = (t12 + t23 > Epsilon) ? (p3 - p1) / (t12 + t23) : glm::dvec3{};
glm::dvec3 m1 = p2 - p1 + t12 * (m01 - m02);
glm::dvec3 m2 = p2 - p1 + t12 * (m23 - m13);
glm::dvec3 a = 2.0 * (p1 - p2) + m1 + m2;
glm::dvec3 b = -3.0 * (p1 - p2) - m1 - m1 - m2;
glm::dvec3 c = m1;
glm::dvec3 d = p1;
return a * t * t * t
+ b * t * t
+ c * t
+ d;
}
glm::dvec3 cubicBezier(double t, const glm::dvec3& cp1, const glm::dvec3& cp2,
const glm::dvec3& cp3, const glm::dvec3& cp4)
{
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
double a = 1.0 - t;
return cp1 * a * a * a
+ cp2 * t * a * a * 3.0
+ cp3 * t * t * a * 3.0
+ cp4 * t * t * t;
}
glm::dvec3 linear(double t, const glm::dvec3 &cp1, const glm::dvec3 &cp2) {
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
return cp1 * (1.0 - t) + cp2 * t;
}
glm::dvec3 hermite(double t, const glm::dvec3 &p1, const glm::dvec3 &p2,
const glm::dvec3 &tangent1, const glm::dvec3 &tangent2)
{
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
if (t <= 0.0) return p1;
if (t >= 1.0) return p2;
const double t2 = t * t;
const double t3 = t2 * t;
// calculate basis functions
double const a0 = (2.0 * t3) - (3.0 * t2) + 1.0;
double const a1 = (-2.0 * t3) + (3.0 * t2);
double const b0 = t3 - (2.0 * t2) + t;
double const b1 = t3 - t2;
return (a0 * p1) + (a1 * p2) + (b0 * tangent1) + (b1 * tangent2);
}
// uniform if tKnots are equally spaced, or else non uniform
glm::dvec3 piecewiseCubicBezier(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots)
{
ghoul_assert(
points.size() > 4,
"Minimum of four control points needed for interpolation"
);
ghoul_assert(
(points.size() - 1) % 3 == 0,
"A vector containing 3n + 1 control points must be provided"
);
int nrSegments = (points.size() - 1) / 3;
ghoul_assert(
rSegments == (tKnots.size() - 1),
"Number of interval times must match number of segments"
);
if (t <= 0.0) return points.front();
if (t >= 1.0) return points.back();
// compute current segment index
std::vector<double>::const_iterator segmentEndIt =
std::lower_bound(tKnots.begin(), tKnots.end(), t);
unsigned int segmentIdx = (segmentEndIt - 1) - tKnots.begin();
double segmentStart = tKnots[segmentIdx];
double segmentDuration = (tKnots[segmentIdx + 1] - tKnots[segmentIdx]);
double tScaled = (t - segmentStart) / segmentDuration;
unsigned int idx = segmentIdx * 3;
// Interpolate using De Casteljau's algorithm
return interpolation::cubicBezier(
tScaled,
points[idx],
points[idx + 1],
points[idx + 2],
points[idx + 3]
);
}
glm::dvec3 piecewiseLinear(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots)
{
ghoul_assert(points.size() == tKnots.size(), "Must have equal number of points and times!");
ghoul_assert(points.size() > 2, "Minimum of two control points needed for interpolation!");
size_t nrSegments = points.size() - 1;
if (t <= 0.0) return points.front();
if (t >= 1.0) return points.back();
// compute current segment index
std::vector<double>::const_iterator segmentEndIt =
std::lower_bound(tKnots.begin(), tKnots.end(), t);
unsigned int idx = (segmentEndIt - 1) - tKnots.begin();
double segmentStart = tKnots[idx];
double segmentDuration = (tKnots[idx + 1] - tKnots[idx]);
double tScaled = (t - segmentStart) / segmentDuration;
return interpolation::linear(tScaled, points[idx], points[idx + 1]);
}
} // interpolation

View File

@@ -0,0 +1,597 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/pathnavigator.h>
#include <openspace/camera/camera.h>
#include <openspace/camera/camerapose.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/pathcreator.h>
#include <openspace/navigation/pathhelperfunctions.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/timemanager.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/quaternion.hpp>
#include <vector>
namespace {
constexpr const char* _loggerCat = "PathNavigator";
constexpr openspace::properties::Property::PropertyInfo DefaultCurveOptionInfo = {
"DefaultCurveOption",
"Default Curve Option",
"The defualt curve type chosen when generating a path, if none is specified"
// TODO: right now there is no way to specify a type for a single path
};
constexpr openspace::properties::Property::PropertyInfo IncludeRollInfo = {
"IncludeRoll",
"Include Roll",
"If disabled, roll is removed from the interpolation of camera orientation"
};
constexpr openspace::properties::Property::PropertyInfo StopBehaviorInfo = {
"StopBehavior",
"Stop Behavior",
"A camera motion behavior that is applied when no path is being played"
};
constexpr openspace::properties::Property::PropertyInfo
ApplyStopBehaviorWhenIdleInfo =
{
"ApplyStopBehaviorWhenIdle",
"Apply Stop Behavior When Idle",
"If enabled, the camera is controlled using the set stop behavior when "
"no path is playing"
};
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
"SpeedScale",
"Speed Scale",
"Scale factor that affects the default speed for a camera path."
};
constexpr openspace::properties::Property::PropertyInfo OrbitSpeedFactorInfo = {
"OrbitSpeedFactor",
"Orbit Speed Factor",
"Controls the speed of the orbiting around an anchor."
};
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo = {
"MinimalValidBoundingSphere",
"Minimal Valid Bounding Sphere",
"The minimal allowed value for a bounding sphere, in meters. Used for "
"computation of target positions and path generation, to avoid issues when "
"there is no bounding sphere."
};
constexpr openspace::properties::Property::PropertyInfo RelevantNodeTagsInfo = {
"RelevantNodeTags",
"Relevant Node Tags",
"List of tags for the nodes that are relevant for path creation, for example "
"when avoiding collisions."
};
} // namespace
#include "pathnavigator_lua.inl"
namespace openspace::interaction {
PathNavigator::PathNavigator()
: properties::PropertyOwner({ "PathNavigator" })
, _defaultCurveOption(
DefaultCurveOptionInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _includeRoll(IncludeRollInfo, false)
, _stopBehavior(
StopBehaviorInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _applyStopBehaviorWhenIdle(ApplyStopBehaviorWhenIdleInfo, false)
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
, _orbitSpeedFactor(OrbitSpeedFactorInfo, 0.5, 0.0, 20.0)
, _minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
, _relevantNodeTags(RelevantNodeTagsInfo)
{
_defaultCurveOption.addOptions({
{ Path::CurveType::AvoidCollision, "AvoidCollision" },
{ Path::CurveType::Linear, "Linear" },
{ Path::CurveType::ZoomOutOverview, "ZoomOutOverview"}
});
addProperty(_defaultCurveOption);
addProperty(_includeRoll);
addProperty(_speedScale);
// OBS! Stop behavior is broken as of core merge
//addProperty(_applyStopBehaviorWhenIdle);
//// Must be listed in the same order as in enum definition
//_stopBehavior.addOptions({
// { StopBehavior::None, "None" },
// { StopBehavior::Orbit, "Orbit" }
//});
//_stopBehavior = StopBehavior::None;
//addProperty(_stopBehavior);
//addProperty(_orbitSpeedFactor);
addProperty(_minValidBoundingSphere);
_relevantNodeTags = std::vector<std::string>{
"planet_solarSystem",
"moon_solarSystem"
};;
_relevantNodeTags.onChange([this]() { findRelevantNodes(); });
addProperty(_relevantNodeTags);
}
PathNavigator::~PathNavigator() {} // NOLINT
Camera* PathNavigator::camera() const {
return global::navigationHandler->camera();
}
const SceneGraphNode* PathNavigator::anchor() const {
return global::navigationHandler->anchorNode();
}
double PathNavigator::speedScale() const {
return _speedScale;
}
bool PathNavigator::hasCurrentPath() const {
return _currentPath != nullptr;
}
bool PathNavigator::hasFinished() const {
if (!hasCurrentPath()) {
return true;
}
return _currentPath->hasReachedEnd();
}
bool PathNavigator::isPlayingPath() const {
return !hasFinished();
}
void PathNavigator::updateCamera(double deltaTime) {
ghoul_assert(camera() != nullptr, "Camera must not be nullptr");
if (!hasCurrentPath()) {
return;
}
if (!_isPlaying) {
//// TODO: Determine how this should work
//// OBS! Stop behavior is broken as of core merge
//if (hasFinished() && _applyStopBehaviorWhenIdle) {
// applyStopBehavior(deltaTime);
//}
return;
}
// If for some reason the time is no longer paused, pause it again
// TODO: Before we get here, one time tick happens. Should move this check to engine
if (!global::timeManager->isPaused()) {
global::timeManager->setPause(true);
LINFO("Cannot start simulation time during camera motion");
}
CameraPose newPose = _currentPath->traversePath(deltaTime);
const std::string newAnchor = _currentPath->currentAnchor();
// Set anchor node in orbitalNavigator, to render visible nodes and add activate
// navigation when we reach the end.
std::string currentAnchor = anchor()->identifier();
if (currentAnchor != newAnchor) {
global::navigationHandler->orbitalNavigator().setAnchorNode(newAnchor);
}
if (!_includeRoll) {
removeRollRotation(newPose, deltaTime);
}
camera()->setPositionVec3(newPose.position);
camera()->setRotation(newPose.rotation);
if (_currentPath->hasReachedEnd()) {
LINFO("Reached end of path");
_isPlaying = false;
return;
}
}
void PathNavigator::createPath(const ghoul::Dictionary& dictionary) {
// TODO: Improve how curve types are handled
const int curveType = _defaultCurveOption;
// Ignore paths that are created during session recording, as the camera
// position should have been recorded
if (global::sessionRecording->isPlayingBack()) {
return;
}
clearPath();
try {
_currentPath = std::make_unique<Path>(
PathCreator::createPath(dictionary, Path::CurveType(curveType))
);
}
catch (const ghoul::RuntimeError& e) {
LERROR("Could not create path");
return;
}
LINFO("Successfully generated camera path");
}
void PathNavigator::clearPath() {
LINFO("Clearing path...");
_currentPath = nullptr;
}
void PathNavigator::startPath() {
if (!hasCurrentPath()) {
LERROR("There is no path to start");
return;
}
//OBS! Until we can handle simulation time: early out if not paused
if (!global::timeManager->isPaused()) {
LERROR("Simulation time must be paused to run a camera path");
return;
}
LINFO("Starting path...");
_isPlaying = true;
}
void PathNavigator::abortPath() {
if (!_isPlaying) {
LWARNING("No camera path is playing");
return;
}
_isPlaying = false;
clearPath(); // TODO: instead of clearing this could be handled better
LINFO("Aborted camera path");
}
void PathNavigator::pausePath() {
if (hasFinished()) {
LERROR("No path to pause (path is empty or has finished).");
return;
}
if (!_isPlaying) {
LERROR("Cannot pause a path that is not playing");
return;
}
LINFO("Path paused");
_isPlaying = false;
}
void PathNavigator::continuePath() {
if (hasFinished()) {
LERROR("No path to resume (path is empty or has finished).");
return;
}
if (_isPlaying) {
LERROR("Cannot resume a path that is already playing");
return;
}
LINFO("Continuing path...");
_isPlaying = true;
}
// Created for debugging
std::vector<glm::dvec3> PathNavigator::curvePositions(int nSteps) const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dvec3> positions;
const double du = 1.0 / nSteps;
const double length = _currentPath->pathLength();
for (double u = 0.0; u < 1.0; u += du) {
glm::dvec3 position = _currentPath->interpolatedPose(u * length).position;
positions.push_back(position);
}
positions.push_back(_currentPath->endPoint().position());
return positions;
}
// Created for debugging
std::vector<glm::dquat> PathNavigator::curveOrientations(int nSteps) const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dquat> orientations;
const double du = 1.0 / nSteps;
const double length = _currentPath->pathLength();
for (double u = 0.0; u <= 1.0; u += du) {
const glm::dquat orientation =
_currentPath->interpolatedPose(u * length).rotation;
orientations.push_back(orientation);
}
orientations.push_back(_currentPath->endPoint().rotation());
return orientations;
}
// Created for debugging
std::vector<glm::dvec3> PathNavigator::curveViewDirections(int nSteps) const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dvec3> viewDirections;
const double du = 1.0 / nSteps;
for (double u = 0.0; u < 1.0; u += du) {
const glm::dquat orientation = _currentPath->interpolatedPose(u).rotation;
const glm::dvec3 direction = glm::normalize(
orientation * glm::dvec3(0.0, 0.0, -1.0)
);
viewDirections.push_back(direction);
}
const glm::dquat orientation = _currentPath->interpolatedPose(1.0).rotation;
const glm::dvec3 direction = glm::normalize(
orientation * glm::dvec3(0.0, 0.0, -1.0)
);
viewDirections.push_back(direction);
return viewDirections;
}
// Created for debugging
std::vector<glm::dvec3> PathNavigator::controlPoints() const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dvec3> points;
const std::vector<glm::dvec3> curvePoints = _currentPath->controlPoints();
points.insert(points.end(), curvePoints.begin(), curvePoints.end());
return points;
}
double PathNavigator::minValidBoundingSphere() const {
return _minValidBoundingSphere;
}
const std::vector<SceneGraphNode*>& PathNavigator::relevantNodes() {
if (!_hasInitializedRelevantNodes) {
findRelevantNodes();
_hasInitializedRelevantNodes = true;
}
return _relevantNodes;
}
void PathNavigator::findRelevantNodes() {
const std::vector<SceneGraphNode*>& allNodes =
global::renderEngine->scene()->allSceneGraphNodes();
const std::vector<std::string> relevantTags = _relevantNodeTags;
if (allNodes.empty() || relevantTags.empty()) {
_relevantNodes = std::vector<SceneGraphNode*>();
return;
}
auto isRelevant = [&](const SceneGraphNode* node) {
const std::vector<std::string> tags = node->tags();
auto result = std::find_first_of(
relevantTags.begin(),
relevantTags.end(),
tags.begin(),
tags.end()
);
// does not match any tags => not interesting
if (result == relevantTags.end()) {
return false;
}
return node->renderable() && (node->boundingSphere() > 0.0);
};
std::vector<SceneGraphNode*> resultingNodes;
std::copy_if(
allNodes.begin(),
allNodes.end(),
std::back_inserter(resultingNodes),
isRelevant
);
_relevantNodes = resultingNodes;
}
void PathNavigator::removeRollRotation(CameraPose& pose, double deltaTime) {
const glm::dvec3 anchorPos = anchor()->worldPosition();
const glm::dvec3 cameraDir = glm::normalize(
pose.rotation * Camera::ViewDirectionCameraSpace
);
const double anchorToPosDistance = glm::distance(anchorPos, pose.position);
const double notTooCloseDistance = deltaTime * anchorToPosDistance;
glm::dvec3 lookAtPos = pose.position + notTooCloseDistance * cameraDir;
glm::dquat rollFreeRotation = helpers::lookAtQuaternion(
pose.position,
lookAtPos,
camera()->lookUpVectorWorldSpace()
);
pose.rotation = rollFreeRotation;
}
void PathNavigator::applyStopBehavior(double deltaTime) {
switch (_stopBehavior) {
case StopBehavior::None:
// Do nothing
break;
case StopBehavior::Orbit:
orbitAnchorNode(deltaTime);
break;
default:
throw ghoul::MissingCaseException();
}
}
void PathNavigator::orbitAnchorNode(double deltaTime) {
ghoul_assert(anchor() != nullptr, "Node to orbit must be set!");
const glm::dvec3 prevPosition = camera()->positionVec3();
const glm::dquat prevRotation = camera()->rotationQuaternion();
const glm::dvec3 nodeCenter = anchor()->worldPosition();
const double speedFactor = 0.1 * _orbitSpeedFactor;
// Compute orbit speed based on factor and distance to surface
const double orbitRadius = glm::distance(prevPosition, nodeCenter);
const double distanceToSurface = orbitRadius - anchor()->boundingSphere();
const double orbitSpeed = distanceToSurface * speedFactor;
// Compute a new position along the orbit
const glm::dvec3 up = camera()->lookUpVectorWorldSpace();
const glm::dquat lookAtNodeRotation = helpers::lookAtQuaternion(
prevPosition,
nodeCenter,
up
);
const glm::dvec3 targetForward = lookAtNodeRotation * glm::dvec3(0.0, 0.0, -1.0);
const glm::dvec3 rightOrbitTangent = glm::normalize(glm::cross(targetForward, up));
glm::dvec3 newPosition = prevPosition + orbitSpeed * deltaTime * rightOrbitTangent;
// Adjust for numerical error - make sure we stay at the same height
const glm::dvec3 nodeToNewPos = newPosition - nodeCenter;
const double targetHeight = glm::distance(prevPosition, nodeCenter);
const double heightDiff = glm::length(nodeToNewPos) - targetHeight;
newPosition -= heightDiff * glm::normalize(nodeToNewPos);
// Rotate along the orbit, but keep relative orientation with regards to the anchor
const glm::dquat localRotation = glm::inverse(lookAtNodeRotation) * prevRotation;
const glm::dquat newLookAtRotation =
helpers::lookAtQuaternion(newPosition, nodeCenter, up);
const glm::dquat newRotation = newLookAtRotation * localRotation;
camera()->setPositionVec3(newPosition);
camera()->setRotation(newRotation);
}
scripting::LuaLibrary PathNavigator::luaLibrary() {
return {
"pathnavigation",
{
{
"isFlying",
&luascriptfunctions::isFlying,
{},
"",
"Returns true if a camera path is currently running, and false otherwise"
},
{
"continuePath",
&luascriptfunctions::continuePath,
{},
"",
"Continue playing a paused camera path"
},
{
"pausePath",
&luascriptfunctions::pausePath,
{},
"",
"Pause a playing camera path"
},
{
"stopPath",
&luascriptfunctions::stopPath,
{},
"",
"Stops a path, if one is being played"
},
{
"goTo",
&luascriptfunctions::goTo,
{},
"string [, bool, double]",
"Move the camera to the node with the specified name. The optional double "
"specifies the duration of the motion. If the optional bool is set to true "
"the target up vector for camera is set based on the target node. Either of "
"the optional parameters can be left out."
},
{
"goToHeight",
&luascriptfunctions::goToHeight,
{},
"string, double [, bool, double]",
"Move the camera to the node with the specified name. The second input "
"parameter is the desired target height. The optional double "
"specifies the duration of the motion. If the optional bool is set to true "
"the target up vector for camera is set based on the target node. Either of "
"the optional parameters can be left out."
},
//{
// "goToGeo",
// &luascriptfunctions::goToGeo,
// {},
// "string, double, double, double [, bool, double]",
// "Move the camera to the globe with the name given by the input string. "
// "The next three input parameters are latitude, longitude and altitude. "
// "The optional double specifies the duration of the motion. If the optional "
// "bool is set to true the target up vector for camera is set based on the "
// "target node. Either of the optional parameters can be left out."
//},
{
"generatePath",
&luascriptfunctions::generatePath,
{},
"table",
"Generate the path as described by the lua table input argument"
},
}
};
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,272 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
//#include <modules/globebrowsing/globebrowsingmodule.h> // TODO: remove dependancy
//#include <modules/globebrowsing/src/renderableglobe.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/updatestructures.h>
#include <openspace/query/query.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/vector_angle.hpp>
namespace {
constexpr const double Epsilon = 1e-12;
} // namespace
namespace openspace::luascriptfunctions {
int isFlying(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::isFlying");
bool hasFinished = global::navigationHandler->pathNavigator().hasFinished();
ghoul::lua::push(L, !hasFinished);
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
int continuePath(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::continuePath");
global::navigationHandler->pathNavigator().continuePath();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int pausePath(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::pausePath");
global::navigationHandler->pathNavigator().pausePath();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int stopPath(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPath");
global::navigationHandler->pathNavigator().abortPath();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
// All the goTo function has the same two optional input parameters at the end. The
// purpose of this function is to handle these input parameters and add the result
// to the dictionary specifying the instruction for a camera path.
int handleOptionalGoToParameters(lua_State* L, const int startLocation,
const int nArguments,
ghoul::Dictionary& resultInstruction)
{
const bool firstIsNumber = (lua_isnumber(L, startLocation) != 0);
const bool firstIsBool = (lua_isboolean(L, startLocation) != 0);
if (!(firstIsNumber || firstIsBool)) {
const char* msg = lua_pushfstring(
L,
"%s or %s expected, got %s",
lua_typename(L, LUA_TNUMBER),
lua_typename(L, LUA_TBOOLEAN),
luaL_typename(L, -1)
);
return ghoul::lua::luaError(
L, fmt::format("bad argument #{} ({})", startLocation, msg)
);
}
int location = startLocation;
if (firstIsBool) {
const bool useUpFromTarget = (lua_toboolean(L, location) == 1);
resultInstruction.setValue("UseTargetUpDirection", useUpFromTarget);
if (nArguments > startLocation) {
location++;
}
}
if (firstIsNumber || nArguments > startLocation) {
double duration = ghoul::lua::value<double>(L, location);
if (duration <= Epsilon) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, "Duration must be larger than zero.");
}
resultInstruction.setValue("Duration", duration);
}
return 0;
}
int goTo(lua_State* L) {
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo");
const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
if (!sceneGraphNode(nodeIdentifier)) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
}
using namespace std::string_literals;
ghoul::Dictionary insDict;
insDict.setValue("Type", "Node"s);
insDict.setValue("Target", nodeIdentifier);
if (nArguments > 1) {
int result = handleOptionalGoToParameters(L, 2, nArguments, insDict);
if (result != 0) {
return result; // An error occurred
}
}
global::navigationHandler->pathNavigator().createPath(insDict);
if (global::navigationHandler->pathNavigator().hasCurrentPath()) {
global::navigationHandler->pathNavigator().startPath();
}
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int goToHeight(lua_State* L) {
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight");
const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
if (!sceneGraphNode(nodeIdentifier)) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
}
double height = ghoul::lua::value<double>(L, 2);
using namespace std::string_literals;
ghoul::Dictionary insDict;
insDict.setValue("Type", "Node"s);
insDict.setValue("Target", nodeIdentifier);
insDict.setValue("Height", height);
if (nArguments > 2) {
int result = handleOptionalGoToParameters(L, 3, nArguments, insDict);
if (result != 0) {
return result; // An error occurred
}
}
global::navigationHandler->pathNavigator().createPath(insDict);
if (global::navigationHandler->pathNavigator().hasCurrentPath()) {
global::navigationHandler->pathNavigator().startPath();
}
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
//// @TODO (emmbr 2020-11-06) Ideally, this module shouldn't depend on things from
//// Globebrowsing, but we want it for an istallation. Later on, move this functionality
//// somewhere else. Maybe combine with the existing "goToGeo" in globebrowsing?
//int goToGeo(lua_State* L) {
// int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 4, 6 }, "lua::goToGeo");
//
// const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
// const SceneGraphNode* n = sceneGraphNode(nodeIdentifier);
// if (!n) {
// lua_settop(L, 0);
// return ghoul::lua::luaError(L, "Unknown globe name: " + nodeIdentifier);
// }
//
// const double latitude = ghoul::lua::value<double>(L, 2);
// const double longitude = ghoul::lua::value<double>(L, 3);
// const double altitude = ghoul::lua::value<double>(L, 4);
//
// using RenderableGlobe = openspace::globebrowsing::RenderableGlobe;
// const RenderableGlobe* globe = dynamic_cast<const RenderableGlobe*>(n->renderable());
// if (!globe) {
// return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe");
// }
//
// // Compute the relative position based on the input values
// glm::dvec3 positionModelCoords = global::moduleEngine->module<GlobeBrowsingModule>()
// ->cartesianCoordinatesFromGeo(
// *globe,
// latitude,
// longitude,
// altitude
// );
//
// using namespace std::string_literals;
// ghoul::Dictionary insDict;
// insDict.setValue("Type", "Node"s);
// insDict.setValue("Target", nodeIdentifier);
// insDict.setValue("Position", positionModelCoords);
//
// if (nArguments > 4) {
// int result = handleOptionalGoToParameters(L, 5, nArguments, insDict);
// if (result != 0) {
// return result; // An error occurred
// }
// }
//
// global::navigationHandler->pathNavigator().createPath(insDict);
//
// if (global::navigationHandler->pathNavigator().hasCurrentPath()) {
// global::navigationHandler->pathNavigator().startPath();
// }
//
// lua_settop(L, 0);
// ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
// return 0;
//}
int generatePath(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::generatePath");
ghoul::Dictionary dictionary;
ghoul::lua::luaDictionaryFromState(L, dictionary);
global::navigationHandler->pathNavigator().createPath(dictionary);
if (global::navigationHandler->pathNavigator().hasCurrentPath()) {
global::navigationHandler->pathNavigator().startPath();
}
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
} // namespace openspace::luascriptfunctions

117
src/navigation/waypoint.cpp Normal file
View File

@@ -0,0 +1,117 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/navigation/waypoint.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* _loggerCat = "Waypoint";
} // namespace
namespace openspace::interaction {
Waypoint::Waypoint(const glm::dvec3& pos, const glm::dquat& rot, const std::string& ref)
: nodeIdentifier(ref)
{
pose = { pos, rot };
const SceneGraphNode* node = sceneGraphNode(nodeIdentifier);
if (!node) {
LERROR(fmt::format("Could not find node '{}'", nodeIdentifier));
return;
}
validBoundingSphere = findValidBoundingSphere(node);
}
Waypoint::Waypoint(const NavigationState& ns) {
const SceneGraphNode* anchorNode = sceneGraphNode(ns.anchor);
if (!anchorNode) {
LERROR(fmt::format("Could not find node '{}' to target", ns.anchor));
return;
}
nodeIdentifier = ns.anchor;
validBoundingSphere = findValidBoundingSphere(anchorNode);
pose = ns.cameraPose();
}
glm::dvec3 Waypoint::position() const {
return pose.position;
}
glm::dquat Waypoint::rotation() const {
return pose.rotation;
}
SceneGraphNode* Waypoint::node() const {
return sceneGraphNode(nodeIdentifier);
}
double Waypoint::findValidBoundingSphere(const SceneGraphNode* node) {
double bs = static_cast<double>(node->boundingSphere());
const double minValidBoundingSphere =
global::navigationHandler->pathNavigator().minValidBoundingSphere();
if (bs < minValidBoundingSphere) {
// If the bs of the target is too small, try to find a good value in a child node.
// Only check the closest children, to avoid deep traversal in the scene graph.
// Also, the possibility to find a bounding sphere represents the visual size of
// the target well is higher for these nodes.
for (SceneGraphNode* child : node->children()) {
bs = static_cast<double>(child->boundingSphere());
if (bs > minValidBoundingSphere) {
LWARNING(fmt::format(
"The scene graph node '{}' has no, or a very small, bounding sphere. "
"Using bounding sphere of child node '{}' in computations.",
node->identifier(),
child->identifier()
));
return bs;
}
}
LWARNING(fmt::format(
"The scene graph node '{}' has no, or a very small, bounding sphere. Using "
"minimal value. This might lead to unexpected results.",
node->identifier())
);
bs = minValidBoundingSphere;
}
return bs;
}
} // namespace openspace::interaction

View File

@@ -24,14 +24,14 @@
#include <openspace/network/parallelpeer.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
#include <openspace/util/timemanager.h>
#include <ghoul/logging/logmanager.h>

View File

@@ -26,6 +26,7 @@
#include <openspace/rendering/abufferrenderer.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/performance/performancemanager.h>
@@ -36,7 +37,6 @@
#include <openspace/rendering/volumeraycaster.h>
#include <openspace/rendering/deferredcaster.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/updatestructures.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/filesystem.h>

View File

@@ -24,6 +24,7 @@
#include <openspace/rendering/framebufferrenderer.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/rendering/deferredcaster.h>
@@ -33,7 +34,6 @@
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/volumeraycaster.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/filesystem.h>

View File

@@ -29,8 +29,8 @@
#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/rendering/abufferrenderer.h>
#include <openspace/rendering/dashboard.h>

View File

@@ -24,6 +24,7 @@
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/camera/camera.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
@@ -32,7 +33,6 @@
#include <openspace/rendering/renderengine.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/factorymanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/profiling.h>

View File

@@ -24,6 +24,7 @@
#include <openspace/scene/profile.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/properties/property.h>
#include <openspace/properties/propertyowner.h>
@@ -445,7 +446,7 @@ Profile::ParsingError::ParsingError(Severity severity_, std::string msg)
void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& rootOwner,
std::string currentTime,
interaction::NavigationHandler::NavigationState navState)
interaction::NavigationState navState)
{
_version = Profile::CurrentVersion;

View File

@@ -24,7 +24,8 @@
#include <openspace/engine/configuration.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
@@ -88,8 +89,7 @@ int saveSettingsToProfile(lua_State* L) {
const properties::PropertyOwner& root = *global::rootPropertyOwner;
std::string currentTime = std::string(global::timeManager->time().ISO8601());
interaction::NavigationHandler::NavigationState navState =
global::navigationHandler->navigationState();
interaction::NavigationState navState = global::navigationHandler->navigationState();
global::profile->saveCurrentSettingsToProfile(root, currentTime, navState);
global::configuration->profile = saveFilePath;

View File

@@ -24,6 +24,7 @@
#include <openspace/scene/scene.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/globalscallbacks.h>
#include <openspace/engine/windowdelegate.h>
@@ -34,7 +35,6 @@
#include <openspace/scene/scenelicensewriter.h>
#include <openspace/scene/sceneinitializer.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/camera.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/logging/logmanager.h>

View File

@@ -24,7 +24,7 @@
#include "catch2/catch.hpp"
#include <openspace/interaction/navigationhandler.h>
#include <openspace/navigation/navigationstate.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
@@ -520,7 +520,7 @@ TEST_CASE("Save settings to profile", "[profile]") {
p1 = 2.f;
p2 = "test-string";
interaction::NavigationHandler::NavigationState state;
interaction::NavigationState state;
state.anchor = "anchor";
state.aim = "aim";
state.referenceFrame = "refFrame";