mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 19:19:39 -06:00
Remove support for multiple path segments
A "path" is now only one "segment"
This commit is contained in:
@@ -26,12 +26,11 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/atnodenavigator.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationhandler.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/helperfunctions.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/instruction.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathspecification.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathsegment.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/path.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathcurve.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rotationinterpolator.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/speedfunction.h
|
||||
@@ -43,13 +42,12 @@ 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
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationhandler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/helperfunctions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/instruction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathspecification.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathsegment.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/path.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathcurve.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rotationinterpolator.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/speedfunction.cpp
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <modules/autonavigation/helperfunctions.h>
|
||||
#include <modules/autonavigation/instruction.h>
|
||||
#include <modules/autonavigation/pathspecification.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
@@ -125,8 +124,7 @@ AutoNavigationHandler::AutoNavigationHandler()
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
, _includeRoll(IncludeRollInfo, false)
|
||||
, _stopAtTargetsPerDefault(StopAtTargetsPerDefaultInfo, false)
|
||||
, _defaultStopBehavior(
|
||||
, _stopBehavior(
|
||||
DefaultStopBehaviorInfo,
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
@@ -147,20 +145,19 @@ AutoNavigationHandler::AutoNavigationHandler()
|
||||
addProperty(_defaultCurveOption);
|
||||
|
||||
addProperty(_includeRoll);
|
||||
addProperty(_stopAtTargetsPerDefault);
|
||||
|
||||
// Must be listed in the same order as in enum definition
|
||||
_defaultStopBehavior.addOptions({
|
||||
_stopBehavior.addOptions({
|
||||
{ AtNodeNavigator::Behavior::None, "None" },
|
||||
{ AtNodeNavigator::Behavior::Orbit, "Orbit" }
|
||||
});
|
||||
_defaultStopBehavior = AtNodeNavigator::Behavior::None;
|
||||
_defaultStopBehavior.onChange([this]() {
|
||||
_stopBehavior = AtNodeNavigator::Behavior::None;
|
||||
_stopBehavior.onChange([this]() {
|
||||
_atNodeNavigator.setBehavior(
|
||||
AtNodeNavigator::Behavior(_defaultStopBehavior.value())
|
||||
AtNodeNavigator::Behavior(_stopBehavior.value())
|
||||
);
|
||||
});
|
||||
addProperty(_defaultStopBehavior);
|
||||
addProperty(_stopBehavior);
|
||||
|
||||
addProperty(_applyStopBehaviorWhenIdle);
|
||||
|
||||
@@ -200,12 +197,8 @@ double AutoNavigationHandler::speedScale() const {
|
||||
return _speedScale;
|
||||
}
|
||||
|
||||
const PathSegment& AutoNavigationHandler::currentSegment() const {
|
||||
return _currentPath.segments[_currentSegmentIndex];
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::noCurrentPath() const {
|
||||
return _currentPath.segments.empty();
|
||||
return _currentPath == nullptr;
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::hasFinished() const {
|
||||
@@ -213,14 +206,17 @@ bool AutoNavigationHandler::hasFinished() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
const int lastIndex = static_cast<int>(_currentPath.segments.size()) - 1;
|
||||
return _currentSegmentIndex > lastIndex;
|
||||
return _currentPath->hasReachedEnd();
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::updateCamera(double deltaTime) {
|
||||
ghoul_assert(camera() != nullptr, "Camera must not be nullptr");
|
||||
|
||||
if (!_isPlaying || _currentPath.segments.empty()) {
|
||||
if (noCurrentPath()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isPlaying) {
|
||||
// For testing, apply at node behavior when idle
|
||||
// @TODO: Determine how this should work instead
|
||||
if (_applyStopBehaviorWhenIdle) {
|
||||
@@ -235,10 +231,8 @@ void AutoNavigationHandler::updateCamera(double deltaTime) {
|
||||
LINFO("Cannot start simulation time during camera motion");
|
||||
}
|
||||
|
||||
PathSegment& currentSegment = _currentPath.segments[_currentSegmentIndex];
|
||||
|
||||
CameraPose newPose = currentSegment.traversePath(deltaTime);
|
||||
const std::string newAnchor = currentSegment.currentAnchor();
|
||||
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.
|
||||
@@ -254,65 +248,70 @@ void AutoNavigationHandler::updateCamera(double deltaTime) {
|
||||
camera()->setPositionVec3(newPose.position);
|
||||
camera()->setRotation(newPose.rotation);
|
||||
|
||||
const int index = _currentSegmentIndex;
|
||||
|
||||
if (currentSegment.hasReachedEnd()) {
|
||||
_currentSegmentIndex++;
|
||||
|
||||
if (hasFinished()) {
|
||||
LINFO("Reached end of path.");
|
||||
_isPlaying = false;
|
||||
return;
|
||||
}
|
||||
// TODO: make this work again
|
||||
if (_currentPath->hasReachedEnd()) {
|
||||
LINFO("Reached end of path");
|
||||
_isPlaying = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::createPath(PathSpecification& spec) {
|
||||
void AutoNavigationHandler::createPath(Instruction& instruction) {
|
||||
clearPath();
|
||||
|
||||
// TODO: do this in some initialize function instead
|
||||
_relevantNodes = findRelevantNodes();
|
||||
|
||||
const std::vector<Instruction>& instructions = spec.instructions;
|
||||
const int nInstructions = static_cast<int>(instructions.size());
|
||||
// TODO: Improve how curve types are handled
|
||||
const int curveType = _defaultCurveOption;
|
||||
|
||||
for (int i = 0; i < nInstructions; i++) {
|
||||
const Instruction& instruction = instructions[i];
|
||||
addSegment(instruction, i);
|
||||
std::vector<Waypoint> waypoints = instruction.waypoints();
|
||||
Waypoint waypointToAdd;
|
||||
|
||||
if (waypoints.empty()) {
|
||||
if (instruction.type == Instruction::Type::Node) {
|
||||
// TODO: allow curves to compute default waypoint instead
|
||||
waypointToAdd = computeDefaultWaypoint(instruction);
|
||||
}
|
||||
else {
|
||||
LWARNING("No path was created from instruction. Failed creating waypoints");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: allow for an instruction to represent a list of waypoints
|
||||
waypointToAdd = waypoints[0];
|
||||
}
|
||||
|
||||
ghoul_assert(
|
||||
_currentPath.stops.size() == (_currentPath.segments.size() - 1),
|
||||
"Must have exactly one stop entry between every segment."
|
||||
bool hasStartState = instruction.startState.has_value();
|
||||
Waypoint startState = hasStartState ? Waypoint(instruction.startState.value())
|
||||
: waypointFromCamera();
|
||||
|
||||
_currentPath = std::make_unique<Path>(
|
||||
startState,
|
||||
waypointToAdd,
|
||||
CurveType(curveType),
|
||||
instruction.duration
|
||||
);
|
||||
|
||||
// Check if we have a specified start navigation state. If so, update first segment
|
||||
if (spec.startState.has_value() && _currentPath.segments.size() > 0) {
|
||||
Waypoint startState{ spec.startState.value() };
|
||||
_currentPath.segments[0].setStartPoint(startState);
|
||||
}
|
||||
|
||||
LINFO(fmt::format(
|
||||
"Succefully generated camera path with {} segments.", _currentPath.segments.size()
|
||||
));
|
||||
LINFO("Successfully generated camera path");
|
||||
startPath();
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::clearPath() {
|
||||
LINFO("Clearing path...");
|
||||
_currentPath.segments.clear();
|
||||
_currentSegmentIndex = 0;
|
||||
_currentPath = nullptr;
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::startPath() {
|
||||
if (noCurrentPath()) {
|
||||
LERROR("Cannot start an empty path.");
|
||||
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.");
|
||||
LERROR("Simulation time must be paused to run a camera path");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -320,52 +319,48 @@ void AutoNavigationHandler::startPath() {
|
||||
_isPlaying = true;
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::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...");
|
||||
|
||||
// recompute start camera state for the upcoming path segment,
|
||||
_currentPath.segments[_currentSegmentIndex].setStartPoint(wayPointFromCamera());
|
||||
}
|
||||
//void AutoNavigationHandler::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...");
|
||||
//
|
||||
// // recompute start camera state for the upcoming path segment,
|
||||
// _currentPath.segments[_currentSegmentIndex].setStartPoint(wayPointFromCamera());
|
||||
//}
|
||||
|
||||
void AutoNavigationHandler::abortPath() {
|
||||
if (!_isPlaying) {
|
||||
LWARNING("No camera path is playing.");
|
||||
LWARNING("No camera path is playing");
|
||||
return;
|
||||
}
|
||||
_isPlaying = false;
|
||||
LINFO("Aborted camera path.");
|
||||
LINFO("Aborted camera path");
|
||||
}
|
||||
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::curvePositions(int nPerSegment) {
|
||||
std::vector<glm::dvec3> positions;
|
||||
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return positions;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<glm::dvec3> positions;
|
||||
const double du = 1.0 / nPerSegment;
|
||||
|
||||
for (const PathSegment& p : _currentPath.segments) {
|
||||
const double length = p.pathLength();
|
||||
for (double u = 0.0; u < 1.0; u += du) {
|
||||
glm::dvec3 position = p.interpolatedPose(u * length).position;
|
||||
positions.push_back(position);
|
||||
}
|
||||
positions.push_back(p.endPoint().position());
|
||||
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;
|
||||
}
|
||||
@@ -373,23 +368,20 @@ std::vector<glm::dvec3> AutoNavigationHandler::curvePositions(int nPerSegment) {
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging
|
||||
std::vector<glm::dquat> AutoNavigationHandler::curveOrientations(int nPerSegment) {
|
||||
std::vector<glm::dquat> orientations;
|
||||
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return orientations;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<glm::dquat> orientations;
|
||||
const double du = 1.0 / nPerSegment;
|
||||
|
||||
for (const PathSegment& p : _currentPath.segments) {
|
||||
const double length = p.pathLength();
|
||||
for (double u = 0.0; u <= 1.0; u += du) {
|
||||
const glm::dquat orientation = p.interpolatedPose(u * length).rotation;
|
||||
orientations.push_back(orientation);
|
||||
}
|
||||
orientations.push_back(p.endPoint().rotation());
|
||||
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;
|
||||
}
|
||||
@@ -398,63 +390,52 @@ std::vector<glm::dquat> AutoNavigationHandler::curveOrientations(int nPerSegment
|
||||
// TODO: remove when not needed or combined into pose version
|
||||
// Created for debugging
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::curveViewDirections(int nPerSegment) {
|
||||
std::vector<glm::dvec3> viewDirections;
|
||||
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return viewDirections;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<glm::dvec3> viewDirections;
|
||||
const double du = 1.0 / nPerSegment;
|
||||
|
||||
for (const PathSegment& p : _currentPath.segments) {
|
||||
for (double u = 0.0; u < 1.0; u += du) {
|
||||
const glm::dquat orientation = p.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 = p.interpolatedPose(1.0).rotation;
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging
|
||||
std::vector<glm::dvec3> AutoNavigationHandler::controlPoints() {
|
||||
std::vector<glm::dvec3> points;
|
||||
|
||||
if (noCurrentPath()) {
|
||||
LERROR("There is no current path to sample points from.");
|
||||
return points;
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const PathSegment&p : _currentPath.segments) {
|
||||
const std::vector<glm::dvec3> curvePoints = p.controlPoints();
|
||||
points.insert(points.end(), curvePoints.begin(), curvePoints.end());
|
||||
}
|
||||
std::vector<glm::dvec3> points;
|
||||
const std::vector<glm::dvec3> curvePoints = _currentPath->controlPoints();
|
||||
points.insert(points.end(), curvePoints.begin(), curvePoints.end());
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
Waypoint AutoNavigationHandler::wayPointFromCamera() {
|
||||
Waypoint AutoNavigationHandler::waypointFromCamera() {
|
||||
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 AutoNavigationHandler::lastWayPoint() {
|
||||
return noCurrentPath() ? wayPointFromCamera() : _currentPath.segments.back().endPoint();
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::removeRollRotation(CameraPose& pose, double deltaTime) {
|
||||
const glm::dvec3 anchorPos = anchor()->worldPosition();
|
||||
const glm::dvec3 cameraDir = glm::normalize(
|
||||
@@ -471,39 +452,6 @@ void AutoNavigationHandler::removeRollRotation(CameraPose& pose, double deltaTim
|
||||
pose.rotation = rollFreeRotation;
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::addSegment(const Instruction& ins, int index) {
|
||||
// TODO: Improve how curve types are handled
|
||||
const int curveType = _defaultCurveOption;
|
||||
|
||||
std::vector<Waypoint> waypoints = ins.waypoints();
|
||||
Waypoint waypointToAdd;
|
||||
|
||||
if (waypoints.empty()) {
|
||||
if (ins.type == Instruction::Type::Node) {
|
||||
// TODO: allow curves to compute default waypoint instead
|
||||
waypointToAdd = computeDefaultWaypoint(ins);
|
||||
}
|
||||
else {
|
||||
LWARNING(fmt::format(
|
||||
"No path segment was created from instruction {}. "
|
||||
"No waypoints could be created.", index
|
||||
));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: allow for an instruction to represent a list of waypoints
|
||||
waypointToAdd = waypoints[0];
|
||||
}
|
||||
|
||||
_currentPath.segments.push_back(PathSegment(
|
||||
lastWayPoint(),
|
||||
waypointToAdd,
|
||||
CurveType(curveType),
|
||||
ins.duration
|
||||
));
|
||||
}
|
||||
|
||||
// Test if the node lies within a given proximity radius of any relevant node in the scene
|
||||
SceneGraphNode* AutoNavigationHandler::findNodeNearTarget(const SceneGraphNode* node) {
|
||||
glm::dvec3 nodePos = node->worldPosition();
|
||||
@@ -547,7 +495,7 @@ Waypoint AutoNavigationHandler::computeDefaultWaypoint(const Instruction& ins) {
|
||||
const glm::dvec3 nodePos = targetNode->worldPosition();
|
||||
const glm::dvec3 sunPos = glm::dvec3(0.0, 0.0, 0.0);
|
||||
const SceneGraphNode* closeNode = findNodeNearTarget(targetNode);
|
||||
const glm::dvec3 prevPos = lastWayPoint().position();
|
||||
const glm::dvec3 prevPos = waypointFromCamera().position();
|
||||
|
||||
// Position
|
||||
glm::dvec3 stepDirection;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define __OPENSPACE_MODULE___AUTONAVIGATIONHANDLER___H__
|
||||
|
||||
#include <modules/autonavigation/atnodenavigator.h>
|
||||
#include <modules/autonavigation/pathsegment.h>
|
||||
#include <modules/autonavigation/path.h>
|
||||
#include <openspace/properties/list/stringlistproperty.h>
|
||||
#include <openspace/properties/optionproperty.h>
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
@@ -41,7 +41,6 @@ namespace openspace::autonavigation {
|
||||
struct Waypoint;
|
||||
struct Instruction;
|
||||
struct TargetNodeInstruction;
|
||||
class PathSpecification;
|
||||
|
||||
class AutoNavigationHandler : public properties::PropertyOwner {
|
||||
public:
|
||||
@@ -55,17 +54,18 @@ public:
|
||||
int integrationResolutionPerFrame() const;
|
||||
double speedScale() const;
|
||||
|
||||
const PathSegment& currentSegment() const;
|
||||
bool noCurrentPath() const;
|
||||
bool hasFinished() const;
|
||||
|
||||
void updateCamera(double deltaTime);
|
||||
void createPath(PathSpecification& spec);
|
||||
void createPath(Instruction& spec);
|
||||
void clearPath();
|
||||
void startPath();
|
||||
void continuePath();
|
||||
void abortPath();
|
||||
|
||||
// TODO: allow option to pause during a path and then change this to continue playing
|
||||
//void continuePath();
|
||||
|
||||
// TODO: remove functions for debugging
|
||||
std::vector<glm::dvec3> curvePositions(int nPerSegment);
|
||||
std::vector<glm::dquat> curveOrientations(int nPerSegment);
|
||||
@@ -74,38 +74,29 @@ public:
|
||||
|
||||
private:
|
||||
Waypoint wayPointFromCamera();
|
||||
Waypoint lastWayPoint();
|
||||
void removeRollRotation(CameraPose& pose, double deltaTime);
|
||||
|
||||
void addSegment(const Instruction& ins, int index);
|
||||
void addSegment(const Instruction& ins);
|
||||
|
||||
SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node);
|
||||
Waypoint computeDefaultWaypoint(const Instruction& ins);
|
||||
|
||||
std::vector<SceneGraphNode*> findRelevantNodes();
|
||||
|
||||
struct Path {
|
||||
std::vector<PathSegment> segments;
|
||||
};
|
||||
|
||||
Path _currentPath;
|
||||
std::unique_ptr<Path> _currentPath = nullptr;
|
||||
|
||||
AtNodeNavigator _atNodeNavigator; // responsible for navigation during stops
|
||||
double _progressedTimeInStop = 0.0;
|
||||
|
||||
bool _isPlaying = false;
|
||||
unsigned int _currentSegmentIndex = 0;
|
||||
|
||||
std::vector<SceneGraphNode*> _relevantNodes;
|
||||
|
||||
properties::OptionProperty _defaultCurveOption;
|
||||
properties::BoolProperty _includeRoll;
|
||||
properties::BoolProperty _stopAtTargetsPerDefault;
|
||||
properties::OptionProperty _defaultStopBehavior;
|
||||
|
||||
// for testing pause behaviors.
|
||||
// TODO: remove later, if it causes problems with regular navigation
|
||||
properties::BoolProperty _applyStopBehaviorWhenIdle;
|
||||
properties::OptionProperty _stopBehavior;
|
||||
|
||||
properties::StringListProperty _relevantNodeTags;
|
||||
properties::FloatProperty _defaultPositionOffsetAngle;
|
||||
|
||||
@@ -59,8 +59,7 @@ double AutoNavigationModule::minValidBoundingSphere() const {
|
||||
|
||||
std::vector<documentation::Documentation> AutoNavigationModule::documentations() const {
|
||||
return {
|
||||
autonavigation::Instruction::Documentation(),
|
||||
autonavigation::PathSpecification::Documentation()
|
||||
autonavigation::Instruction::Documentation()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -78,13 +77,13 @@ scripting::LuaLibrary AutoNavigationModule::luaLibrary() const {
|
||||
"",
|
||||
"Returns true if a camera path is currently running, and false otherwise."
|
||||
},
|
||||
{
|
||||
"continuePath",
|
||||
&autonavigation::luascriptfunctions::continuePath,
|
||||
{},
|
||||
"",
|
||||
"Continue playing a paused camera path."
|
||||
},
|
||||
//{
|
||||
// "continuePath",
|
||||
// &autonavigation::luascriptfunctions::continuePath,
|
||||
// {},
|
||||
// "",
|
||||
// "Continue playing a paused camera path."
|
||||
//},
|
||||
{
|
||||
"stopPath",
|
||||
&autonavigation::luascriptfunctions::stopPath,
|
||||
@@ -131,14 +130,6 @@ scripting::LuaLibrary AutoNavigationModule::luaLibrary() const {
|
||||
"table",
|
||||
"Generate the path as described by the lua table input argument. "
|
||||
},
|
||||
{
|
||||
"generatePathFromFile",
|
||||
&autonavigation::luascriptfunctions::generatePathFromFile,
|
||||
{},
|
||||
"string",
|
||||
"Read an input file with lua instructions and use those to generate a camera "
|
||||
"path. "
|
||||
},
|
||||
{
|
||||
"getPathPositions",
|
||||
&autonavigation::luascriptfunctions::getPathPositions,
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/autonavigation/instruction.h>
|
||||
#include <modules/autonavigation/pathspecification.h>
|
||||
#include <modules/globebrowsing/globebrowsingmodule.h>
|
||||
#include <modules/globebrowsing/src/renderableglobe.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
@@ -58,15 +57,15 @@ int isFlying(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int continuePath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::continuePath");
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
module->AutoNavigationHandler().continuePath();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
//int continuePath(lua_State* L) {
|
||||
// ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::continuePath");
|
||||
//
|
||||
// AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
// module->AutoNavigationHandler().continuePath();
|
||||
//
|
||||
// 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");
|
||||
@@ -146,10 +145,10 @@ int goTo(lua_State* L) {
|
||||
}
|
||||
}
|
||||
|
||||
PathSpecification spec = PathSpecification(Instruction{ insDict });
|
||||
Instruction instruction(insDict);
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
module->AutoNavigationHandler().createPath(spec);
|
||||
module->AutoNavigationHandler().createPath(instruction);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
@@ -181,10 +180,10 @@ int goToHeight(lua_State* L) {
|
||||
}
|
||||
}
|
||||
|
||||
PathSpecification spec = PathSpecification(Instruction{ insDict });
|
||||
Instruction instruction(insDict);
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
module->AutoNavigationHandler().createPath(spec);
|
||||
module->AutoNavigationHandler().createPath(instruction);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
@@ -236,10 +235,10 @@ int goToGeo(lua_State* L) {
|
||||
}
|
||||
}
|
||||
|
||||
PathSpecification spec = PathSpecification(Instruction{ insDict });
|
||||
Instruction instruction(insDict);
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
module->AutoNavigationHandler().createPath(spec);
|
||||
module->AutoNavigationHandler().createPath(instruction);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
@@ -251,74 +250,16 @@ int generatePath(lua_State* L) {
|
||||
|
||||
ghoul::Dictionary dictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, dictionary);
|
||||
PathSpecification spec(dictionary);
|
||||
|
||||
if (spec.instructions.empty()) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(
|
||||
L, fmt::format("No instructions for camera path generation were provided.")
|
||||
);
|
||||
}
|
||||
Instruction instruction(dictionary);
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
module->AutoNavigationHandler().createPath(spec);
|
||||
module->AutoNavigationHandler().createPath(instruction);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generatePathFromFile(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::generatePathFromFile");
|
||||
|
||||
const std::string& filepath =
|
||||
ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
|
||||
if (filepath.empty()) {
|
||||
return ghoul::lua::luaError(L, "Filepath string is empty");
|
||||
}
|
||||
|
||||
const std::filesystem::path file = absPath(filepath);
|
||||
|
||||
LINFO(fmt::format("Reading path instructions from file: {}", file));
|
||||
|
||||
if (!std::filesystem::is_regular_file(file)) {
|
||||
throw ghoul::FileNotFoundError(file.string(), "PathSpecification");
|
||||
}
|
||||
|
||||
// Try to read the dictionary
|
||||
ghoul::Dictionary dictionary;
|
||||
try {
|
||||
ghoul::lua::loadDictionaryFromFile(file.string(), dictionary);
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
PathSpecification::Documentation(),
|
||||
dictionary,
|
||||
"PathSpecification"
|
||||
);
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
return ghoul::lua::luaError(
|
||||
L, fmt::format("Unable to read dictionary from file: {}", e.message)
|
||||
);
|
||||
}
|
||||
|
||||
PathSpecification spec(dictionary);
|
||||
|
||||
if (spec.instructions.empty()) {
|
||||
return ghoul::lua::luaError(
|
||||
L, fmt::format("No instructions for camera path generation were provided")
|
||||
);
|
||||
}
|
||||
|
||||
LINFOC("AutoNavigationModule", "Reading succeeded. Creating path");
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
|
||||
module->AutoNavigationHandler().createPath(spec);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: remove when not needed
|
||||
// Created for debugging. Access info for rendereable path
|
||||
int getPathPositions(lua_State* L) {
|
||||
|
||||
@@ -61,9 +61,13 @@ namespace {
|
||||
std::optional<bool> useTargetUpDirection;
|
||||
|
||||
// (NavigationState): A navigation state that will be the target
|
||||
// of this path segment.
|
||||
// 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 "instruction_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
struct Instruction {
|
||||
using NavigationState = interaction::NavigationHandler::NavigationState;
|
||||
|
||||
enum class Type {
|
||||
Node,
|
||||
NavigationState
|
||||
@@ -46,6 +48,7 @@ struct Instruction {
|
||||
Type type;
|
||||
|
||||
std::optional<double> duration;
|
||||
std::optional<NavigationState> startState;
|
||||
|
||||
// Node details
|
||||
std::string nodeIdentifier;
|
||||
@@ -54,7 +57,7 @@ struct Instruction {
|
||||
bool useTargetUpDirection;
|
||||
|
||||
// Navigation state details
|
||||
interaction::NavigationHandler::NavigationState navigationState;
|
||||
NavigationState navigationState;
|
||||
|
||||
std::vector<Waypoint> _waypoints;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/autonavigation/pathsegment.h>
|
||||
#include <modules/autonavigation/path.h>
|
||||
|
||||
#include <modules/autonavigation/autonavigationmodule.h>
|
||||
#include <modules/autonavigation/helperfunctions.h>
|
||||
@@ -37,18 +37,17 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "PathSegment";
|
||||
|
||||
constexpr const char* _loggerCat = "Path";
|
||||
const double Epsilon = 1E-7;
|
||||
} // namespace
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
PathSegment::PathSegment(Waypoint start, Waypoint end, CurveType type,
|
||||
std::optional<double> duration)
|
||||
Path::Path(Waypoint start, Waypoint end, CurveType type,
|
||||
std::optional<double> duration)
|
||||
: _start(start), _end(end), _curveType(type)
|
||||
{
|
||||
initCurve();
|
||||
initializePath();
|
||||
|
||||
if (duration.has_value()) {
|
||||
_duration = duration.value();
|
||||
@@ -61,26 +60,25 @@ PathSegment::PathSegment(Waypoint start, Waypoint end, CurveType type,
|
||||
}
|
||||
}
|
||||
|
||||
void PathSegment::setStartPoint(Waypoint cs) {
|
||||
void Path::setStartPoint(Waypoint cs) {
|
||||
_start = std::move(cs);
|
||||
initCurve();
|
||||
initializePath();
|
||||
// TODO later: maybe recompute duration as well...
|
||||
}
|
||||
|
||||
const Waypoint PathSegment::startPoint() const { return _start; }
|
||||
const Waypoint Path::startPoint() const { return _start; }
|
||||
|
||||
const Waypoint PathSegment::endPoint() const { return _end; }
|
||||
const Waypoint Path::endPoint() const { return _end; }
|
||||
|
||||
const double PathSegment::duration() const { return _duration; }
|
||||
const double Path::duration() const { return _duration; }
|
||||
|
||||
const double PathSegment::pathLength() const { return _curve->length(); }
|
||||
const double Path::pathLength() const { return _curve->length(); }
|
||||
|
||||
// TODO: remove function for debugging
|
||||
const std::vector<glm::dvec3> PathSegment::controlPoints() const {
|
||||
const std::vector<glm::dvec3> Path::controlPoints() const {
|
||||
return _curve->points();
|
||||
}
|
||||
|
||||
CameraPose PathSegment::traversePath(double dt) {
|
||||
CameraPose Path::traversePath(double dt) {
|
||||
if (!_curve || !_rotationInterpolator || !_speedFunction) {
|
||||
// TODO: handle better (abort path somehow)
|
||||
return _start.pose;
|
||||
@@ -103,20 +101,20 @@ CameraPose PathSegment::traversePath(double dt) {
|
||||
return interpolatedPose(_traveledDistance);
|
||||
}
|
||||
|
||||
std::string PathSegment::currentAnchor() const {
|
||||
std::string Path::currentAnchor() const {
|
||||
bool pastHalfway = (_traveledDistance / pathLength()) > 0.5;
|
||||
return (pastHalfway) ? _end.nodeDetails.identifier : _start.nodeDetails.identifier;
|
||||
}
|
||||
|
||||
bool PathSegment::hasReachedEnd() const {
|
||||
bool Path::hasReachedEnd() const {
|
||||
return (_traveledDistance / pathLength()) >= 1.0;
|
||||
}
|
||||
|
||||
double PathSegment::speedAtTime(double time) const {
|
||||
double Path::speedAtTime(double time) const {
|
||||
return _speedFunction->scaledValue(time, _duration, pathLength());
|
||||
}
|
||||
|
||||
CameraPose PathSegment::interpolatedPose(double distance) const {
|
||||
CameraPose Path::interpolatedPose(double distance) const {
|
||||
double u = distance / pathLength();
|
||||
CameraPose cs;
|
||||
cs.position = _curve->positionAt(u);
|
||||
@@ -124,7 +122,7 @@ CameraPose PathSegment::interpolatedPose(double distance) const {
|
||||
return cs;
|
||||
}
|
||||
|
||||
void PathSegment::initCurve() {
|
||||
void Path::initializePath() {
|
||||
_curve.reset();
|
||||
|
||||
switch (_curveType)
|
||||
@@ -34,11 +34,13 @@
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
class PathSegment {
|
||||
class Path {
|
||||
public:
|
||||
PathSegment(Waypoint start, Waypoint end, CurveType type,
|
||||
Path(Waypoint start, Waypoint end, CurveType type,
|
||||
std::optional<double> duration = std::nullopt);
|
||||
|
||||
// TODO: add a constructor that takes an instruction and curve type?
|
||||
|
||||
void setStartPoint(Waypoint wp);
|
||||
|
||||
const Waypoint startPoint() const;
|
||||
@@ -46,7 +48,7 @@ public:
|
||||
const double duration() const;
|
||||
const double pathLength() const;
|
||||
|
||||
const std::vector<glm::dvec3> controlPoints() const; // debugging
|
||||
const std::vector<glm::dvec3> controlPoints() const;
|
||||
|
||||
CameraPose traversePath(double dt);
|
||||
std::string currentAnchor() const;
|
||||
@@ -56,7 +58,7 @@ public:
|
||||
CameraPose interpolatedPose(double distance) const;
|
||||
|
||||
private:
|
||||
void initCurve();
|
||||
void initializePath();
|
||||
|
||||
Waypoint _start;
|
||||
Waypoint _end;
|
||||
@@ -1,76 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* 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/pathspecification.h>
|
||||
|
||||
#include <modules/autonavigation/instruction.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "PathSpecification";
|
||||
|
||||
struct [[codegen::Dictionary(PathSpecification)]] Parameters {
|
||||
// A list of path instructions
|
||||
std::vector<ghoul::Dictionary> instructions
|
||||
[[codegen::reference("autonavigation_pathinstruction")]];
|
||||
|
||||
// A navigation state that determines the start state for the camera path
|
||||
std::optional<ghoul::Dictionary> startState
|
||||
[[codegen::reference("core_navigation_state")]];
|
||||
};
|
||||
#include "pathspecification_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
documentation::Documentation PathSpecification::Documentation() {
|
||||
return codegen::doc<Parameters>("autonavigation_pathspecification");
|
||||
}
|
||||
|
||||
PathSpecification::PathSpecification(const ghoul::Dictionary& dictionary) {
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
const std::vector<ghoul::Dictionary> instructionDicts = p.instructions;
|
||||
int counter = 1;
|
||||
for (const ghoul::Dictionary& dict : instructionDicts) {
|
||||
try {
|
||||
instructions.push_back(Instruction(dict));
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LERROR(fmt::format("Failed reading instruction {}: {}", counter, e.message));
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (p.startState.has_value()) {
|
||||
startState = NavigationState(p.startState.value());
|
||||
}
|
||||
}
|
||||
|
||||
PathSpecification::PathSpecification(const Instruction instruction) {
|
||||
instructions.push_back(instruction);
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
@@ -1,51 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* 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___PATHSPECIFICATION___H__
|
||||
#define __OPENSPACE_MODULE___PATHSPECIFICATION___H__
|
||||
|
||||
#include <modules/autonavigation/instruction.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <optional>
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
struct PathSpecification {
|
||||
using NavigationState = interaction::NavigationHandler::NavigationState;
|
||||
|
||||
PathSpecification() = default;
|
||||
PathSpecification(const ghoul::Dictionary& dictionary);
|
||||
PathSpecification(const Instruction instruction);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
std::vector<Instruction> instructions;
|
||||
std::optional<NavigationState> startState;
|
||||
};
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
#endif // __OPENSPACE_MODULE___PATHSPECIFICATION___H__
|
||||
Reference in New Issue
Block a user