Remove support for multiple path segments

A "path" is now only one "segment"
This commit is contained in:
Emma Broman
2021-06-04 15:05:01 +02:00
parent 8a08fa43e4
commit fd9521db41
11 changed files with 171 additions and 422 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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__