mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-24 04:58:59 -05:00
refactor instructions
This commit is contained in:
@@ -102,7 +102,7 @@ const SceneGraphNode* AutoNavigationHandler::anchor() const {
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::hasFinished() const {
|
||||
int lastIndex = (int)_pathSegments.size() - 1;
|
||||
unsigned int lastIndex = (unsigned int)_pathSegments.size() - 1;
|
||||
return _currentSegmentIndex > lastIndex;
|
||||
}
|
||||
|
||||
@@ -163,11 +163,13 @@ void AutoNavigationHandler::createPath(PathSpecification& spec) {
|
||||
|
||||
bool success = true;
|
||||
for (int i = 0; i < spec.instructions()->size(); i++) {
|
||||
const Instruction& ins = spec.instructions()->at(i);
|
||||
success = handleInstruction(ins, i);
|
||||
|
||||
if (!success)
|
||||
break;
|
||||
const Instruction* ins = spec.instruction(i);
|
||||
if (ins) {
|
||||
// TODO: allow for a list of waypoints
|
||||
std::vector<Waypoint> waypoints = ins->getWaypoints();
|
||||
if (waypoints.size() > 0)
|
||||
addSegment(waypoints[0], ins);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have a specified start navigation state. If so, update first segment
|
||||
@@ -291,112 +293,15 @@ Waypoint AutoNavigationHandler::lastWayPoint() {
|
||||
return _pathSegments.empty() ? wayPointFromCamera() : _pathSegments.back()->end();
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::handleInstruction(const Instruction& ins, int index) {
|
||||
bool success = true;
|
||||
switch (ins.type)
|
||||
{
|
||||
case InstructionType::TargetNode:
|
||||
success = handleTargetNodeInstruction(ins);
|
||||
break;
|
||||
|
||||
case InstructionType::NavigationState:
|
||||
success = handleNavigationStateInstruction(ins);
|
||||
break;
|
||||
|
||||
default:
|
||||
LERROR("Non-implemented instruction type.");
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
LERROR(fmt::format("Failed handling instruction number {}.", std::to_string(index + 1)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::handleTargetNodeInstruction(const Instruction& ins) {
|
||||
// Verify instruction type
|
||||
TargetNodeInstructionProps* props =
|
||||
dynamic_cast<TargetNodeInstructionProps*>(ins.props.get());
|
||||
|
||||
if (!props) {
|
||||
LERROR("Could not handle target node instruction.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute end state
|
||||
std::string& identifier = props->targetNode;
|
||||
const SceneGraphNode* targetNode = sceneGraphNode(identifier);
|
||||
|
||||
if (!targetNode) {
|
||||
LERROR(fmt::format("Could not find node '{}' to target", identifier));
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::dvec3 targetPos;
|
||||
if (props->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() * props->position.value();
|
||||
}
|
||||
else {
|
||||
// TODO: Instead of this case, allow the curve to set its final position
|
||||
|
||||
glm::dvec3 nodePos = targetNode->worldPosition();
|
||||
glm::dvec3 nodeToPrev = lastWayPoint().position() - nodePos;
|
||||
// TODO: compute position in a more clever way
|
||||
|
||||
const double radius = WaypointNodeDetails::findValidBoundingSphere(targetNode, _minAllowedBoundingSphere);
|
||||
const double defaultHeight = 2 * radius;
|
||||
|
||||
bool hasHeight = props->height.has_value();
|
||||
double height = hasHeight ? props->height.value() : defaultHeight;
|
||||
|
||||
// move target position out from surface, along vector to camera
|
||||
targetPos = nodePos + glm::normalize(nodeToPrev) * (radius + height);
|
||||
}
|
||||
|
||||
glm::dmat4 lookAtMat = glm::lookAt(
|
||||
targetPos,
|
||||
targetNode->worldPosition(),
|
||||
camera()->lookUpVectorWorldSpace()
|
||||
);
|
||||
|
||||
glm::dquat targetRot = glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
|
||||
|
||||
Waypoint endState{ targetPos, targetRot, identifier, _minAllowedBoundingSphere };
|
||||
addSegment(endState, ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::handleNavigationStateInstruction(const Instruction& ins) {
|
||||
// Verify instruction type
|
||||
NavigationStateInstructionProps* props =
|
||||
dynamic_cast<NavigationStateInstructionProps*>(ins.props.get());
|
||||
|
||||
if (!props) {
|
||||
LERROR(fmt::format("Could not handle navigation state instruction."));
|
||||
return false;
|
||||
}
|
||||
|
||||
Waypoint endState{ props->navState , _minAllowedBoundingSphere };
|
||||
addSegment(endState, ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::addSegment(Waypoint& waypoint, const Instruction& ins){
|
||||
void AutoNavigationHandler::addSegment(Waypoint& waypoint, const Instruction* ins){
|
||||
// TODO: Improve how curve types are handled
|
||||
const int curveType = _defaultCurveOption;
|
||||
|
||||
PathSegment segment = PathSegment(lastWayPoint(), waypoint, CurveType(curveType));
|
||||
|
||||
// TODO: handle duration better
|
||||
if (ins.props->duration.has_value()) {
|
||||
segment.setDuration(ins.props->duration.value());
|
||||
if (ins->duration.has_value()) {
|
||||
segment.setDuration(ins->duration.value());
|
||||
}
|
||||
_pathSegments.push_back(std::unique_ptr<PathSegment>(new PathSegment(segment)));
|
||||
}
|
||||
|
||||
@@ -68,18 +68,11 @@ public:
|
||||
private:
|
||||
Waypoint wayPointFromCamera();
|
||||
Waypoint lastWayPoint();
|
||||
|
||||
bool handleInstruction(const Instruction& ins, int index);
|
||||
|
||||
bool handleTargetNodeInstruction(const Instruction& ins);
|
||||
bool handleNavigationStateInstruction(const Instruction& ins);
|
||||
|
||||
void addSegment(Waypoint& state, const Instruction& ins);
|
||||
void addSegment(Waypoint& waypoint, const Instruction* ins);
|
||||
|
||||
// this list essentially represents the camera path
|
||||
std::vector<std::unique_ptr<PathSegment>> _pathSegments;
|
||||
|
||||
|
||||
bool _isPlaying = false;
|
||||
unsigned int _currentSegmentIndex = 0;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace openspace::autonavigation::luascriptfunctions {
|
||||
insDict.setValue("Duration", duration);
|
||||
}
|
||||
|
||||
PathSpecification spec = PathSpecification(Instruction{insDict});
|
||||
PathSpecification spec = PathSpecification(TargetNodeInstruction{insDict});
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine.module<AutoNavigationModule>();
|
||||
AutoNavigationHandler& handler = module->AutoNavigationHandler();
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
#include <modules/autonavigation/instruction.h>
|
||||
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
@@ -40,73 +45,30 @@ namespace {
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
documentation::Documentation TargetNodeInstructionDocumentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Target Node Instruction",
|
||||
"target_node_instruction",
|
||||
{
|
||||
{
|
||||
KeyTarget,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The identifier of the target node."
|
||||
},
|
||||
{
|
||||
KeyDuration,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The desired duration for the camera movement."
|
||||
},
|
||||
{
|
||||
KeyPosition,
|
||||
new Vector3Verifier<double>,
|
||||
Optional::Yes,
|
||||
"The desired final position for the camera movement, given in model space."
|
||||
},
|
||||
{
|
||||
KeyHeight,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The desired height from surface for final position (meters). Will be ignored if a target position is set. "
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
InstructionProps::InstructionProps(const ghoul::Dictionary& dictionary) {
|
||||
// TODO: validate against some documentation?
|
||||
|
||||
Instruction::Instruction(const ghoul::Dictionary& dictionary) {
|
||||
if (dictionary.hasValue<double>(KeyDuration)) {
|
||||
duration = dictionary.value<double>(KeyDuration);
|
||||
}
|
||||
|
||||
// TODO: include info about pauses/stops
|
||||
}
|
||||
|
||||
InstructionProps::~InstructionProps() {}
|
||||
Instruction::~Instruction() {}
|
||||
|
||||
TargetNodeInstructionProps::TargetNodeInstructionProps(
|
||||
const ghoul::Dictionary& dictionary) : InstructionProps(dictionary)
|
||||
TargetNodeInstruction::TargetNodeInstruction(const ghoul::Dictionary& dictionary)
|
||||
: Instruction(dictionary)
|
||||
{
|
||||
try {
|
||||
documentation::testSpecificationAndThrow(
|
||||
TargetNodeInstructionDocumentation(),
|
||||
dictionary,
|
||||
"Target Node Instruction"
|
||||
);
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LERROR(fmt::format("Unable to generate target node instruction from dictionary. Does not match documentation: {}", e.message));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dictionary.hasValue<std::string>(KeyTarget)) {
|
||||
throw ghoul::RuntimeError(
|
||||
"A camera path instruction requires a target node, to go to or use as reference frame."
|
||||
);
|
||||
}
|
||||
|
||||
targetNode = dictionary.value<std::string>(KeyTarget);
|
||||
nodeIdentifier = dictionary.value<std::string>(KeyTarget);
|
||||
|
||||
if (!sceneGraphNode(nodeIdentifier)) {
|
||||
throw ghoul::RuntimeError(fmt::format("Could not find target node '{}'", nodeIdentifier));
|
||||
}
|
||||
|
||||
if (dictionary.hasValue<glm::dvec3>(KeyPosition)) {
|
||||
position = dictionary.value<glm::dvec3>(KeyPosition);
|
||||
@@ -117,46 +79,76 @@ TargetNodeInstructionProps::TargetNodeInstructionProps(
|
||||
}
|
||||
}
|
||||
|
||||
NavigationStateInstructionProps::NavigationStateInstructionProps(
|
||||
const ghoul::Dictionary& dictionary) : InstructionProps(dictionary)
|
||||
std::vector<Waypoint> TargetNodeInstruction::getWaypoints() const {
|
||||
const SceneGraphNode* targetNode = sceneGraphNode(nodeIdentifier);
|
||||
if (!targetNode) {
|
||||
LERROR(fmt::format("Could not find target node '{}'", nodeIdentifier));
|
||||
return std::vector<Waypoint>();
|
||||
}
|
||||
|
||||
glm::dvec3 targetPos;
|
||||
if (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();
|
||||
}
|
||||
else {
|
||||
// TODO: Instead of this case, allow the curve to set its final position
|
||||
|
||||
//glm::dvec3 nodePos = targetNode->worldPosition();
|
||||
//glm::dvec3 nodeToPrev = lastWayPoint().position() - nodePos;
|
||||
//// TODO: compute position in a more clever way
|
||||
|
||||
//const double radius = WaypointNodeDetails::findValidBoundingSphere(targetNode, _minAllowedBoundingSphere);
|
||||
//const double defaultHeight = 2 * radius;
|
||||
|
||||
//bool hasHeight = props->height.has_value();
|
||||
//double height = hasHeight ? props->height.value() : defaultHeight;
|
||||
|
||||
//// move target position out from surface, along vector to camera
|
||||
//targetPos = nodePos + glm::normalize(nodeToPrev) * (radius + height);
|
||||
|
||||
|
||||
// OBS! TEMPORARY!! TODO: fix so that a camera pose is optional in Waypoint
|
||||
const double radius = WaypointNodeDetails::findValidBoundingSphere(targetNode, 10.0);
|
||||
targetPos = targetNode->worldPosition() + 3 * radius * glm::dvec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
Camera* camera = global::navigationHandler.camera();
|
||||
|
||||
glm::dmat4 lookAtMat = glm::lookAt(
|
||||
targetPos,
|
||||
targetNode->worldPosition(),
|
||||
camera->lookUpVectorWorldSpace()
|
||||
);
|
||||
|
||||
glm::dquat targetRot = glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
|
||||
|
||||
Waypoint wp{ targetPos, targetRot, nodeIdentifier, 10.0 }; // TODO: make property for min valid boudnignsphere
|
||||
|
||||
return std::vector<Waypoint>({ wp });
|
||||
}
|
||||
|
||||
NavigationStateInstruction::NavigationStateInstruction(
|
||||
const ghoul::Dictionary& dictionary): Instruction(dictionary)
|
||||
{
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyNavigationState)) {
|
||||
auto navStateDict = dictionary.value<ghoul::Dictionary>(KeyNavigationState);
|
||||
|
||||
try {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
interaction::NavigationHandler::NavigationState::Documentation(),
|
||||
navStateDict,
|
||||
"NavigationState"
|
||||
);
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LERROR(fmt::format("Unable to generate navigation state instruction from dictionary. Does not match documentation: {}", e.message));
|
||||
return;
|
||||
}
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
NavigationState::Documentation(),
|
||||
navStateDict,
|
||||
"NavigationState"
|
||||
);
|
||||
|
||||
navState = interaction::NavigationHandler::NavigationState(navStateDict);
|
||||
navigationState = NavigationState(navStateDict);
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::Instruction(const ghoul::Dictionary& dictionary) {
|
||||
|
||||
// TODO: test against some documentation?
|
||||
|
||||
// Deduce the instruction type based on the fields in the dictionary
|
||||
if (dictionary.hasValue<std::string>(KeyTarget)) {
|
||||
type = InstructionType::TargetNode;
|
||||
props = std::make_shared<TargetNodeInstructionProps>(dictionary);
|
||||
}
|
||||
else if (dictionary.hasValue<ghoul::Dictionary>(KeyNavigationState)) {
|
||||
type = InstructionType::NavigationState;
|
||||
props = std::make_shared<NavigationStateInstructionProps>(dictionary);
|
||||
}
|
||||
else {
|
||||
throw ghoul::RuntimeError(
|
||||
"Could not deduce instruction type."
|
||||
);
|
||||
}
|
||||
std::vector<Waypoint> NavigationStateInstruction::getWaypoints() const {
|
||||
Waypoint wp{ navigationState, 10.0 }; // TODO: make property for min valid boudnignsphere
|
||||
return std::vector<Waypoint>({ wp });
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
@@ -25,42 +25,53 @@
|
||||
#ifndef __OPENSPACE_MODULE___PATHINSTRUCTION___H__
|
||||
#define __OPENSPACE_MODULE___PATHINSTRUCTION___H__
|
||||
|
||||
#include <modules/autonavigation/waypoint.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <optional>
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
enum class InstructionType { TargetNode, NavigationState };
|
||||
struct Instruction {
|
||||
Instruction() = default;
|
||||
Instruction(const ghoul::Dictionary& dictionary);
|
||||
virtual ~Instruction();
|
||||
|
||||
struct InstructionProps {
|
||||
InstructionProps() = default;
|
||||
InstructionProps(const ghoul::Dictionary& dictionary);
|
||||
virtual ~InstructionProps() = 0;
|
||||
virtual std::vector<Waypoint> getWaypoints() const = 0;
|
||||
|
||||
// TODO
|
||||
//static documentation::Documentation Documentation();
|
||||
|
||||
std::optional<double> duration;
|
||||
|
||||
// TODO: include pause information
|
||||
};
|
||||
|
||||
struct TargetNodeInstructionProps : public InstructionProps {
|
||||
TargetNodeInstructionProps(const ghoul::Dictionary& dictionary);
|
||||
struct TargetNodeInstruction : public Instruction {
|
||||
TargetNodeInstruction(const ghoul::Dictionary& dictionary);
|
||||
|
||||
std::string targetNode;
|
||||
std::vector<Waypoint> getWaypoints() const override;
|
||||
|
||||
// TODO
|
||||
//static documentation::Documentation Documentation();
|
||||
|
||||
std::string nodeIdentifier;
|
||||
std::optional<glm::dvec3> position; // relative to target node (model space)
|
||||
std::optional<double> height;
|
||||
};
|
||||
|
||||
struct NavigationStateInstructionProps : public InstructionProps {
|
||||
NavigationStateInstructionProps(const ghoul::Dictionary& dictionary);
|
||||
struct NavigationStateInstruction : public Instruction {
|
||||
using NavigationState = interaction::NavigationHandler::NavigationState;
|
||||
|
||||
interaction::NavigationHandler::NavigationState navState;
|
||||
NavigationStateInstruction(const ghoul::Dictionary& dictionary);
|
||||
|
||||
std::vector<Waypoint> getWaypoints() const override;
|
||||
|
||||
// TODO
|
||||
//static documentation::Documentation Documentation();
|
||||
|
||||
NavigationState navigationState;
|
||||
};
|
||||
|
||||
struct Instruction {
|
||||
Instruction() = default;
|
||||
Instruction(const ghoul::Dictionary& dictionary);
|
||||
|
||||
InstructionType type;
|
||||
std::shared_ptr<InstructionProps> props;
|
||||
};
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
|
||||
@@ -35,66 +35,76 @@ namespace {
|
||||
constexpr const char* KeyStopAtTargets = "StopAtTargets";
|
||||
constexpr const char* KeyStartState = "StartState";
|
||||
|
||||
// Instruction Types
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyTypeTargetNode = "Node";
|
||||
constexpr const char* KeyTypeNavigationState = "NavigationState";
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
PathSpecification::PathSpecification(const ghoul::Dictionary& dictionary) {
|
||||
try {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"Path Specification"
|
||||
);
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LERROR(fmt::format("Unable to generate path specification from dictionary. Does not match documentation: {}", e.message));
|
||||
return;
|
||||
}
|
||||
using NavigationState = interaction::NavigationHandler::NavigationState;
|
||||
|
||||
// Read instructions from dictionary
|
||||
ghoul::Dictionary instructions = dictionary.value<ghoul::Dictionary>(KeyInstructions);
|
||||
PathSpecification::PathSpecification(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"Path Specification"
|
||||
);
|
||||
|
||||
ghoul::Dictionary instructions =
|
||||
dictionary.value<ghoul::Dictionary>(KeyInstructions);
|
||||
|
||||
for (size_t i = 1; i <= instructions.size(); ++i) {
|
||||
ghoul::Dictionary insDict = instructions.value<ghoul::Dictionary>(std::to_string(i));
|
||||
ghoul::Dictionary insDict =
|
||||
instructions.value<ghoul::Dictionary>(std::to_string(i));
|
||||
|
||||
_instructions.push_back(Instruction{ insDict });
|
||||
if (!insDict.hasValue<std::string>(KeyType)) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Each instruction must have a specified type."
|
||||
);
|
||||
}
|
||||
|
||||
std::string type = insDict.value<std::string>(KeyType);
|
||||
tryReadInstruction(i, type, insDict);
|
||||
}
|
||||
|
||||
// Read stop at targets flag
|
||||
if (dictionary.hasValue<bool>(KeyStopAtTargets)) {
|
||||
_stopAtTargets = dictionary.value<bool>(KeyStopAtTargets);
|
||||
}
|
||||
|
||||
// Read start state
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyStartState)) {
|
||||
auto navStateDict = dictionary.value<ghoul::Dictionary>(KeyStartState);
|
||||
|
||||
try {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
interaction::NavigationHandler::NavigationState::Documentation(),
|
||||
NavigationState::Documentation(),
|
||||
navStateDict,
|
||||
"NavigationState"
|
||||
);
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LERROR(fmt::format("Unable to read start navigation state. Does not match documentation: {}", e.message));
|
||||
LERROR(fmt::format("Unable to read start navigation state. {}", e.message));
|
||||
return;
|
||||
}
|
||||
|
||||
_startState = interaction::NavigationHandler::NavigationState(navStateDict);
|
||||
_startState = NavigationState(navStateDict);
|
||||
}
|
||||
}
|
||||
|
||||
PathSpecification::PathSpecification(const Instruction instruction) {
|
||||
_instructions.push_back(instruction);
|
||||
_stopAtTargets = false;
|
||||
PathSpecification::PathSpecification(const TargetNodeInstruction instruction) {
|
||||
_instructions.push_back(std::make_unique<TargetNodeInstruction>(instruction));
|
||||
}
|
||||
|
||||
const std::vector<Instruction>* PathSpecification::instructions() const {
|
||||
const std::vector<std::unique_ptr<Instruction>>* PathSpecification::instructions() const {
|
||||
return &_instructions;
|
||||
}
|
||||
|
||||
const Instruction* PathSpecification::instruction(int i) const {
|
||||
return (_instructions.size() > i) ? _instructions[i].get() : nullptr;
|
||||
}
|
||||
|
||||
const bool PathSpecification::stopAtTargets() const {
|
||||
return _stopAtTargets.value();
|
||||
}
|
||||
@@ -103,7 +113,7 @@ const bool PathSpecification::stopAtTargetsSpecified() const {
|
||||
return _stopAtTargets.has_value();
|
||||
}
|
||||
|
||||
const interaction::NavigationHandler::NavigationState& PathSpecification::startState() const {
|
||||
const NavigationState& PathSpecification::startState() const {
|
||||
return _startState.value();
|
||||
}
|
||||
|
||||
@@ -140,4 +150,36 @@ documentation::Documentation PathSpecification::Documentation() {
|
||||
};
|
||||
}
|
||||
|
||||
void PathSpecification::tryReadInstruction(int index, std::string type,
|
||||
ghoul::Dictionary& dictionary)
|
||||
{
|
||||
// create correct type of instruction and present and throw error with useful
|
||||
// error message if we failed.
|
||||
if (type == KeyTypeTargetNode) {
|
||||
try {
|
||||
_instructions.push_back(std::make_unique<TargetNodeInstruction>(dictionary));
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
throw ghoul::RuntimeError(
|
||||
fmt::format("Failed reading instruction {}: {}", index, e.message));
|
||||
}
|
||||
}
|
||||
else if (type == KeyTypeNavigationState) {
|
||||
try {
|
||||
_instructions.push_back(
|
||||
std::make_unique<NavigationStateInstruction>(dictionary));
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
throw ghoul::RuntimeError(
|
||||
fmt::format("Failed reading instruction {}: {}", index, e.message));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Failed reading instruction {}: Uknown instruction type '{}'",
|
||||
index, type)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
@@ -39,19 +39,22 @@ class PathSpecification {
|
||||
public:
|
||||
PathSpecification() = default;
|
||||
PathSpecification(const ghoul::Dictionary& dictionary);
|
||||
PathSpecification(const Instruction instruction);
|
||||
PathSpecification(const TargetNodeInstruction instruction);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
// Accessors
|
||||
const std::vector<Instruction>* instructions() const;
|
||||
const std::vector<std::unique_ptr<Instruction>>* instructions() const;
|
||||
const Instruction* instruction(int i) const;
|
||||
const bool stopAtTargets() const;
|
||||
const bool stopAtTargetsSpecified() const;
|
||||
const NavigationState& startState() const;
|
||||
const bool hasStartState() const;
|
||||
|
||||
private:
|
||||
std::vector<Instruction> _instructions;
|
||||
void tryReadInstruction(int index, std::string type, ghoul::Dictionary& dictionary);
|
||||
|
||||
std::vector<std::unique_ptr<Instruction>> _instructions;
|
||||
std::optional<bool> _stopAtTargets;
|
||||
std::optional<NavigationState> _startState;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user