mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-03-10 23:38:38 -05:00
Add code for camera path generation module
Add all code in the state it was in Jan 10 2020 when branch cleanup was performed
This commit is contained in:
49
modules/autonavigation/CMakeLists.txt
Normal file
49
modules/autonavigation/CMakeLists.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
##########################################################################################
|
||||
# #
|
||||
# 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(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationhandler.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/transferfunctions.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathspecification.h
|
||||
)
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule_lua.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationhandler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/transferfunctions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pathspecification.cpp
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
create_new_module(
|
||||
"AutoNavigation"
|
||||
autonavigation_module
|
||||
STATIC
|
||||
${HEADER_FILES} ${SOURCE_FILES}
|
||||
)
|
||||
332
modules/autonavigation/autonavigationhandler.cpp
Normal file
332
modules/autonavigation/autonavigationhandler.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/autonavigationhandler.h>
|
||||
|
||||
#include <modules/autonavigation/transferfunctions.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.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>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "AutoNavigationHandler";
|
||||
} // namespace
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
AutoNavigationHandler::AutoNavigationHandler()
|
||||
: properties::PropertyOwner({ "AutoNavigationHandler" })
|
||||
{
|
||||
// Add the properties
|
||||
// TODO
|
||||
}
|
||||
|
||||
AutoNavigationHandler::~AutoNavigationHandler() {} // NOLINT
|
||||
|
||||
Camera* AutoNavigationHandler::camera() const {
|
||||
return global::navigationHandler.camera();
|
||||
}
|
||||
|
||||
const double AutoNavigationHandler::pathDuration() const {
|
||||
return _pathDuration;
|
||||
}
|
||||
|
||||
PathSegment& AutoNavigationHandler::currentPathSegment() {
|
||||
for (PathSegment& ps : _pathSegments) {
|
||||
double endTime = ps.startTime + ps.duration;
|
||||
if (endTime > _currentTime) {
|
||||
return ps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::updateCamera(double deltaTime) {
|
||||
ghoul_assert(camera() != nullptr, "Camera must not be nullptr");
|
||||
|
||||
if (!_isPlaying || _pathSegments.empty()) return;
|
||||
|
||||
PathSegment cps = currentPathSegment();
|
||||
|
||||
// INTERPOLATE (TODO: make a function, and allow different methods)
|
||||
|
||||
double t = (_currentTime - cps.startTime) / cps.duration;
|
||||
t = transferfunctions::cubicEaseInOut(t); // TEST
|
||||
t = std::max(0.0, std::min(t, 1.0));
|
||||
|
||||
// TODO: don't set every frame and
|
||||
// Set anchor node in orbitalNavigator, to render visible nodes and
|
||||
// add possibility to navigate when we reach the end.
|
||||
CameraState cs = (t < 0.5) ? cps.start : cps.end;
|
||||
global::navigationHandler.orbitalNavigator().setAnchorNode(cs.referenceNode);
|
||||
|
||||
// TODO: add different ways to interpolate later
|
||||
glm::dvec3 cameraPosition = cps.start.position * (1.0 - t) + cps.end.position * t;
|
||||
glm::dquat cameraRotation =
|
||||
glm::slerp(cps.start.rotation, cps.end.rotation, t);
|
||||
|
||||
camera()->setPositionVec3(cameraPosition);
|
||||
camera()->setRotation(cameraRotation);
|
||||
|
||||
_currentTime += deltaTime;
|
||||
|
||||
// reached the end of the path => stop playing
|
||||
if (_currentTime > _pathDuration) {
|
||||
_isPlaying = false;
|
||||
// TODO: implement suitable stop behaviour
|
||||
}
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::createPath(PathSpecification& spec) {
|
||||
clearPath();
|
||||
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;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
LINFO("Succefully generated camera path. Starting.");
|
||||
startPath();
|
||||
}
|
||||
else
|
||||
LINFO("Could not create path.");
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::clearPath() {
|
||||
_pathSegments.clear();
|
||||
_pathDuration = 0.0;
|
||||
_currentTime = 0.0;
|
||||
}
|
||||
|
||||
void AutoNavigationHandler::startPath() {
|
||||
ghoul_assert(!_pathSegments.empty(), "Cannot start an empty path");
|
||||
|
||||
_pathDuration = 0.0;
|
||||
for (auto ps : _pathSegments) {
|
||||
_pathDuration += ps.duration;
|
||||
}
|
||||
_currentTime = 0.0;
|
||||
_isPlaying = true;
|
||||
}
|
||||
|
||||
CameraState AutoNavigationHandler::getStartState() {
|
||||
CameraState cs;
|
||||
if (_pathSegments.empty()) {
|
||||
cs.position = camera()->positionVec3();
|
||||
cs.rotation = camera()->rotationQuaternion();
|
||||
cs.referenceNode = global::navigationHandler.anchorNode()->identifier();
|
||||
}
|
||||
else {
|
||||
cs = _pathSegments.back().end;
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::handleInstruction(const Instruction& instruction, int index)
|
||||
{
|
||||
CameraState startState = getStartState();
|
||||
CameraState endState;
|
||||
double duration, startTime;
|
||||
bool success = true;
|
||||
|
||||
switch (instruction.type)
|
||||
{
|
||||
case InstructionType::TargetNode:
|
||||
success = endFromTargetNodeInstruction(
|
||||
endState, startState, instruction, index
|
||||
);
|
||||
break;
|
||||
|
||||
case InstructionType::NavigationState:
|
||||
success = endFromNavigationStateInstruction(
|
||||
endState, instruction, index
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
LERROR(fmt::format("Non-implemented instruction type: {}.", instruction.type));
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success) return false;
|
||||
|
||||
// compute duration
|
||||
if (instruction.props->duration.has_value()) {
|
||||
duration = instruction.props->duration.value();
|
||||
if (duration <= 0) {
|
||||
LERROR(fmt::format("Failed creating path segment number {}. Duration can not be negative.", index + 1));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: compute default duration
|
||||
duration = 5.0;
|
||||
}
|
||||
|
||||
// compute startTime
|
||||
startTime = 0.0;
|
||||
if (!_pathSegments.empty()) {
|
||||
PathSegment& last = _pathSegments.back();
|
||||
startTime = last.startTime + last.duration;
|
||||
}
|
||||
|
||||
// create new path
|
||||
_pathSegments.push_back(
|
||||
PathSegment{ startState, endState, duration, startTime }
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::endFromTargetNodeInstruction(
|
||||
CameraState& endState, CameraState& prevState, const Instruction& instruction, int index)
|
||||
{
|
||||
TargetNodeInstructionProps* props =
|
||||
dynamic_cast<TargetNodeInstructionProps*>(instruction.props.get());
|
||||
|
||||
if (!props) {
|
||||
LERROR(fmt::format("Could not handle target node instruction (number {}).", index + 1));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute end state
|
||||
std::string& identifier = props->targetNode;
|
||||
const SceneGraphNode* targetNode = sceneGraphNode(identifier);
|
||||
if (!targetNode) {
|
||||
LERROR(fmt::format("Failed handling instruction number {}. Could not find node '{}' to target", index + 1, 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 {
|
||||
bool hasHeight = props->height.has_value();
|
||||
|
||||
// TODO: compute defualt height in a better way
|
||||
double defaultHeight = 2 * targetNode->boundingSphere();
|
||||
double height = hasHeight? props->height.value() : defaultHeight;
|
||||
|
||||
targetPos = computeTargetPositionAtNode(
|
||||
targetNode,
|
||||
prevState.position,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
glm::dmat4 lookAtMat = glm::lookAt(
|
||||
targetPos,
|
||||
targetNode->worldPosition(),
|
||||
camera()->lookUpVectorWorldSpace()
|
||||
);
|
||||
|
||||
glm::dquat targetRot = glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
|
||||
|
||||
endState = CameraState{ targetPos, targetRot, identifier };
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AutoNavigationHandler::endFromNavigationStateInstruction(
|
||||
CameraState& endState, const Instruction& instruction, int index)
|
||||
{
|
||||
NavigationStateInstructionProps* props =
|
||||
dynamic_cast<NavigationStateInstructionProps*>(instruction.props.get());
|
||||
|
||||
if (!props) {
|
||||
LERROR(fmt::format("Could not handle navigation state instruction (number {}).", index + 1));
|
||||
return false;
|
||||
}
|
||||
|
||||
interaction::NavigationHandler::NavigationState ns = props->navState;
|
||||
|
||||
// OBS! The following code is exactly the same as used in NavigationHandler::applyNavigationState. Should probably be made into a function.
|
||||
const SceneGraphNode* referenceFrame = sceneGraphNode(ns.referenceFrame);
|
||||
const SceneGraphNode* anchorNode = sceneGraphNode(ns.anchor); // The anchor is also the target
|
||||
|
||||
if (!anchorNode) {
|
||||
LERROR(fmt::format("Failed handling instruction number {}. Could not find node '{}' to target", index + 1, ns.anchor));
|
||||
return false;
|
||||
}
|
||||
|
||||
const glm::dvec3 anchorWorldPosition = anchorNode->worldPosition();
|
||||
const glm::dmat3 referenceFrameTransform = referenceFrame->worldRotationMatrix();
|
||||
|
||||
const glm::dvec3 targetPositionWorld = anchorWorldPosition +
|
||||
glm::dvec3(referenceFrameTransform * glm::dvec4(ns.position, 1.0));
|
||||
|
||||
glm::dvec3 up = ns.up.has_value() ?
|
||||
glm::normalize(referenceFrameTransform * ns.up.value()) :
|
||||
glm::dvec3(0.0, 1.0, 0.0);
|
||||
|
||||
// Construct vectors of a "neutral" view, i.e. when the aim is centered in view.
|
||||
glm::dvec3 neutralView =
|
||||
glm::normalize(anchorWorldPosition - targetPositionWorld);
|
||||
|
||||
glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt(
|
||||
glm::dvec3(0.0),
|
||||
neutralView,
|
||||
up
|
||||
)));
|
||||
|
||||
glm::dquat pitchRotation = glm::angleAxis(ns.pitch, glm::dvec3(1.f, 0.f, 0.f));
|
||||
glm::dquat yawRotation = glm::angleAxis(ns.yaw, glm::dvec3(0.f, -1.f, 0.f));
|
||||
|
||||
glm::quat targetRotation = neutralCameraRotation * yawRotation * pitchRotation;
|
||||
|
||||
endState = CameraState{ targetPositionWorld, targetRotation, ns.anchor };
|
||||
return true;
|
||||
}
|
||||
|
||||
glm::dvec3 AutoNavigationHandler::computeTargetPositionAtNode(
|
||||
const SceneGraphNode* node, glm::dvec3 prevPos, double height)
|
||||
{
|
||||
// TODO: compute actual distance above surface and validate negative values
|
||||
|
||||
glm::dvec3 targetPos = node->worldPosition();
|
||||
glm::dvec3 targetToPrevVector = prevPos - targetPos;
|
||||
|
||||
double radius = static_cast<double>(node->boundingSphere());
|
||||
|
||||
// move target position out from surface, along vector to camera
|
||||
targetPos += glm::normalize(targetToPrevVector) * (radius + height);
|
||||
|
||||
return targetPos;
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
91
modules/autonavigation/autonavigationhandler.h
Normal file
91
modules/autonavigation/autonavigationhandler.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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___AUTONAVIGATIONHANDLER___H__
|
||||
#define __OPENSPACE_MODULE___AUTONAVIGATIONHANDLER___H__
|
||||
|
||||
#include <modules/autonavigation/pathspecification.h>
|
||||
#include <openspace/interaction/interpolator.h>
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
namespace openspace {
|
||||
class Camera;
|
||||
} // namespace openspace
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
struct CameraState {
|
||||
glm::dvec3 position;
|
||||
glm::dquat rotation;
|
||||
std::string referenceNode;
|
||||
};
|
||||
|
||||
struct PathSegment {
|
||||
CameraState start;
|
||||
CameraState end;
|
||||
double duration;
|
||||
double startTime;
|
||||
};
|
||||
|
||||
class AutoNavigationHandler : public properties::PropertyOwner {
|
||||
public:
|
||||
AutoNavigationHandler();
|
||||
~AutoNavigationHandler();
|
||||
|
||||
// Mutators
|
||||
|
||||
// Accessors
|
||||
Camera* camera() const;
|
||||
const double pathDuration() const;
|
||||
PathSegment& currentPathSegment();
|
||||
|
||||
void updateCamera(double deltaTime);
|
||||
void createPath(PathSpecification& spec);
|
||||
void clearPath();
|
||||
void startPath();
|
||||
|
||||
private:
|
||||
CameraState getStartState();
|
||||
|
||||
bool handleInstruction(const Instruction& instruction, int index);
|
||||
|
||||
bool endFromTargetNodeInstruction(CameraState& endState, CameraState& prevState, const Instruction& instruction, int index);
|
||||
|
||||
bool endFromNavigationStateInstruction(CameraState& endState, const Instruction& instruction, int index);
|
||||
|
||||
glm::dvec3 computeTargetPositionAtNode(const SceneGraphNode* node,
|
||||
glm::dvec3 prevPos, double height);
|
||||
|
||||
std::vector<PathSegment> _pathSegments;
|
||||
|
||||
double _pathDuration;
|
||||
double _currentTime;
|
||||
bool _isPlaying = false;
|
||||
};
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
#endif // __OPENSPACE_CORE___NAVIGATIONHANDLER___H__
|
||||
88
modules/autonavigation/autonavigationmodule.cpp
Normal file
88
modules/autonavigation/autonavigationmodule.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/autonavigationmodule.h>
|
||||
|
||||
#include <modules/autonavigation/autonavigationmodule_lua.inl>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "AutoNavigationModule";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
AutoNavigationModule::AutoNavigationModule() : OpenSpaceModule(Name) {}
|
||||
|
||||
autonavigation::AutoNavigationHandler& AutoNavigationModule::AutoNavigationHandler() {
|
||||
return _autoNavigationHandler;
|
||||
}
|
||||
|
||||
std::vector<documentation::Documentation> AutoNavigationModule::documentations() const {
|
||||
return {
|
||||
// TODO: call documentation methods for the other classes in this module
|
||||
};
|
||||
}
|
||||
|
||||
scripting::LuaLibrary AutoNavigationModule::luaLibrary() const {
|
||||
scripting::LuaLibrary res;
|
||||
res.name = "autonavigation";
|
||||
res.functions = {
|
||||
{
|
||||
"goTo",
|
||||
&autonavigation::luascriptfunctions::goTo,
|
||||
{},
|
||||
"string, [double]",
|
||||
"TODO: Description. Go to the node with the given name with optional duration."
|
||||
},
|
||||
{
|
||||
"generatePath",
|
||||
&autonavigation::luascriptfunctions::generatePath,
|
||||
{},
|
||||
"table",
|
||||
"Generate the path as described by the lua table input argument. TODO: Describe how a path instruction is defined?. " //TODO also make this one start path from file
|
||||
},
|
||||
{
|
||||
"generatePathFromFile",
|
||||
&autonavigation::luascriptfunctions::generatePathFromFile,
|
||||
{},
|
||||
"string",
|
||||
"Read an input file with lua instructions and use those to generate a camera path. TODO: Describe how a path instruction is defined?. " //TODO also make this one start path from file
|
||||
}
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
void AutoNavigationModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
global::callback::preSync.emplace_back([this]() {
|
||||
_autoNavigationHandler.updateCamera(global::windowDelegate.deltaTime());
|
||||
});
|
||||
|
||||
// TODO: register other classes (that are Factory created) and used in this module, if any
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
55
modules/autonavigation/autonavigationmodule.h
Normal file
55
modules/autonavigation/autonavigationmodule.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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_AUTONAVIGATION___AUTONAVIGATION_MODULE___H__
|
||||
#define __OPENSPACE_MODULE_AUTONAVIGATION___AUTONAVIGATION_MODULE___H__
|
||||
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <modules/autonavigation/autonavigationhandler.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class AutoNavigationModule : public OpenSpaceModule {
|
||||
public:
|
||||
constexpr static const char* Name = "AutoNavigation";
|
||||
|
||||
AutoNavigationModule();
|
||||
virtual ~AutoNavigationModule() = default;
|
||||
|
||||
autonavigation::AutoNavigationHandler& AutoNavigationHandler();
|
||||
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
|
||||
private:
|
||||
void internalInitialize(const ghoul::Dictionary&) override;
|
||||
|
||||
autonavigation::AutoNavigationHandler _autoNavigationHandler;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___AUTONAVIGATION_MODULE___H__
|
||||
150
modules/autonavigation/autonavigationmodule_lua.inl
Normal file
150
modules/autonavigation/autonavigationmodule_lua.inl
Normal file
@@ -0,0 +1,150 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
namespace openspace::autonavigation::luascriptfunctions {
|
||||
|
||||
const double EPSILON = 1e-12;
|
||||
|
||||
int goTo(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::goTo");
|
||||
|
||||
const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
|
||||
if (!sceneGraphNode(nodeIdentifier)) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
|
||||
}
|
||||
|
||||
ghoul::Dictionary insDict;
|
||||
insDict.setValue("Target", nodeIdentifier);
|
||||
|
||||
if (nArguments > 1) {
|
||||
double duration = ghoul::lua::value<double>(L, 2);
|
||||
if (duration <= EPSILON) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero.");
|
||||
}
|
||||
insDict.setValue("Duration", duration);
|
||||
}
|
||||
|
||||
PathSpecification spec = PathSpecification(Instruction{insDict});
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine.module<AutoNavigationModule>();
|
||||
AutoNavigationHandler& handler = module->AutoNavigationHandler();
|
||||
handler.createPath(spec);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generatePath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::generatePath");
|
||||
|
||||
ghoul::Dictionary dictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, dictionary);
|
||||
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.")
|
||||
);
|
||||
}
|
||||
|
||||
AutoNavigationModule* module = global::moduleEngine.module<AutoNavigationModule>();
|
||||
AutoNavigationHandler& handler = module->AutoNavigationHandler();
|
||||
handler.createPath(spec);
|
||||
|
||||
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::string absolutePath = absPath(filepath);
|
||||
|
||||
LINFOC("AutoNavigationModule", fmt::format("Reading path instructions from file: {}", absolutePath));
|
||||
|
||||
if (!FileSys.fileExists(absolutePath)) {
|
||||
throw ghoul::FileNotFoundError(absolutePath, "PathSpecification");
|
||||
}
|
||||
|
||||
// Try to read the dictionary
|
||||
ghoul::Dictionary dictionary;
|
||||
try {
|
||||
ghoul::lua::loadDictionaryFromFile(absolutePath, 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>();
|
||||
AutoNavigationHandler& handler = module->AutoNavigationHandler();
|
||||
handler.createPath(spec);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::autonavigation::luascriptfunctions
|
||||
5
modules/autonavigation/include.cmake
Normal file
5
modules/autonavigation/include.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
set(DEFAULT_MODULE ON)
|
||||
|
||||
set(OPENSPACE_DEPENDENCIES
|
||||
#add possible other modules that this module depends upon
|
||||
)
|
||||
209
modules/autonavigation/pathspecification.cpp
Normal file
209
modules/autonavigation/pathspecification.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <openspace/documentation/verifier.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "PathInstruction";
|
||||
|
||||
constexpr const char* KeyInstructions = "Instructions";
|
||||
|
||||
constexpr const char* KeyTarget = "Target";
|
||||
constexpr const char* KeyDuration = "Duration";
|
||||
constexpr const char* KeyPosition = "Position";
|
||||
constexpr const char* KeyHeight = "Height";
|
||||
|
||||
constexpr const char* KeyNavigationState = "NavigationState";
|
||||
} // 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?
|
||||
|
||||
if (dictionary.hasValue<double>(KeyDuration)) {
|
||||
duration = dictionary.value<double>(KeyDuration);
|
||||
}
|
||||
}
|
||||
|
||||
TargetNodeInstructionProps::TargetNodeInstructionProps(
|
||||
const ghoul::Dictionary& dictionary) : InstructionProps(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);
|
||||
|
||||
if (dictionary.hasValue<glm::dvec3>(KeyPosition)) {
|
||||
position = dictionary.value<glm::dvec3>(KeyPosition);
|
||||
}
|
||||
|
||||
if (dictionary.hasValue<double>(KeyHeight)) {
|
||||
height = dictionary.value<double>(KeyHeight);
|
||||
}
|
||||
}
|
||||
|
||||
NavigationStateInstructionProps::NavigationStateInstructionProps(
|
||||
const ghoul::Dictionary& dictionary) : InstructionProps(dictionary)
|
||||
{
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyNavigationState)) {
|
||||
auto navStateDict = dictionary.value<ghoul::Dictionary>(KeyNavigationState);
|
||||
|
||||
try {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
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;
|
||||
}
|
||||
|
||||
navState = NavigationState(navStateDict);
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::Instruction(const ghoul::Dictionary& dictionary) {
|
||||
|
||||
// TODO: test against some documentation?
|
||||
|
||||
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."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
_instructions.push_back(Instruction{ insDict });
|
||||
}
|
||||
}
|
||||
|
||||
PathSpecification::PathSpecification(const Instruction instruction) {
|
||||
_instructions.push_back(instruction);
|
||||
}
|
||||
|
||||
const std::vector<Instruction>* PathSpecification::instructions() const {
|
||||
return &_instructions;
|
||||
}
|
||||
|
||||
documentation::Documentation PathSpecification::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Path Specification",
|
||||
"camera_path_specification",
|
||||
{
|
||||
{
|
||||
KeyInstructions,
|
||||
new TableVerifier,
|
||||
Optional::No,
|
||||
"A list of path instructions."
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
88
modules/autonavigation/pathspecification.h
Normal file
88
modules/autonavigation/pathspecification.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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___PATHINSTRUCTION___H__
|
||||
#define __OPENSPACE_MODULE___PATHINSTRUCTION___H__
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <optional>
|
||||
|
||||
namespace openspace::autonavigation {
|
||||
|
||||
enum InstructionType { TargetNode, NavigationState };
|
||||
|
||||
struct InstructionProps {
|
||||
InstructionProps() = default;
|
||||
InstructionProps(const ghoul::Dictionary& dictionary);
|
||||
virtual ~InstructionProps() {} // abstract
|
||||
|
||||
std::optional<double> duration;
|
||||
};
|
||||
|
||||
struct TargetNodeInstructionProps : public InstructionProps {
|
||||
TargetNodeInstructionProps(const ghoul::Dictionary& dictionary);
|
||||
|
||||
std::string targetNode;
|
||||
std::optional<glm::dvec3> position; // relative to target node (model space)
|
||||
std::optional<double> height;
|
||||
};
|
||||
|
||||
struct NavigationStateInstructionProps : public InstructionProps {
|
||||
using NavigationState = interaction::NavigationHandler::NavigationState;
|
||||
|
||||
NavigationStateInstructionProps(const ghoul::Dictionary& dictionary);
|
||||
|
||||
NavigationState navState;
|
||||
};
|
||||
|
||||
struct Instruction {
|
||||
Instruction() = default;
|
||||
Instruction(const ghoul::Dictionary& dictionary);
|
||||
|
||||
InstructionType type;
|
||||
std::shared_ptr<InstructionProps> props;
|
||||
};
|
||||
|
||||
class PathSpecification {
|
||||
|
||||
public:
|
||||
PathSpecification() = default;
|
||||
PathSpecification(const ghoul::Dictionary& dictionary);
|
||||
PathSpecification(const Instruction instruction);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
// Accessors
|
||||
const std::vector<Instruction>* instructions() const;
|
||||
|
||||
private:
|
||||
std::vector<Instruction> _instructions;
|
||||
// TODO: maxSpeed or speedFactor or something?
|
||||
};
|
||||
|
||||
} // namespace openspace::autonavigation
|
||||
|
||||
#endif // __OPENSPACE_MODULE___NAVIGATIONHANDLER___H__
|
||||
76
modules/autonavigation/transferfunctions.cpp
Normal file
76
modules/autonavigation/transferfunctions.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/transferfunctions.h>
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
namespace openspace::autonavigation::transferfunctions {
|
||||
|
||||
double linear(double t) { return t; };
|
||||
|
||||
double step(double t) { return (t > 0.5); };
|
||||
|
||||
double circularEaseOut(double p){
|
||||
return sqrt((2 - p) * p);
|
||||
}
|
||||
|
||||
double cubicEaseIn(double t) { return (t*t*t); };
|
||||
|
||||
double cubicEaseOut(double t) {
|
||||
double p = 1 - t;
|
||||
return (p*p*p);
|
||||
};
|
||||
|
||||
double cubicEaseInOut(double t) {
|
||||
if (t < 0.5) {
|
||||
return 4 * t * t * t;
|
||||
}
|
||||
else {
|
||||
double f = ((2 * t) - 2);
|
||||
return 0.5 * f * f * f + 1;
|
||||
}
|
||||
};
|
||||
|
||||
double quadraticEaseInOut(double t) {
|
||||
if (t < 0.5) {
|
||||
return 2 * t * t;
|
||||
}
|
||||
else {
|
||||
return (-2 * t * t) + (4 * t) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
double exponentialEaseInOut(double t) {
|
||||
if (t == 0.0 || t == 1.0) return t;
|
||||
|
||||
if (t < 0.5) {
|
||||
return 0.5 * glm::pow(2, (20 * t) - 10);
|
||||
}
|
||||
else {
|
||||
return -0.5 * glm::pow(2, (-20 * t) + 10) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
49
modules/autonavigation/transferfunctions.h
Normal file
49
modules/autonavigation/transferfunctions.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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___TRANSFERFUNCTIONS___H__
|
||||
#define __OPENSPACE_MODULE___TRANSFERFUNCTIONS___H__
|
||||
|
||||
namespace openspace::autonavigation::transferfunctions {
|
||||
|
||||
// Based on functions from https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c
|
||||
|
||||
double linear(double t);
|
||||
|
||||
double step(double t);
|
||||
|
||||
double circularEaseOut(double p);
|
||||
|
||||
double cubicEaseIn(double t);
|
||||
|
||||
double cubicEaseOut(double t);
|
||||
|
||||
double cubicEaseInOut(double t);
|
||||
|
||||
double quadraticEaseInOut(double t);
|
||||
|
||||
double exponentialEaseInOut(double t);
|
||||
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user