More cleanup/restructuring

This commit is contained in:
Emma Broman
2021-06-08 10:25:18 +02:00
parent 3881f1f2fc
commit 9e566efcce
7 changed files with 145 additions and 278 deletions

View File

@@ -25,7 +25,6 @@
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/atnodenavigator.h
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationhandler.h
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.h
${CMAKE_CURRENT_SOURCE_DIR}/helperfunctions.h
@@ -40,7 +39,6 @@ set(HEADER_FILES
source_group("Header Files" FILES ${HEADER_FILES})
set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/atnodenavigator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationhandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.cpp
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule_lua.inl

View File

@@ -1,132 +0,0 @@
/*****************************************************************************************
* *
* 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/autonavigation/atnodenavigator.h>
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/waypoint.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/rotate_vector.hpp>
namespace {
constexpr const char* _loggerCat = "AtNodeNavigator";
constexpr const openspace::properties::Property::PropertyInfo OrbitSpeedFactorInfo = {
"OrbitSpeedFactor",
"Orbit Speed Factor",
"Controls the speed of the orbiting around an anchor."
};
} // namespace
namespace openspace::autonavigation {
AtNodeNavigator::AtNodeNavigator()
: properties::PropertyOwner({ "AtNodeNavigator" })
, _orbitSpeedFactor(OrbitSpeedFactorInfo, 0.5, 0.0, 20.0)
{
addProperty(_orbitSpeedFactor);
_behavior = Behavior::None;
}
AtNodeNavigator::~AtNodeNavigator() {} // NOLINT
AtNodeNavigator::Behavior AtNodeNavigator::behavior() const {
return _behavior;
}
void AtNodeNavigator::setBehavior(Behavior behavior) {
_behavior = behavior;
}
void AtNodeNavigator::updateCamera(double deltaTime) {
switch (_behavior)
{
case Behavior::Orbit:
orbitNode(deltaTime);
break;
case Behavior::None:
// Do nothing
break;
default:
LERROR("Behavior type not implemented.");
break;
}
}
Camera* AtNodeNavigator::camera() const {
return global::navigationHandler->camera();
}
const SceneGraphNode* AtNodeNavigator::anchor() const {
return global::navigationHandler->anchorNode();
}
// Move along the right vector for the camera, while looking at the center of the node
void AtNodeNavigator::orbitNode(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 up = camera()->lookUpVectorWorldSpace();
const double speedFactor = 0.1 * _orbitSpeedFactor;
glm::dvec3 nodeCenter = anchor()->worldPosition();
double orbitRadius = glm::distance(prevPosition, nodeCenter);
double distanceToSurface = orbitRadius - anchor()->boundingSphere();
double orbitSpeed = distanceToSurface * speedFactor;
// compute a new position along the orbit
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
const glm::dvec3 nodeToNewPos = newPosition - nodeCenter;
const double nodeToPrevPosDistance = glm::distance(prevPosition, nodeCenter);
const double distanceDiff = glm::length(nodeToNewPos) - nodeToPrevPosDistance;
newPosition -= distanceDiff * glm::normalize(nodeToNewPos);
// rotate with the orbit, but keep the 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);
}
} // namespace openspace::autonavigation

View File

@@ -1,66 +0,0 @@
/*****************************************************************************************
* *
* 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_MODULE___ATNODENAVIGATOR___H__
#define __OPENSPACE_MODULE___ATNODENAVIGATOR___H__
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/scalar/doubleproperty.h>
namespace openspace {
class Camera;
class SceneGraphNode;
} // namespace openspace
namespace openspace::autonavigation {
class AtNodeNavigator : public properties::PropertyOwner {
public:
enum Behavior {
None = 0,
Orbit,
};
AtNodeNavigator();
~AtNodeNavigator();
Behavior behavior() const;
void setBehavior(Behavior behavior);
void updateCamera(double deltaTime);
private:
Camera* camera() const;
const SceneGraphNode* anchor() const;
//Behaviors
void orbitNode(double deltaTime);
Behavior _behavior;
properties::DoubleProperty _orbitSpeedFactor;
};
} // namespace openspace::autonavigation
#endif // __OPENSPACE_MODULE___ATNODENAVIGATOR___H__

View File

@@ -27,7 +27,6 @@
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/pathinstruction.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
@@ -45,27 +44,28 @@ namespace {
constexpr openspace::properties::Property::PropertyInfo DefaultCurveOptionInfo = {
"DefaultCurveOption",
"Default Curve Option",
"The defualt curve type chosen when generating a path, if none is specified."
"The defualt curve type chosen when generating a path, if none is specified"
};
constexpr openspace::properties::Property::PropertyInfo IncludeRollInfo = {
"IncludeRoll",
"Include Roll",
"If disabled, roll is removed from the interpolation of camera orientation."
"If disabled, roll is removed from the interpolation of camera orientation"
};
constexpr openspace::properties::Property::PropertyInfo DefaultStopBehaviorInfo = {
"DefaultStopBehavior",
"Default Stop Behavior",
"The default camera behavior that is applied when the camera reaches and stops "
"at a target."
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 = {
constexpr openspace::properties::Property::PropertyInfo
ApplyStopBehaviorWhenIdleInfo =
{
"ApplyStopBehaviorWhenIdle",
"Apply Stop Behavior When Idle",
"If enabled, the camera is controlled using the default stop behavior even when"
"no path is playing."
"If enabled, the camera is controlled using the set stop behavior when"
"no path is playing"
};
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
@@ -74,6 +74,11 @@ namespace {
"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."
};
} // namespace
namespace openspace::autonavigation {
@@ -86,14 +91,13 @@ AutoNavigationHandler::AutoNavigationHandler()
)
, _includeRoll(IncludeRollInfo, false)
, _stopBehavior(
DefaultStopBehaviorInfo,
StopBehaviorInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _applyStopBehaviorWhenIdle(ApplyStopBehaviorWhenIdleInfo, false)
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
, _orbitSpeedFactor(OrbitSpeedFactorInfo, 0.5, 0.0, 20.0)
{
addPropertySubOwner(_atNodeNavigator);
_defaultCurveOption.addOptions({
{ CurveType::AvoidCollision, "AvoidCollision" },
{ CurveType::Linear, "Linear" },
@@ -108,16 +112,13 @@ AutoNavigationHandler::AutoNavigationHandler()
// Must be listed in the same order as in enum definition
_stopBehavior.addOptions({
{ AtNodeNavigator::Behavior::None, "None" },
{ AtNodeNavigator::Behavior::Orbit, "Orbit" }
});
_stopBehavior = AtNodeNavigator::Behavior::None;
_stopBehavior.onChange([this]() {
_atNodeNavigator.setBehavior(
AtNodeNavigator::Behavior(_stopBehavior.value())
);
{ StopBehavior::None, "None" },
{ StopBehavior::Orbit, "Orbit" }
});
_stopBehavior = StopBehavior::None;
addProperty(_stopBehavior);
addProperty(_orbitSpeedFactor);
}
AutoNavigationHandler::~AutoNavigationHandler() {} // NOLINT
@@ -150,10 +151,9 @@ void AutoNavigationHandler::updateCamera(double deltaTime) {
ghoul_assert(camera() != nullptr, "Camera must not be nullptr");
if (!_isPlaying) {
// For testing, apply at node behavior when idle
// @TODO: Determine how this should work instead
// TODO: Determine how this should work
if (_applyStopBehaviorWhenIdle) {
_atNodeNavigator.updateCamera(deltaTime);
applyStopBehavior(deltaTime);
}
return;
}
@@ -199,7 +199,7 @@ void AutoNavigationHandler::createPath(PathInstruction& instruction) {
// TODO: Improve how curve types are handled
const int curveType = _defaultCurveOption;
std::vector<Waypoint> waypoints = instruction.waypoints;
std::vector<Waypoint> waypoints = instruction.waypoints();
Waypoint waypointToAdd;
if (waypoints.empty()) {
@@ -212,10 +212,10 @@ void AutoNavigationHandler::createPath(PathInstruction& instruction) {
}
_currentPath = std::make_unique<Path>(
instruction.startPoint,
instruction.startPoint(),
waypointToAdd,
CurveType(curveType),
instruction.duration
instruction.duration()
);
LINFO("Successfully generated camera path");
@@ -367,4 +367,59 @@ void AutoNavigationHandler::removeRollRotation(CameraPose& pose, double deltaTim
pose.rotation = rollFreeRotation;
}
void AutoNavigationHandler::applyStopBehavior(double deltaTime) {
switch (_stopBehavior) {
case StopBehavior::None:
// Do nothing
break;
case StopBehavior::Orbit:
orbitAnchorNode(deltaTime);
break;
default:
throw ghoul::MissingCaseException();
}
}
void AutoNavigationHandler::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 up = camera()->lookUpVectorWorldSpace();
const double speedFactor = 0.1 * _orbitSpeedFactor;
glm::dvec3 nodeCenter = anchor()->worldPosition();
double orbitRadius = glm::distance(prevPosition, nodeCenter);
double distanceToSurface = orbitRadius - anchor()->boundingSphere();
double orbitSpeed = distanceToSurface * speedFactor;
// compute a new position along the orbit
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
const glm::dvec3 nodeToNewPos = newPosition - nodeCenter;
const double nodeToPrevPosDistance = glm::distance(prevPosition, nodeCenter);
const double distanceDiff = glm::length(nodeToNewPos) - nodeToPrevPosDistance;
newPosition -= distanceDiff * glm::normalize(nodeToNewPos);
// rotate with 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);
}
} // namespace openspace::autonavigation

View File

@@ -25,7 +25,6 @@
#ifndef __OPENSPACE_MODULE___AUTONAVIGATIONHANDLER___H__
#define __OPENSPACE_MODULE___AUTONAVIGATIONHANDLER___H__
#include <modules/autonavigation/atnodenavigator.h>
#include <modules/autonavigation/path.h>
#include <openspace/properties/list/stringlistproperty.h>
#include <openspace/properties/optionproperty.h>
@@ -43,6 +42,11 @@ struct PathInstruction;
class AutoNavigationHandler : public properties::PropertyOwner {
public:
enum StopBehavior {
None = 0,
Orbit
};
AutoNavigationHandler();
~AutoNavigationHandler();
@@ -71,15 +75,17 @@ public:
private:
void removeRollRotation(CameraPose& pose, double deltaTime);
void applyStopBehavior(double deltaTime);
void orbitAnchorNode(double deltaTime);
std::unique_ptr<Path> _currentPath = nullptr;
AtNodeNavigator _atNodeNavigator;
bool _isPlaying = false;
properties::OptionProperty _defaultCurveOption;
properties::BoolProperty _includeRoll;
properties::FloatProperty _speedScale;
properties::FloatProperty _orbitSpeedFactor;
// for testing pause behaviors.
// TODO: remove later, if it causes problems with regular navigation

View File

@@ -39,7 +39,6 @@ namespace {
constexpr const char* _loggerCat = "PathInstruction";
constexpr const float Epsilon = 1e-5f;
struct [[codegen::Dictionary(Instruction)]] Parameters {
enum class Type {
Node,
@@ -85,31 +84,27 @@ documentation::Documentation PathInstruction::Documentation() {
PathInstruction::PathInstruction(const ghoul::Dictionary& dictionary) {
const Parameters p = codegen::bake<Parameters>(dictionary);
duration = p.duration;
_duration = p.duration;
bool hasStart = p.startState.has_value();
startPoint = hasStart ? Waypoint(p.startState.value()) : waypointFromCamera();
_startPoint = hasStart ? Waypoint(p.startState.value()) : waypointFromCamera();
switch (p.type) {
case Parameters::Type::NavigationState: {
type = Type::NavigationState;
if (!p.navigationState.has_value()) {
throw ghoul::RuntimeError("A navigation state is required");
}
navigationState = NavigationState(p.navigationState.value());
waypoints = { Waypoint(navigationState) };
NavigationState navigationState = NavigationState(p.navigationState.value());
_waypoints = { Waypoint(navigationState) };
break;
}
case Parameters::Type::Node: {
type = Type::Node;
if (!p.target.has_value()) {
throw ghoul::RuntimeError("A target node is required");
}
nodeIdentifier = p.target.value();
std::string nodeIdentifier = p.target.value();
const SceneGraphNode* targetNode = sceneGraphNode(nodeIdentifier);
if (!targetNode) {
@@ -118,10 +113,14 @@ PathInstruction::PathInstruction(const ghoul::Dictionary& dictionary) {
));
}
position = p.position;
height = p.height;
useTargetUpDirection = p.useTargetUpDirection.value_or(false);
waypoints = { computeDefaultWaypoint() };
NodeInfo info {
nodeIdentifier,
p.position,
p.height,
p.useTargetUpDirection.value_or(false)
};
_waypoints = { computeDefaultWaypoint(info) };
break;
}
default: {
@@ -132,6 +131,18 @@ PathInstruction::PathInstruction(const ghoul::Dictionary& dictionary) {
}
}
Waypoint PathInstruction::startPoint() const {
return _startPoint;
}
std::vector<Waypoint> PathInstruction::waypoints() const {
return _waypoints;
}
std::optional<double> PathInstruction::duration() const {
return _duration;
}
Waypoint PathInstruction::waypointFromCamera() const {
Camera* camera = global::navigationHandler->camera();
const glm::dvec3 pos = camera->positionVec3();
@@ -142,19 +153,19 @@ Waypoint PathInstruction::waypointFromCamera() const {
// OBS! The desired default waypoint may vary between curve types.
// TODO: let the curves update the default position if no exact position is required
Waypoint PathInstruction::computeDefaultWaypoint() const {
const SceneGraphNode* targetNode = sceneGraphNode(nodeIdentifier);
Waypoint PathInstruction::computeDefaultWaypoint(const NodeInfo& info) const {
const SceneGraphNode* targetNode = sceneGraphNode(info.identifier);
if (!targetNode) {
LERROR(fmt::format("Could not find target node '{}'", nodeIdentifier));
LERROR(fmt::format("Could not find target node '{}'", info.identifier));
return Waypoint();
}
glm::dvec3 targetPos;
if (position.has_value()) {
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() * position.value();
targetNode->worldRotationMatrix() * info.position.value();
}
else {
const glm::dvec3 nodePos = targetNode->worldPosition();
@@ -175,7 +186,7 @@ Waypoint PathInstruction::computeDefaultWaypoint() const {
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 prevPos = _startPoint.position();
const glm::dvec3 targetToPrev = prevPos - nodePos;
const glm::dvec3 targetToSun = sunPos - nodePos;
@@ -189,25 +200,23 @@ Waypoint PathInstruction::computeDefaultWaypoint() const {
const double radius = Waypoint::findValidBoundingSphere(targetNode);
const double defaultHeight = 2.0 * radius;
const double targetHeight = height.value_or(defaultHeight);
const double height = info.height.value_or(defaultHeight);
targetPos = nodePos + stepDirection * (radius + targetHeight);
targetPos = nodePos + stepDirection * (radius + height);
}
// Up direction
glm::dvec3 up = global::navigationHandler->camera()->lookUpVectorWorldSpace();
if (useTargetUpDirection) {
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);
}
// Rotation
const glm::dvec3 lookAtPos = targetNode->worldPosition();
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
return Waypoint(targetPos, targetRot, nodeIdentifier);
return Waypoint(targetPos, targetRot, info.identifier);
}
// Test if the node lies within a given proximity radius of any relevant node in the scene

View File

@@ -31,36 +31,33 @@
namespace openspace::autonavigation {
struct PathInstruction {
class PathInstruction {
public:
using NavigationState = interaction::NavigationHandler::NavigationState;
enum class Type {
Node,
NavigationState
};
PathInstruction(const ghoul::Dictionary& dictionary);
Waypoint startPoint() const;
std::vector<Waypoint> waypoints() const;
std::optional<double> duration() const;
static documentation::Documentation Documentation();
private:
struct NodeInfo {
std::string identifier;
std::optional<glm::dvec3> position;
std::optional<double> height;
bool useTargetUpDirection;
};
Waypoint waypointFromCamera() const;
Waypoint computeDefaultWaypoint() const;
Waypoint computeDefaultWaypoint(const NodeInfo& info) const;
SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node) const;
Type type;
// Node details
std::string nodeIdentifier;
std::optional<glm::dvec3> position;
std::optional<double> height;
bool useTargetUpDirection;
// Navigation state details
NavigationState navigationState;
std::optional<double> duration;
Waypoint startPoint;
std::vector<Waypoint> waypoints;
Waypoint _startPoint;
std::vector<Waypoint> _waypoints;
std::optional<double> _duration;
};
} // namespace openspace::autonavigation