Remove old autonavigation module files

This commit is contained in:
Emma Broman
2021-06-23 15:16:08 +02:00
parent 4ae70283a7
commit 6c9840121f
24 changed files with 0 additions and 3405 deletions
-59
View File
@@ -1,59 +0,0 @@
##########################################################################################
# #
# OpenSpace #
# #
# Copyright (c) 2014-2021 #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
# software and associated documentation files (the "Software"), to deal in the Software #
# without restriction, including without limitation the rights to use, copy, modify, #
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to #
# permit persons to whom the Software is furnished to do so, subject to the following #
# conditions: #
# #
# The above copyright notice and this permission notice shall be included in all copies #
# or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A #
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF #
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE #
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
##########################################################################################
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/autonavigationmodule.h
${CMAKE_CURRENT_SOURCE_DIR}/helperfunctions.h
${CMAKE_CURRENT_SOURCE_DIR}/path.h
${CMAKE_CURRENT_SOURCE_DIR}/pathcreator.h
${CMAKE_CURRENT_SOURCE_DIR}/pathcurve.h
${CMAKE_CURRENT_SOURCE_DIR}/pathnavigationhandler.h
${CMAKE_CURRENT_SOURCE_DIR}/waypoint.h
${CMAKE_CURRENT_SOURCE_DIR}/curves/avoidcollisioncurve.h
${CMAKE_CURRENT_SOURCE_DIR}/curves/zoomoutoverviewcurve.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}/helperfunctions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/path.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pathcreator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pathcurve.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pathnavigationhandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/waypoint.cpp
${CMAKE_CURRENT_SOURCE_DIR}/curves/avoidcollisioncurve.cpp
${CMAKE_CURRENT_SOURCE_DIR}/curves/zoomoutoverviewcurve.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
create_new_module(
"AutoNavigation"
autonavigation_module
STATIC
${HEADER_FILES} ${SOURCE_FILES}
)
@@ -1,160 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/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 openspace {
AutoNavigationModule::AutoNavigationModule()
: OpenSpaceModule(Name)
{
addPropertySubOwner(_pathNavigationHandler);
}
pathnavigation::PathNavigationHandler& AutoNavigationModule::PathNavigationHandler() {
return _pathNavigationHandler;
}
scripting::LuaLibrary AutoNavigationModule::luaLibrary() const {
scripting::LuaLibrary res;
res.name = "autonavigation";
res.scripts = {
absPath("${MODULE_AUTONAVIGATION}/scripts/rendering.lua")
};
res.functions = {
{
"isFlying",
&pathnavigation::luascriptfunctions::isFlying,
{},
"",
"Returns true if a camera path is currently running, and false otherwise."
},
{
"continuePath",
&pathnavigation::luascriptfunctions::continuePath,
{},
"",
"Continue playing a paused camera path."
},
{
"pausePath",
&pathnavigation::luascriptfunctions::pausePath,
{},
"",
"Pause a playing camera path."
},
{
"stopPath",
&pathnavigation::luascriptfunctions::stopPath,
{},
"",
"Stops a path, if one is being played."
},
{
"goTo",
&pathnavigation::luascriptfunctions::goTo,
{},
"string [, bool, double]",
"Move the camera to the node with the specified name. The optional double "
"specifies the duration of the motion. If the optional bool is set to true "
"the target up vector for camera is set based on the target node. Either of "
"the optional parameters can be left out."
},
{
"goToHeight",
&pathnavigation::luascriptfunctions::goToHeight,
{},
"string, double [, bool, double]",
"Move the camera to the node with the specified name. The second input "
"parameter is the desired target height. The optional double "
"specifies the duration of the motion. If the optional bool is set to true "
"the target up vector for camera is set based on the target node. Either of "
"the optional parameters can be left out."
},
{
"goToGeo",
&pathnavigation::luascriptfunctions::goToGeo,
{},
"string, double, double, double [, bool, double]",
"Move the camera to the globe with the name given by the input string. "
"The next three input parameters are latitude, longitude and altitude. "
"The optional double specifies the duration of the motion. If the optional "
"bool is set to true the target up vector for camera is set based on the "
"target node. Either of the optional parameters can be left out."
},
{
"generatePath",
&pathnavigation::luascriptfunctions::generatePath,
{},
"table",
"Generate the path as described by the lua table input argument. "
},
{
"getPathPositions",
&pathnavigation::luascriptfunctions::getPathPositions,
{},
"number",
"FOR DEBUG. Sample positions along the path. The input argument is the "
"number of samples per path segment. "
},
{
"getPathOrientations",
&pathnavigation::luascriptfunctions::getPathOrientations,
{},
"number",
"FOR DEBUG. Sample orientations along the path. The input argument is the "
"number of samples per path segment. "
},
{
"getPathViewDirections",
&pathnavigation::luascriptfunctions::getPathViewDirections,
{},
"number",
"FOR DEBUG. Sample view directions along the path. The input argument is "
"the number of samples per path segment. "
},
{
"getControlPoints",
&pathnavigation::luascriptfunctions::getControlPoints,
{},
"",
"FOR DEBUG. Get control point positions from all pathsegments"
}
};
return res;
}
void AutoNavigationModule::internalInitialize(const ghoul::Dictionary&) {
global::callback::preSync->emplace_back([this]() {
_pathNavigationHandler.updateCamera(global::windowDelegate->deltaTime());
});
}
} // namespace openspace
@@ -1,53 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___AUTONAVIGATION_MODULE___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___AUTONAVIGATION_MODULE___H__
#include <openspace/util/openspacemodule.h>
#include <modules/autonavigation/pathnavigationhandler.h>
namespace openspace {
class AutoNavigationModule : public OpenSpaceModule {
public:
constexpr static const char* Name = "AutoNavigation";
AutoNavigationModule();
virtual ~AutoNavigationModule() = default;
pathnavigation::PathNavigationHandler& PathNavigationHandler();
scripting::LuaLibrary luaLibrary() const override;
private:
void internalInitialize(const ghoul::Dictionary&) override;
pathnavigation::PathNavigationHandler _pathNavigationHandler;
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___AUTONAVIGATION_MODULE___H__
@@ -1,421 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/globebrowsingmodule.h>
#include <modules/globebrowsing/src/renderableglobe.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/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 {
constexpr const char* _loggerCat = "PathNavigation";
constexpr const double Epsilon = 1e-12;
} // namespace
namespace openspace::pathnavigation::luascriptfunctions {
int isFlying(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::isFlying");
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
bool hasFinished = module->PathNavigationHandler().hasFinished();
ghoul::lua::push(L, !hasFinished);
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
int continuePath(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::continuePath");
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().continuePath();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int pausePath(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::pausePath");
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().pausePath();
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");
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().abortPath();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
// All the goTo function has the same two optional input parameters at the end. The
// purpose of this function is to handle these input parameters and add the result
// to the dictionary specifying the instruction for a camera path.
int handleOptionalGoToParameters(lua_State* L, const int startLocation,
const int nArguments,
ghoul::Dictionary& resultInstruction)
{
const bool firstIsNumber = (lua_isnumber(L, startLocation) != 0);
const bool firstIsBool = (lua_isboolean(L, startLocation) != 0);
if (!(firstIsNumber || firstIsBool)) {
const char* msg = lua_pushfstring(
L,
"%s or %s expected, got %s",
lua_typename(L, LUA_TNUMBER),
lua_typename(L, LUA_TBOOLEAN),
luaL_typename(L, -1)
);
return ghoul::lua::luaError(
L, fmt::format("bad argument #{} ({})", startLocation, msg)
);
}
int location = startLocation;
if (firstIsBool) {
const bool useUpFromTarget = (lua_toboolean(L, location) == 1);
resultInstruction.setValue("UseTargetUpDirection", useUpFromTarget);
if (nArguments > startLocation) {
location++;
}
}
if (firstIsNumber || nArguments > startLocation) {
double duration = ghoul::lua::value<double>(L, location);
if (duration <= Epsilon) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, "Duration must be larger than zero.");
}
resultInstruction.setValue("Duration", duration);
}
return 0;
}
int goTo(lua_State* L) {
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "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);
}
using namespace std::string_literals;
ghoul::Dictionary insDict;
insDict.setValue("Type", "Node"s);
insDict.setValue("Target", nodeIdentifier);
if (nArguments > 1) {
int result = handleOptionalGoToParameters(L, 2, nArguments, insDict);
if (result != 0) {
return result; // An error occurred
}
}
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().createPath(insDict);
if (module->PathNavigationHandler().hasCurrentPath()) {
module->PathNavigationHandler().startPath();
}
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int goToHeight(lua_State* L) {
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight");
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);
}
double height = ghoul::lua::value<double>(L, 2);
using namespace std::string_literals;
ghoul::Dictionary insDict;
insDict.setValue("Type", "Node"s);
insDict.setValue("Target", nodeIdentifier);
insDict.setValue("Height", height);
if (nArguments > 2) {
int result = handleOptionalGoToParameters(L, 3, nArguments, insDict);
if (result != 0) {
return result; // An error occurred
}
}
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().createPath(insDict);
if (module->PathNavigationHandler().hasCurrentPath()) {
module->PathNavigationHandler().startPath();
}
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
// @TODO (emmbr 2020-11-06) Ideally, this module shouldn't depend on things from
// Globebrowsing, but we want it for an istallation. Later on, move this functionality
// somewhere else. Maybe combine with the existing "goToGeo" in globebrowsing?
int goToGeo(lua_State* L) {
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 4, 6 }, "lua::goToGeo");
const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
const SceneGraphNode* n = sceneGraphNode(nodeIdentifier);
if (!n) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, "Unknown globe name: " + nodeIdentifier);
}
const double latitude = ghoul::lua::value<double>(L, 2);
const double longitude = ghoul::lua::value<double>(L, 3);
const double altitude = ghoul::lua::value<double>(L, 4);
using RenderableGlobe = openspace::globebrowsing::RenderableGlobe;
const RenderableGlobe* globe = dynamic_cast<const RenderableGlobe*>(n->renderable());
if (!globe) {
return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe");
}
// Compute the relative position based on the input values
glm::dvec3 positionModelCoords = global::moduleEngine->module<GlobeBrowsingModule>()
->cartesianCoordinatesFromGeo(
*globe,
latitude,
longitude,
altitude
);
using namespace std::string_literals;
ghoul::Dictionary insDict;
insDict.setValue("Type", "Node"s);
insDict.setValue("Target", nodeIdentifier);
insDict.setValue("Position", positionModelCoords);
if (nArguments > 4) {
int result = handleOptionalGoToParameters(L, 5, nArguments, insDict);
if (result != 0) {
return result; // An error occurred
}
}
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().createPath(insDict);
if (module->PathNavigationHandler().hasCurrentPath()) {
module->PathNavigationHandler().startPath();
}
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);
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
module->PathNavigationHandler().createPath(dictionary);
if (module->PathNavigationHandler().hasCurrentPath()) {
module->PathNavigationHandler().startPath();
}
lua_settop(L, 0);
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) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::getPathPositions");
const int pointsPerSegment = (int)ghoul::lua::value<lua_Number>(L, 1);
// Get sample positions from the current curve
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
PathNavigationHandler& handler = module->PathNavigationHandler();
std::vector<glm::dvec3> points = handler.curvePositions(pointsPerSegment);
// Push the points to the Lua stack:
lua_settop(L, 0);
const auto pushVector = [](lua_State* L, const glm::dvec3& v) {
lua_newtable(L);
ghoul::lua::push(L, 1, v.x);
lua_rawset(L, -3);
ghoul::lua::push(L, 2, v.y);
lua_rawset(L, -3);
ghoul::lua::push(L, 3, v.z);
lua_rawset(L, -3);
};
lua_newtable(L);
for (int i = 0; i < points.size(); ++i) {
ghoul::lua::push(L, i+1);
pushVector(L, points[i]);
lua_rawset(L, -3);
}
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
// TODO: remove when not needed
// Created for debugging. Access info for rendereable path
int getPathOrientations(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::getPathPositions");
const int pointsPerSegment = (int)ghoul::lua::value<lua_Number>(L, 1);
// Get sample positions from the current curve
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
PathNavigationHandler& handler = module->PathNavigationHandler();
std::vector<glm::dquat> orientations = handler.curveOrientations(pointsPerSegment);
// Push the rotation to the Lua stack:
lua_settop(L, 0);
const auto pushVector = [](lua_State* L, const glm::dquat& v) {
lua_newtable(L);
ghoul::lua::push(L, 1, v.w);
lua_rawset(L, -4);
ghoul::lua::push(L, 2, v.x);
lua_rawset(L, -4);
ghoul::lua::push(L, 3, v.y);
lua_rawset(L, -4);
ghoul::lua::push(L, 4, v.z);
lua_rawset(L, -4);
};
lua_newtable(L);
for (int i = 0; i < orientations.size(); ++i) {
ghoul::lua::push(L, i + 1);
pushVector(L, orientations[i]);
lua_rawset(L, -4);
}
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
// TODO: remove when not needed
// Created for debugging. Access info for rendereable path
int getPathViewDirections(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::getPathViewDirections");
const int pointsPerSegment = (int)ghoul::lua::value<lua_Number>(L, 1);
// Get sample positions from the current curve
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
PathNavigationHandler& handler = module->PathNavigationHandler();
std::vector<glm::dvec3> viewDirections = handler.curveViewDirections(pointsPerSegment);
// Push the points to the Lua stack:
lua_settop(L, 0);
const auto pushVector = [](lua_State* L, const glm::dvec3& v) {
lua_newtable(L);
ghoul::lua::push(L, 1, v.x);
lua_rawset(L, -3);
ghoul::lua::push(L, 2, v.y);
lua_rawset(L, -3);
ghoul::lua::push(L, 3, v.z);
lua_rawset(L, -3);
};
// Push the rotation to the Lua stack:
lua_newtable(L);
for (int i = 0; i < viewDirections.size(); ++i) {
ghoul::lua::push(L, i + 1);
pushVector(L, viewDirections[i]);
lua_rawset(L, -3);
}
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
// TODO: remove when not needed
// Created for debugging. Access info for rendering of control points
int getControlPoints(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getControlPoints");
// Get sample positions from the current curve
AutoNavigationModule* module = global::moduleEngine->module<AutoNavigationModule>();
PathNavigationHandler& handler = module->PathNavigationHandler();
std::vector<glm::dvec3> points = handler.controlPoints();
// Push the points to the Lua stack:
lua_settop(L, 0);
const auto pushVector = [](lua_State* L, const glm::dvec3& v) {
lua_newtable(L);
ghoul::lua::push(L, 1, v.x);
lua_rawset(L, -3);
ghoul::lua::push(L, 2, v.y);
lua_rawset(L, -3);
ghoul::lua::push(L, 3, v.z);
lua_rawset(L, -3);
};
lua_newtable(L);
for (int i = 0; i < points.size(); ++i) {
ghoul::lua::push(L, i+1);
pushVector(L, points[i]);
lua_rawset(L, -3);
}
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
} // namespace openspace::pathnavigation::luascriptfunctions
@@ -1,190 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/curves/avoidcollisioncurve.h>
#include <modules/autonavigation/autonavigationmodule.h>
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/waypoint.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
namespace {
constexpr const char* _loggerCat = "AvoidCollisionCurve";
constexpr const double CloseToNodeThresholdFactor = 5.0;
constexpr const double AvoidCollisionDistanceFactor = 3.0;
constexpr const double CollisionBufferSizeFactor = 1.0;
constexpr const int MaxAvoidCollisionSteps = 10;
} // namespace
namespace openspace::pathnavigation {
AvoidCollisionCurve::AvoidCollisionCurve(const Waypoint& start, const Waypoint& end) {
auto module = global::moduleEngine->module<AutoNavigationModule>();
_relevantNodes = module->PathNavigationHandler().relevantNodes();
const glm::dvec3 startNodeCenter = start.node()->worldPosition();
const glm::dvec3 endNodeCenter = end.node()->worldPosition();
const double startNodeRadius = start.validBoundingSphere;
const double endNodeRadius = end.validBoundingSphere;
const glm::dvec3 startViewDir = start.rotation() * glm::dvec3(0.0, 0.0, -1.0);
// Add control points for a catmull-rom spline, first and last will not be intersected
_points.push_back(start.position());
_points.push_back(start.position());
// Add an extra point to first go backwards if starting close to planet
glm::dvec3 nodeToStart = start.position() - startNodeCenter;
double distanceToStartNode = glm::length(nodeToStart);
if (distanceToStartNode < CloseToNodeThresholdFactor * startNodeRadius) {
double distance = startNodeRadius;
glm::dvec3 newPos = start.position() + distance * glm::normalize(nodeToStart);
_points.push_back(newPos);
}
// Add point for moving out if the end state is in opposite direction
glm::dvec3 startToEnd = end.position() - start.position();
double cosAngleToTarget = glm::dot(normalize(-startViewDir), normalize(startToEnd));
bool targetInOppositeDirection = cosAngleToTarget > 0.7;
if (targetInOppositeDirection) {
const glm::dquat midleRot = glm::slerp(start.rotation(), end.rotation(), 0.5);
const glm::dvec3 middleViewDir = midleRot * glm::dvec3(0.0, 0.0, -1.0);
const double stepOutDistance = 0.4 * glm::length(startToEnd);
glm::dvec3 newPos = start.position() + 0.2 * startToEnd -
stepOutDistance * glm::normalize(middleViewDir);
_points.push_back(newPos);
}
// Add an extra point to approach target
const glm::dvec3 nodeToEnd = end.position() - endNodeCenter;
const double distanceToEndNode = glm::length(nodeToEnd);
if (distanceToEndNode < CloseToNodeThresholdFactor * endNodeRadius) {
double distance = endNodeRadius;
glm::dvec3 newPos = end.position() + distance * glm::normalize(nodeToEnd);
_points.push_back(newPos);
}
_points.push_back(end.position());
_points.push_back(end.position());
// Create extra points to avoid collision
removeCollisions();
initializeParameterData();
}
// Try to reduce the risk of collision by approximating the curve with linear segments.
// If a collision happens, create a new point for the path to go through, in an attempt to
// avoid that collision
void AvoidCollisionCurve::removeCollisions(int step) {
if (step > MaxAvoidCollisionSteps) {
return;
}
const int nSegments = static_cast<int>( _points.size() - 3);
for (int i = 0; i < nSegments; ++i) {
const glm::dvec3 lineStart = _points[i + 1];
const glm::dvec3 lineEnd = _points[i + 2];
for (SceneGraphNode* node : _relevantNodes) {
// Do collision check in relative coordinates, to avoid huge numbers
const glm::dmat4 modelTransform = node->modelTransform();
glm::dvec3 p1 = glm::inverse(modelTransform) * glm::dvec4(lineStart, 1.0);
glm::dvec3 p2 = glm::inverse(modelTransform) * glm::dvec4(lineEnd, 1.0);
// Sphere to check for collision
double radius = node->boundingSphere();
glm::dvec3 center = glm::dvec3(0.0, 0.0, 0.0);
// Add a buffer to avoid passing too close to the node.
// Dont't add it if any point is inside the buffer
double buffer = CollisionBufferSizeFactor * node->boundingSphere();
bool p1IsInside = helpers::isPointInsideSphere(p1, center, radius + buffer);
bool p2IsInside = helpers::isPointInsideSphere(p2, center, radius + buffer);
if (!p1IsInside && !p2IsInside) {
radius += buffer;
}
glm::dvec3 intersectionPointModelCoords;
bool collision = helpers::lineSphereIntersection(
p1,
p2,
center,
radius,
intersectionPointModelCoords
);
if (collision) {
glm::dvec3 collisionPoint = modelTransform *
glm::dvec4(intersectionPointModelCoords, 1.0);
// before collision response, make sure none of the points are inside the node
bool isStartInsideNode = helpers::isPointInsideSphere(p1, center, radius);
bool isEndInsideNode = helpers::isPointInsideSphere(p2, center, radius);
if (isStartInsideNode || isEndInsideNode) {
LWARNING(fmt::format(
"Something went wrong! "
"At least one point in the path is inside node: {}",
node->identifier()
));
break;
}
// To avoid collision, take a step in an orhtogonal direction of the
// collision point and add a new point
const glm::dvec3 lineDirection = glm::normalize(lineEnd - lineStart);
const glm::dvec3 nodeCenter = node->worldPosition();
const glm::dvec3 collisionPointToCenter = nodeCenter - collisionPoint;
const glm::dvec3 parallell = glm::proj(collisionPointToCenter, lineDirection);
const glm::dvec3 orthogonal = collisionPointToCenter - parallell;
const double avoidCollisionDistance = AvoidCollisionDistanceFactor * radius;
glm::dvec3 extraKnot = collisionPoint -
avoidCollisionDistance * glm::normalize(orthogonal);
_points.insert(_points.begin() + i + 2, extraKnot);
step++;
removeCollisions(step);
break;
}
}
}
}
} // namespace openspace::pathnavigation
@@ -1,46 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___AVOIDCOLLISIONCURVE___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___AVOIDCOLLISIONCURVE___H__
#include <modules/autonavigation/pathcurve.h>
namespace openspace::pathnavigation {
struct WayPoint;
class AvoidCollisionCurve : public PathCurve {
public:
AvoidCollisionCurve(const Waypoint& start, const Waypoint& end);
private:
void removeCollisions(int step = 0);
std::vector<SceneGraphNode*> _relevantNodes;
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___AVOIDCOLLISIONCURVE___H__
@@ -1,104 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/curves/zoomoutoverviewcurve.h>
#include <modules/autonavigation/autonavigationmodule.h>
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/waypoint.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
namespace {
constexpr const char* _loggerCat = "ZoomOutOverviewCurve";
} // namespace
namespace openspace::pathnavigation {
// Go far out to get a view of both tagets, aimed to match lookAt orientation
ZoomOutOverviewCurve::ZoomOutOverviewCurve(const Waypoint& start, const Waypoint& end) {
const double startNodeRadius = start.validBoundingSphere;
const double endNodeRadius = end.validBoundingSphere;
const double endTangentsLengthFactor = 2.0;
const double startTangentLength = endTangentsLengthFactor * startNodeRadius;
const double endTangentLength = endTangentsLengthFactor * endNodeRadius;
const glm::dvec3 startNodePos = start.node()->worldPosition();
const glm::dvec3 endNodePos = end.node()->worldPosition();
const glm::dvec3 startTangentDir = normalize(start.position() - startNodePos);
const glm::dvec3 endTangentDir = normalize(end.position() - endNodePos);
// Start by going outwards
_points.push_back(start.position());
_points.push_back(start.position());
_points.push_back(start.position() + startTangentLength * startTangentDir);
// Zoom out
if (start.nodeIdentifier != end.nodeIdentifier) {
const glm::dvec3 n1 = startTangentDir;
const glm::dvec3 n2 = endTangentDir;
// Decide the step direction for the "overview point" based on the directions
// at the start and end of the path, to try to get a nice curve shape
glm::dvec3 goodStepDirection;
if (glm::dot(n1, n2) < 0.0) {
// Facing in different directions => step in direction of the cross product
goodStepDirection = glm::normalize(glm::cross(-n1, n2));
}
else {
goodStepDirection = glm::normalize(n1 + n2);
}
// Find a direction that is orthogonal to the line between the start and end position
const glm::dvec3 startPosToEndPos = end.position() - start.position();
const glm::dvec3 outwardStepVector =
0.5 * glm::length(startPosToEndPos) * goodStepDirection;
const glm::dvec3 projectedVec = glm::proj(outwardStepVector, startPosToEndPos);
const glm::dvec3 orthogonalComponent = outwardStepVector - projectedVec;
const glm::dvec3 stepDirection = glm::normalize(orthogonalComponent);
// Step half-way along the line between the position and then orthogonally
const glm::dvec3 extraKnot = start.position() + 0.5 * startPosToEndPos
+ 1.5 * glm::length(startPosToEndPos) * stepDirection;
_points.push_back(extraKnot);
}
// Closing in on end node
_points.push_back(end.position() + endTangentLength * endTangentDir);
_points.push_back(end.position());
_points.push_back(end.position());
initializeParameterData();
}
} // namespace openspace::pathnavigation
@@ -1,41 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___ZOOMOUTOVERVIEWCURVE___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___ZOOMOUTOVERVIEWCURVE___H__
#include <modules/autonavigation/pathcurve.h>
namespace openspace::pathnavigation {
struct WayPoint;
class ZoomOutOverviewCurve : public PathCurve {
public:
ZoomOutOverviewCurve(const Waypoint& start, const Waypoint& end);
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___ZOOMOUTOVERVIEWCURVE___H__
-294
View File
@@ -1,294 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/helperfunctions.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/easing.h>
namespace {
constexpr const char* _loggerCat = "Helpers";
const double Epsilon = 1E-7;
} // namespace
namespace openspace::pathnavigation::helpers {
// Shift and scale to a subinterval [start,end]
double shiftAndScale(double t, double start, double end) {
ghoul_assert(0.0 < start && start < end&& end < 1.0,
"Values must be 0.0 < start < end < 1.0!");
double tScaled = t / (end - start) - start;
return std::max(0.0, std::min(tScaled, 1.0));
}
glm::dquat lookAtQuaternion(glm::dvec3 eye, glm::dvec3 center, glm::dvec3 up) {
glm::dmat4 lookAtMat = glm::lookAt(eye, center, up);
return glm::normalize(glm::inverse(glm::quat_cast(lookAtMat)));
}
glm::dvec3 viewDirection(const glm::dquat& q) {
return glm::normalize(q * glm::dvec3(0.0, 0.0, -1.0));
};
/*
* Calculate the intersection of a line and a sphere
* The line segment is defined from p1 to p2
* The sphere is of radius r and centered at sc
* There are potentially two points of intersection given by
* p = p1 + mu1 (p2 - p1)
* p = p1 + mu2 (p2 - p1)
* Source: http://paulbourke.net/geometry/circlesphere/raysphere.c
*/
bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 sc,
double r, glm::dvec3& intersectionPoint)
{
long double a, b, c;
glm::dvec3 dp = p2 - p1;
a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;
b = 2 * (dp.x * (p1.x - sc.x) + dp.y * (p1.y - sc.y) + dp.z * (p1.z - sc.z));
c = sc.x * sc.x + sc.y * sc.y + sc.z * sc.z;
c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
c -= 2 * (sc.x * p1.x + sc.y * p1.y + sc.z * p1.z);
c -= r * r;
long double intersectionTest = b * b - 4.0 * a * c;
// no intersection
if (std::abs(a) < Epsilon || intersectionTest < 0.0) {
return false;
}
else {
// only care about the first intersection point if we have two
const double t = (-b - std::sqrt(intersectionTest)) / (2.0 *a);
if (t <= Epsilon || t >= abs(1.0 - Epsilon)) return false;
intersectionPoint = p1 + t * dp;
return true;
}
}
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r) {
const glm::dvec3 v = c - p;
const long double squaredDistance = v.x * v.x + v.y * v.y + v.z * v.z;
const long double squaredRadius = r * r;
return (squaredDistance <= squaredRadius);
}
double simpsonsRule(double t0, double t1, int n, std::function<double(double)> f) {
const double h = (t1 - t0) / static_cast<double>(n);
const double endpoints = f(t0) + f(t1);
double times4 = 0.0;
double times2 = 0.0;
// weight 4
for (int i = 1; i < n; i += 2) {
double t = t0 + i * h;
times4 += f(t);
}
// weight 2
for (int i = 2; i < n; i += 2) {
double t = t0 + i * h;
times2 += f(t);
}
return (h / 3) * (endpoints + 4 * times4 + 2 * times2);
}
/*
* Approximate area under a function using 5-point Gaussian quadrature
* https://en.wikipedia.org/wiki/Gaussian_quadrature
*/
double fivePointGaussianQuadrature(double t0, double t1,
std::function<double(double)> f)
{
struct GaussLengendreCoefficient {
double abscissa; // xi
double weight; // wi
};
static constexpr GaussLengendreCoefficient coefficients[] = {
{ 0.0, 0.5688889 },
{ -0.5384693, 0.47862867 },
{ 0.5384693, 0.47862867 },
{ -0.90617985, 0.23692688 },
{ 0.90617985, 0.23692688 }
};
const double a = t0;
const double b = t1;
double sum = 0.0;
for (auto coefficient : coefficients) {
// change of interval to [a, b] from [-1, 1] (also 0.5 * (b - a) below)
double const t = 0.5 * ((b - a) * coefficient.abscissa + (b + a));
sum += f(t) * coefficient.weight;
}
return 0.5 * (b - a) * sum;
}
} // helpers
namespace openspace::pathnavigation::interpolation {
glm::dquat easedSlerp(const glm::dquat q1, const glm::dquat q2, double t) {
double tScaled = helpers::shiftAndScale(t, 0.1, 0.9);
tScaled = ghoul::sineEaseInOut(tScaled);
return glm::slerp(q1, q2, tScaled);
}
// Based on implementation by Mika Rantanen
// https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
glm::dvec3 catmullRom(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3, double alpha)
{
glm::dvec3 m01, m02, m23, m13;
double t01 = pow(glm::distance(p0, p1), alpha);
double t12 = pow(glm::distance(p1, p2), alpha);
double t23 = pow(glm::distance(p2, p3), alpha);
m01 = (t01 > Epsilon) ? (p1 - p0) / t01 : glm::dvec3{};
m23 = (t23 > Epsilon) ? (p3 - p2) / t23 : glm::dvec3{};
m02 = (t01 + t12 > Epsilon) ? (p2 - p0) / (t01 + t12) : glm::dvec3{};
m13 = (t12 + t23 > Epsilon) ? (p3 - p1) / (t12 + t23) : glm::dvec3{};
glm::dvec3 m1 = p2 - p1 + t12 * (m01 - m02);
glm::dvec3 m2 = p2 - p1 + t12 * (m23 - m13);
glm::dvec3 a = 2.0 * (p1 - p2) + m1 + m2;
glm::dvec3 b = -3.0 * (p1 - p2) - m1 - m1 - m2;
glm::dvec3 c = m1;
glm::dvec3 d = p1;
return a * t * t * t
+ b * t * t
+ c * t
+ d;
}
glm::dvec3 cubicBezier(double t, const glm::dvec3& cp1, const glm::dvec3& cp2,
const glm::dvec3& cp3, const glm::dvec3& cp4)
{
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
double a = 1.0 - t;
return cp1 * a * a * a
+ cp2 * t * a * a * 3.0
+ cp3 * t * t * a * 3.0
+ cp4 * t * t * t;
}
glm::dvec3 linear(double t, const glm::dvec3 &cp1, const glm::dvec3 &cp2) {
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
return cp1 * (1.0 - t) + cp2 * t;
}
glm::dvec3 hermite(double t, const glm::dvec3 &p1, const glm::dvec3 &p2,
const glm::dvec3 &tangent1, const glm::dvec3 &tangent2)
{
ghoul_assert(t >= 0 && t <= 1.0, "Interpolation variable out of range [0, 1]");
if (t <= 0.0) return p1;
if (t >= 1.0) return p2;
const double t2 = t * t;
const double t3 = t2 * t;
// calculate basis functions
double const a0 = (2.0 * t3) - (3.0 * t2) + 1.0;
double const a1 = (-2.0 * t3) + (3.0 * t2);
double const b0 = t3 - (2.0 * t2) + t;
double const b1 = t3 - t2;
return (a0 * p1) + (a1 * p2) + (b0 * tangent1) + (b1 * tangent2);
}
// uniform if tKnots are equally spaced, or else non uniform
glm::dvec3 piecewiseCubicBezier(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots)
{
ghoul_assert(
points.size() > 4,
"Minimum of four control points needed for interpolation"
);
ghoul_assert(
(points.size() - 1) % 3 == 0,
"A vector containing 3n + 1 control points must be provided"
);
int nrSegments = (points.size() - 1) / 3;
ghoul_assert(
rSegments == (tKnots.size() - 1),
"Number of interval times must match number of segments"
);
if (t <= 0.0) return points.front();
if (t >= 1.0) return points.back();
// compute current segment index
std::vector<double>::const_iterator segmentEndIt =
std::lower_bound(tKnots.begin(), tKnots.end(), t);
unsigned int segmentIdx = (segmentEndIt - 1) - tKnots.begin();
double segmentStart = tKnots[segmentIdx];
double segmentDuration = (tKnots[segmentIdx + 1] - tKnots[segmentIdx]);
double tScaled = (t - segmentStart) / segmentDuration;
unsigned int idx = segmentIdx * 3;
// Interpolate using De Casteljau's algorithm
return interpolation::cubicBezier(
tScaled,
points[idx],
points[idx + 1],
points[idx + 2],
points[idx + 3]
);
}
glm::dvec3 piecewiseLinear(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots)
{
ghoul_assert(points.size() == tKnots.size(), "Must have equal number of points and times!");
ghoul_assert(points.size() > 2, "Minimum of two control points needed for interpolation!");
size_t nrSegments = points.size() - 1;
if (t <= 0.0) return points.front();
if (t >= 1.0) return points.back();
// compute current segment index
std::vector<double>::const_iterator segmentEndIt =
std::lower_bound(tKnots.begin(), tKnots.end(), t);
unsigned int idx = (segmentEndIt - 1) - tKnots.begin();
double segmentStart = tKnots[idx];
double segmentDuration = (tKnots[idx + 1] - tKnots[idx]);
double tScaled = (t - segmentStart) / segmentDuration;
return interpolation::linear(tScaled, points[idx], points[idx + 1]);
}
} // interpolation
-83
View File
@@ -1,83 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___HELPERFUNCTIONS___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___HELPERFUNCTIONS___H__
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
namespace openspace::pathnavigation::helpers {
// Make interpolator parameter t [0,1] progress only inside a subinterval
double shiftAndScale(double t, double newStart, double newEnd);
glm::dquat lookAtQuaternion(glm::dvec3 eye, glm::dvec3 center, glm::dvec3 up);
glm::dvec3 viewDirection(const glm::dquat& q);
bool lineSphereIntersection(glm::dvec3 linePoint1, glm::dvec3 linePoint2,
glm::dvec3 sphereCenter, double spehereRadius, glm::dvec3& intersectionPoint);
bool isPointInsideSphere(const glm::dvec3& p, const glm::dvec3& c, double r);
double simpsonsRule(double t0, double t1, int n, std::function<double(double)> f);
double fivePointGaussianQuadrature(double t0, double t1,
std::function<double(double)> f);
} // namespace openspace::pathnavigation::helpers
namespace openspace::pathnavigation::interpolation {
glm::dquat easedSlerp(const glm::dquat q1, const glm::dquat q2, double t);
// TODO: make all these into template functions.
// Alternatively, add cubicBezier interpolation in ghoul and only use
// ghoul's interpolator methods
// Centripetal version alpha = 0, uniform for alpha = 0.5 and chordal for alpha = 1
glm::dvec3 catmullRom(double t, const glm::dvec3& p0, const glm::dvec3& p1,
const glm::dvec3& p2, const glm::dvec3& p3, double alpha = 0.5);
glm::dvec3 cubicBezier(double t, const glm::dvec3& cp1, const glm::dvec3& cp2,
const glm::dvec3& cp3, const glm::dvec3& cp4);
glm::dvec3 linear(double t, const glm::dvec3& cp1, const glm::dvec3& cp2);
glm::dvec3 hermite(double t, const glm::dvec3 &cp1, const glm::dvec3 &cp2,
const glm::dvec3 &tangent1, const glm::dvec3 &tangent2);
glm::dvec3 piecewiseCubicBezier(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots);
glm::dvec3 piecewiseLinear(double t, const std::vector<glm::dvec3>& points,
const std::vector<double>& tKnots);
} // namespace openspace::pathnavigation::interpolation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___HELPERFUNCTIONS___H__
-5
View File
@@ -1,5 +0,0 @@
set(DEFAULT_MODULE ON)
set(OPENSPACE_DEPENDENCIES
#add possible other modules that this module depends upon
)
-222
View File
@@ -1,222 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/path.h>
#include <modules/autonavigation/autonavigationmodule.h>
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/pathcurve.h>
#include <modules/autonavigation/curves/avoidcollisioncurve.h>
#include <modules/autonavigation/curves/zoomoutoverviewcurve.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/interpolator.h>
namespace {
constexpr const char* _loggerCat = "Path";
} // namespace
namespace openspace::pathnavigation {
Path::Path(Waypoint start, Waypoint end, CurveType type,
std::optional<double> duration)
: _start(start), _end(end), _curveType(type)
{
switch (_curveType) {
case CurveType::AvoidCollision:
_curve = std::make_unique<AvoidCollisionCurve>(_start, _end);
break;
case CurveType::Linear:
_curve = std::make_unique<LinearCurve>(_start, _end);
break;
case CurveType::ZoomOutOverview:
_curve = std::make_unique<ZoomOutOverviewCurve>(_start, _end);
break;
default:
LERROR("Could not create curve. Type does not exist!");
throw ghoul::MissingCaseException();
}
const auto defaultDuration = [](double pathlength) {
auto module = global::moduleEngine->module<AutoNavigationModule>();
const double speedScale = module->PathNavigationHandler().speedScale();
return std::log(pathlength) / speedScale;
};
_duration = duration.value_or(defaultDuration(pathLength()));
// Compute speed factor to match the generated path length and duration, by
// traversing the path and computing how much faster/slower it should be
const int nSteps = 500;
const double dt = (_duration / nSteps) > 0.01 ? (_duration / nSteps) : 0.01;
while (!hasReachedEnd()) {
traversePath(dt);
}
_speedFactorFromDuration = _progressedTime / _duration;
// Reset playback variables
_traveledDistance = 0.0;
_progressedTime = 0.0;
}
Waypoint Path::startPoint() const { return _start; }
Waypoint Path::endPoint() const { return _end; }
double Path::duration() const { return _duration; }
double Path::pathLength() const { return _curve->length(); }
std::vector<glm::dvec3> Path::controlPoints() const {
return _curve->points();
}
CameraPose Path::traversePath(double dt) {
const double speed = _speedFactorFromDuration * speedAlongPath(_traveledDistance);
const double displacement = dt * speed;
_progressedTime += dt;
_traveledDistance += displacement;
return interpolatedPose(_traveledDistance);
}
std::string Path::currentAnchor() const {
bool pastHalfway = (_traveledDistance / pathLength()) > 0.5;
return (pastHalfway) ? _end.nodeIdentifier : _start.nodeIdentifier;
}
bool Path::hasReachedEnd() const {
return (_traveledDistance / pathLength()) >= 1.0;
}
CameraPose Path::interpolatedPose(double distance) const {
const double relativeDistance = distance / pathLength();
CameraPose cs;
cs.position = _curve->positionAt(relativeDistance);
cs.rotation = interpolateRotation(relativeDistance);
return cs;
}
glm::dquat Path::interpolateRotation(double t) const {
switch (_curveType) {
case CurveType::AvoidCollision:
case CurveType::Linear:
return interpolation::easedSlerp(_start.rotation(), _end.rotation(), t);
case CurveType::ZoomOutOverview:
{
const double t1 = 0.2;
const double t2 = 0.8;
const glm::dvec3 startPos = _curve->positionAt(0.0);
const glm::dvec3 endPos = _curve->positionAt(1.0);
const glm::dvec3 startNodePos = _start.node()->worldPosition();
const glm::dvec3 endNodePos = _end.node()->worldPosition();
glm::dvec3 lookAtPos;
if (t < t1) {
// Compute a position in front of the camera at the start orientation
const double inFrontDistance = glm::distance(startPos, startNodePos);
const glm::dvec3 viewDir = helpers::viewDirection(_start.rotation());
const glm::dvec3 inFrontOfStart = startPos + inFrontDistance * viewDir;
const double tScaled = ghoul::cubicEaseInOut(t / t1);
lookAtPos =
ghoul::interpolateLinear(tScaled, inFrontOfStart, startNodePos);
}
else if (t <= t2) {
const double tScaled = ghoul::cubicEaseInOut((t - t1) / (t2 - t1));
lookAtPos = ghoul::interpolateLinear(tScaled, startNodePos, endNodePos);
}
else if (t > t2) {
// Compute a position in front of the camera at the end orientation
const double inFrontDistance = glm::distance(endPos, endNodePos);
const glm::dvec3 viewDir = helpers::viewDirection(_end.rotation());
const glm::dvec3 inFrontOfEnd = endPos + inFrontDistance * viewDir;
const double tScaled = ghoul::cubicEaseInOut((t - t2) / (1.0 - t2));
lookAtPos = ghoul::interpolateLinear(tScaled, endNodePos, inFrontOfEnd);
}
// Handle up vector separately
glm::dvec3 startUp = _start.rotation() * glm::dvec3(0.0, 1.0, 0.0);
glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
double tUp = helpers::shiftAndScale(t, t1, t2);
tUp = ghoul::sineEaseInOut(tUp);
glm::dvec3 up = ghoul::interpolateLinear(tUp, startUp, endUp);
return helpers::lookAtQuaternion(_curve->positionAt(t), lookAtPos, up);
}
default:
throw ghoul::MissingCaseException();
}
}
double Path::speedAlongPath(double traveledDistance) {
const glm::dvec3 endNodePos = _end.node()->worldPosition();
const glm::dvec3 startNodePos = _start.node()->worldPosition();
const CameraPose prevPose = interpolatedPose(traveledDistance);
const double distanceToEndNode = glm::distance(prevPose.position, endNodePos);
const double distanceToStartNode = glm::distance(prevPose.position, startNodePos);
// Decide which is the closest node
SceneGraphNode* closestNode = _start.node();
glm::dvec3 closestPos = startNodePos;
if (distanceToEndNode < distanceToStartNode) {
closestPos = endNodePos;
closestNode = _end.node();
}
const double distanceToClosestNode = glm::distance(closestPos, prevPose.position);
double speed = distanceToClosestNode;
// Dampen speed in beginning of path
const double startUpDistance = 2.0 * _start.node()->boundingSphere();
if (traveledDistance < startUpDistance) {
speed *= traveledDistance / startUpDistance + 0.01;
}
// Dampen speed in end of path
// Note: this leads to problems when the full length of the path is really big
const double closeUpDistance = 2.0 * _end.node()->boundingSphere();
if (traveledDistance > (pathLength() - closeUpDistance)) {
const double remainingDistance = pathLength() - traveledDistance;
speed *= remainingDistance / closeUpDistance + 0.01;
}
// TODO: also dampen speed based on curvature, or make sure the curve has a rounder shape
// TODO: check for when path is shorter than the starUpDistance or closeUpDistance variables
return speed;
}
} // namespace openspace::pathnavigation
-79
View File
@@ -1,79 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___PATH___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___PATH___H__
#include <modules/autonavigation/pathcurve.h>
#include <modules/autonavigation/waypoint.h>
namespace openspace::pathnavigation {
class Path {
public:
enum CurveType {
AvoidCollision,
Linear,
ZoomOutOverview
};
Path(Waypoint start, Waypoint end, CurveType type,
std::optional<double> duration = std::nullopt);
// TODO: add a constructor that takes an instruction and curve type?
Waypoint startPoint() const;
Waypoint endPoint() const;
double duration() const;
double pathLength() const;
std::vector<glm::dvec3> controlPoints() const;
CameraPose traversePath(double dt);
std::string currentAnchor() const;
bool hasReachedEnd() const;
CameraPose interpolatedPose(double distance) const;
private:
glm::dquat interpolateRotation(double u) const;
double speedAlongPath(double traveledDistance);
Waypoint _start;
Waypoint _end;
double _duration;
CurveType _curveType;
std::unique_ptr<PathCurve> _curve;
double _speedFactorFromDuration = 1.0;
// Playback variables
double _traveledDistance = 0.0;
double _progressedTime = 0.0; // Time since playback started
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___PATH___H__
-251
View File
@@ -1,251 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/pathcreator.h>
#include <modules/autonavigation/autonavigationmodule.h>
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/waypoint.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <openspace/util/camera.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* _loggerCat = "PathCreator";
constexpr const float Epsilon = 1e-5f;
// TODO: where should this documentation be?
struct [[codegen::Dictionary(PathInstruction)]] Parameters {
enum class Type {
Node,
NavigationState
};
Type type;
// The desired duration traversing the specified path segment should take
std::optional<float> duration;
// (Node): The target node of the camera path. Not optional for 'Node' instructions
std::optional<std::string> target;
// (Node): An optional position in relation to the target node, in model
// coordinates (meters)
std::optional<glm::dvec3> position;
// (Node): An optional height in relation to the target node, in meters
std::optional<double> height;
// (Node): If true, the up direction of the node is taken into account when
// computing the wayopoint for this instruction
std::optional<bool> useTargetUpDirection;
// (NavigationState): A navigation state that will be the target
// 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 "pathinstruction_codegen.cpp"
} // namespace
namespace openspace::pathnavigation {
using NavigationState = interaction::NavigationHandler::NavigationState;
Path PathCreator::createPath(const ghoul::Dictionary& dictionary,
Path::CurveType curveType)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
std::optional<float> duration = p.duration;
bool hasStart = p.startState.has_value();
Waypoint startPoint = hasStart ? Waypoint(p.startState.value()) : waypointFromCamera();
// TODO: also handle curve type here
std::vector<Waypoint> waypoints;
switch (p.type) {
case Parameters::Type::NavigationState: {
if (!p.navigationState.has_value()) {
throw ghoul::RuntimeError("A navigation state is required");
}
const NavigationState navigationState =
NavigationState(p.navigationState.value());
waypoints = { Waypoint(navigationState) };
break;
}
case Parameters::Type::Node: {
if (!p.target.has_value()) {
throw ghoul::RuntimeError("A target node is required");
}
const std::string nodeIdentifier = p.target.value();
const SceneGraphNode* targetNode = sceneGraphNode(nodeIdentifier);
if (!targetNode) {
throw ghoul::RuntimeError(fmt::format(
"Could not find target node '{}'", nodeIdentifier
));
}
NodeInfo info {
nodeIdentifier,
p.position,
p.height,
p.useTargetUpDirection.value_or(false)
};
waypoints = { computeDefaultWaypoint(info, startPoint) };
break;
}
default: {
LERROR(fmt::format("Uknown instruciton type: {}", p.type));
throw ghoul::MissingCaseException();
}
}
// TODO: allow for an instruction to represent a list of waypoints
Waypoint waypointToAdd = waypoints[0];
return Path(startPoint, waypointToAdd, curveType, duration);
}
Waypoint PathCreator::waypointFromCamera() {
Camera* camera = global::navigationHandler->camera();
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 PathCreator::computeDefaultWaypoint(const NodeInfo& info,
const Waypoint& startPoint)
{
const SceneGraphNode* targetNode = sceneGraphNode(info.identifier);
if (!targetNode) {
LERROR(fmt::format("Could not find target node '{}'", info.identifier));
return Waypoint();
}
glm::dvec3 targetPos;
if (info.position.has_value()) {
// Note that the anchor and reference frame is our targetnode.
// The position in instruction is given is relative coordinates
targetPos = targetNode->worldPosition() +
targetNode->worldRotationMatrix() * info.position.value();
}
else {
const glm::dvec3 nodePos = targetNode->worldPosition();
const glm::dvec3 sunPos = glm::dvec3(0.0, 0.0, 0.0);
const SceneGraphNode* closeNode = findNodeNearTarget(targetNode);
glm::dvec3 stepDirection;
if (closeNode) {
// If the node is close to another node in the scene, make sure that the
// position is set to minimize risk of collision
stepDirection = glm::normalize(nodePos - closeNode->worldPosition());
}
else if (glm::length(sunPos - nodePos) < Epsilon) {
// Special case for when the target is the Sun. Assumption: want an overview of
// the solar system, and not stay in the orbital plane
stepDirection = glm::dvec3(0.0, 0.0, 1.0);
}
else {
// Go to a point that is being lit up by the sun, slightly offsetted from sun
// direction
const glm::dvec3 prevPos = startPoint.position();
const glm::dvec3 targetToPrev = prevPos - nodePos;
const glm::dvec3 targetToSun = sunPos - nodePos;
constexpr const float defaultPositionOffsetAngle = -30.f; // degrees
constexpr const float angle = glm::radians(defaultPositionOffsetAngle);
const glm::dvec3 axis = glm::normalize(glm::cross(targetToPrev, targetToSun));
const glm::dquat offsetRotation = angleAxis(static_cast<double>(angle), axis);
stepDirection = glm::normalize(offsetRotation * targetToSun);
}
const double radius = Waypoint::findValidBoundingSphere(targetNode);
const double defaultHeight = 2.0 * radius;
const double height = info.height.value_or(defaultHeight);
targetPos = nodePos + stepDirection * (radius + height);
}
glm::dvec3 up = global::navigationHandler->camera()->lookUpVectorWorldSpace();
if (info.useTargetUpDirection) {
// @TODO (emmbr 2020-11-17) For now, this is hardcoded to look good for Earth,
// which is where it matters the most. A better solution would be to make each
// sgn aware of its own 'up' and query
up = targetNode->worldRotationMatrix() * glm::dvec3(0.0, 0.0, 1.0);
}
const glm::dvec3 lookAtPos = targetNode->worldPosition();
const glm::dquat targetRot = helpers::lookAtQuaternion(targetPos, lookAtPos, up);
return Waypoint(targetPos, targetRot, info.identifier);
}
SceneGraphNode* PathCreator::findNodeNearTarget(const SceneGraphNode* node) {
auto module = global::moduleEngine->module<AutoNavigationModule>();
const std::vector<SceneGraphNode*>& relevantNodes =
module->PathNavigationHandler().relevantNodes();
for (SceneGraphNode* n : relevantNodes) {
if (n->identifier() == node->identifier()) {
continue;
}
constexpr const float proximityRadiusFactor = 3.f;
const float bs = static_cast<float>(n->boundingSphere());
const float proximityRadius = proximityRadiusFactor * bs;
const glm::dvec3 posInModelCoords =
glm::inverse(n->modelTransform()) * glm::dvec4(node->worldPosition(), 1.0);
bool isClose = helpers::isPointInsideSphere(
posInModelCoords,
glm::dvec3(0.0, 0.0, 0.0),
proximityRadius
);
if (isClose) {
return n;
}
}
return nullptr;
}
} // namespace openspace::pathnavigation
-59
View File
@@ -1,59 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___PATHCREATOR___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___PATHCREATOR___H__
#include <modules/autonavigation/path.h>
namespace openspace::pathnavigation {
struct Waypoint;
class PathCreator {
public:
// Create a path from a dictionary containing the instruction
static Path createPath(const ghoul::Dictionary& dictionary,
Path::CurveType curveType);
private:
struct NodeInfo {
std::string identifier;
std::optional<glm::dvec3> position;
std::optional<double> height;
bool useTargetUpDirection;
};
static Waypoint waypointFromCamera();
static Waypoint computeDefaultWaypoint(const NodeInfo& info,
const Waypoint& startPoint);
// Test if the node lies within a given proximity radius of any relevant node
// in the scene
static SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node);
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___PATHCREATOR___H__
-235
View File
@@ -1,235 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/pathcurve.h>
#include <modules/autonavigation/helperfunctions.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>
#include <algorithm>
#include <vector>
namespace {
constexpr const char* _loggerCat = "PathCurve";
constexpr const int NrSamplesPerSegment = 100;
} // namespace
namespace openspace::pathnavigation {
PathCurve::~PathCurve() {}
const double PathCurve::length() const {
return _totalLength;
}
glm::dvec3 PathCurve::positionAt(double relativeDistance) {
const double u = curveParameter(relativeDistance * _totalLength);
return interpolate(u);
}
// Compute the curve parameter from an arc length value, using a combination of
// Newton's method and bisection. Source:
// https://www.geometrictools.com/Documentation/MovingAlongCurveSpecifiedSpeed.pdf
// Input s is a length value, in the range [0, _totalLength]
// Returns curve parameter in range [0, 1]
double PathCurve::curveParameter(double s) {
if (s <= 0.0) return 0.0;
if (s >= _totalLength) return 1.0;
unsigned int segmentIndex = 1;
while (s > _lengthSums[segmentIndex]) {
segmentIndex++;
}
const int startIndex = (segmentIndex - 1) * NrSamplesPerSegment;
const int endIndex = segmentIndex * NrSamplesPerSegment + 1;
const double segmentS = s - _lengthSums[segmentIndex - 1];
const double uMin = _curveParameterSteps[segmentIndex - 1];
const double uMax = _curveParameterSteps[segmentIndex];
// Use samples to find an initial guess for Newton's method
// Find first sample with s larger than input s
auto sampleIterator = std::upper_bound(
_parameterSamples.begin() + startIndex,
_parameterSamples.begin() + endIndex,
ParameterPair{ 0.0 , s }, // 0.0 is a dummy value for u
[](ParameterPair lhs, ParameterPair rhs) {
return lhs.s < rhs.s;
}
);
const ParameterPair& sample = *sampleIterator;
const ParameterPair& prevSample = *(sampleIterator - 1);
const double uPrev = prevSample.u;
const double sPrev = prevSample.s;
const double slope = (sample.u - uPrev) / (sample.s - sPrev);
double u = uPrev + slope * (s - sPrev);
constexpr const int maxIterations = 50;
// Initialize root bounding limits for bisection
double lower = uMin;
double upper = uMax;
for (int i = 0; i < maxIterations; ++i) {
double F = arcLength(uMin, u) - segmentS;
// The error we tolerate, in meters. Note that distances are very large
constexpr const double tolerance = 0.005;
if (std::abs(F) <= tolerance) {
return u;
}
// Generate a candidate for Newton's method
double dfdu = approximatedDerivative(u); // > 0
double uCandidate = u - F / dfdu;
// Update root-bounding interval and test candidate
if (F > 0) { // => candidate < u <= upper
upper = u;
u = (uCandidate <= lower) ? (upper + lower) / 2.0 : uCandidate;
}
else { // F < 0 => lower <= u < candidate
lower = u;
u = (uCandidate >= upper) ? (upper + lower) / 2.0 : uCandidate;
}
}
// No root was found based on the number of iterations and tolerance. However, it is
// safe to report the last computed u value, since it is within the segment interval
return u;
}
std::vector<glm::dvec3> PathCurve::points() {
return _points;
}
void PathCurve::initializeParameterData() {
_nSegments = static_cast<int>(_points.size() - 3);
ghoul_assert(_nSegments > 0, "Cannot have a curve with zero segments!");
_curveParameterSteps.clear();
_lengthSums.clear();
_parameterSamples.clear();
// Evenly space out parameter intervals
_curveParameterSteps.reserve(_nSegments + 1);
const double dt = 1.0 / _nSegments;
_curveParameterSteps.push_back(0.0);
for (unsigned int i = 1; i < _nSegments; i++) {
_curveParameterSteps.push_back(dt * i);
}
_curveParameterSteps.push_back(1.0);
// Arc lengths
_lengthSums.reserve(_nSegments + 1);
_lengthSums.push_back(0.0);
for (unsigned int i = 1; i <= _nSegments; i++) {
double u = _curveParameterSteps[i];
double uPrev = _curveParameterSteps[i - 1];
double length = arcLength(uPrev, u);
_lengthSums.push_back(_lengthSums[i - 1] + length);
}
_totalLength = _lengthSums.back();
// Compute a map of arc lengths s and curve parameters u, for reparameterization
_parameterSamples.reserve(NrSamplesPerSegment * _nSegments + 1);
const double uStep = 1.0 / (_nSegments * NrSamplesPerSegment);
for (unsigned int i = 0; i < _nSegments; i++) {
double uStart = _curveParameterSteps[i];
double sStart = _lengthSums[i];
for (int j = 0; j < NrSamplesPerSegment; ++j) {
double u = uStart + j * uStep;
double s = sStart + arcLength(uStart, u);
_parameterSamples.push_back({ u, s });
}
}
_parameterSamples.push_back({ 1.0, _totalLength });
}
double PathCurve::approximatedDerivative(double u, double h) {
if (u <= h) {
return (1.0 / h) * glm::length(interpolate(0.0 + h) - interpolate(0.0));
}
if (u >= 1.0 - h) {
return (1.0 / h) * glm::length(interpolate(1.0) - interpolate(1.0 - h));
}
return (0.5 / h) * glm::length(interpolate(u + h) - interpolate(u - h));
}
double PathCurve::arcLength(double limit) {
return arcLength(0.0, limit);
}
double PathCurve::arcLength(double lowerLimit, double upperLimit) {
return helpers::fivePointGaussianQuadrature(
lowerLimit,
upperLimit,
[this](double u) { return approximatedDerivative(u); }
);
}
glm::dvec3 PathCurve::interpolate(double u) {
ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable out of range [0, 1]");
if (u < 0.0) {
return _points[1];
}
if (u > 1.0) {
return *(_points.end() - 2);
}
std::vector<double>::iterator segmentEndIt =
std::lower_bound(_curveParameterSteps.begin(), _curveParameterSteps.end(), u);
const int index =
static_cast<int>((segmentEndIt - 1) - _curveParameterSteps.begin());
double segmentStart = _curveParameterSteps[index];
double segmentDuration = (_curveParameterSteps[index + 1] - segmentStart);
double uSegment = (u - segmentStart) / segmentDuration;
return interpolation::catmullRom(
uSegment,
_points[index],
_points[index + 1],
_points[index + 2],
_points[index + 3],
1.0 // chordal version
);
}
LinearCurve::LinearCurve(const Waypoint& start, const Waypoint& end) {
_points.push_back(start.position());
_points.push_back(start.position());
_points.push_back(end.position());
_points.push_back(end.position());
initializeParameterData();
}
} // namespace openspace::pathnavigation
-80
View File
@@ -1,80 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___PATHCURVE___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___PATHCURVE___H__
#include <modules/autonavigation/waypoint.h>
#include <ghoul/glm.h>
#include <vector>
namespace openspace::pathnavigation {
class PathCurve {
public:
virtual ~PathCurve() = 0;
const double length() const;
glm::dvec3 positionAt(double relativeDistance);
// Compute curve parameter u that matches the input arc length s
double curveParameter(double s);
virtual glm::dvec3 interpolate(double u);
std::vector<glm::dvec3> points();
protected:
// Precompute information related to the pspline parameters, that are
// needed for arc length reparameterization. Must be called after
// control point creation
void initializeParameterData();
double approximatedDerivative(double u, double h = 0.0001);
double arcLength(double limit = 1.0);
double arcLength(double lowerLimit, double upperLimit);
std::vector<glm::dvec3> _points;
unsigned int _nSegments;
std::vector<double> _curveParameterSteps; // per segment
std::vector<double> _lengthSums; // per segment
double _totalLength;
struct ParameterPair {
double u; // curve parameter
double s; // arc length parameter
};
std::vector<ParameterPair> _parameterSamples;
};
class LinearCurve : public PathCurve {
public:
LinearCurve(const Waypoint& start, const Waypoint& end);
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___PATHCURVE___H__
@@ -1,503 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/pathnavigationhandler.h>
#include <modules/autonavigation/helperfunctions.h>
#include <modules/autonavigation/pathcreator.h>
#include <openspace/engine/globals.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
#include <openspace/util/timemanager.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/quaternion.hpp>
#include <vector>
namespace {
constexpr const char* _loggerCat = "PathNavigationHandler";
constexpr openspace::properties::Property::PropertyInfo DefaultCurveOptionInfo = {
"DefaultCurveOption",
"Default Curve Option",
"The defualt curve type chosen when generating a path, if none is specified"
// TODO: right now there is no way to specify a type for a single path
};
constexpr openspace::properties::Property::PropertyInfo IncludeRollInfo = {
"IncludeRoll",
"Include Roll",
"If disabled, roll is removed from the interpolation of camera orientation"
};
constexpr openspace::properties::Property::PropertyInfo StopBehaviorInfo = {
"StopBehavior",
"Stop Behavior",
"A camera motion behavior that is applied when no path is being played"
};
constexpr openspace::properties::Property::PropertyInfo
ApplyStopBehaviorWhenIdleInfo =
{
"ApplyStopBehaviorWhenIdle",
"Apply Stop Behavior When Idle",
"If enabled, the camera is controlled using the set stop behavior when "
"no path is playing"
};
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
"SpeedScale",
"Speed Scale",
"Scale factor that affects the default speed for a camera path."
};
constexpr openspace::properties::Property::PropertyInfo OrbitSpeedFactorInfo = {
"OrbitSpeedFactor",
"Orbit Speed Factor",
"Controls the speed of the orbiting around an anchor."
};
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo = {
"MinimalValidBoundingSphere",
"Minimal Valid Bounding Sphere",
"The minimal allowed value for a bounding sphere, in meters. Used for "
"computation of target positions and path generation, to avoid issues when "
"there is no bounding sphere."
};
constexpr openspace::properties::Property::PropertyInfo RelevantNodeTagsInfo = {
"RelevantNodeTags",
"Relevant Node Tags",
"List of tags for the nodes that are relevant for path creation, for example "
"when avoiding collisions."
};
} // namespace
namespace openspace::pathnavigation {
PathNavigationHandler::PathNavigationHandler()
: properties::PropertyOwner({ "PathNavigationHandler" })
, _defaultCurveOption(
DefaultCurveOptionInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _includeRoll(IncludeRollInfo, false)
, _stopBehavior(
StopBehaviorInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _applyStopBehaviorWhenIdle(ApplyStopBehaviorWhenIdleInfo, false)
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
, _orbitSpeedFactor(OrbitSpeedFactorInfo, 0.5, 0.0, 20.0)
, _minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
, _relevantNodeTags(RelevantNodeTagsInfo)
{
_defaultCurveOption.addOptions({
{ Path::CurveType::AvoidCollision, "AvoidCollision" },
{ Path::CurveType::Linear, "Linear" },
{ Path::CurveType::ZoomOutOverview, "ZoomOutOverview"}
});
addProperty(_defaultCurveOption);
addProperty(_includeRoll);
addProperty(_speedScale);
addProperty(_applyStopBehaviorWhenIdle);
// Must be listed in the same order as in enum definition
_stopBehavior.addOptions({
{ StopBehavior::None, "None" },
{ StopBehavior::Orbit, "Orbit" }
});
_stopBehavior = StopBehavior::None;
addProperty(_stopBehavior);
addProperty(_orbitSpeedFactor);
addProperty(_minValidBoundingSphere);
_relevantNodeTags = std::vector<std::string>{
"planet_solarSystem",
"moon_solarSystem"
};;
_relevantNodeTags.onChange([this]() { findRelevantNodes(); });
addProperty(_relevantNodeTags);
}
PathNavigationHandler::~PathNavigationHandler() {} // NOLINT
Camera* PathNavigationHandler::camera() const {
return global::navigationHandler->camera();
}
const SceneGraphNode* PathNavigationHandler::anchor() const {
return global::navigationHandler->anchorNode();
}
double PathNavigationHandler::speedScale() const {
return _speedScale;
}
bool PathNavigationHandler::hasCurrentPath() const {
return _currentPath != nullptr;
}
bool PathNavigationHandler::hasFinished() const {
if (!hasCurrentPath()) {
return true;
}
return _currentPath->hasReachedEnd();
}
void PathNavigationHandler::updateCamera(double deltaTime) {
ghoul_assert(camera() != nullptr, "Camera must not be nullptr");
if (!_isPlaying) {
// TODO: Determine how this should work
if (hasFinished() && _applyStopBehaviorWhenIdle) {
applyStopBehavior(deltaTime);
}
return;
}
if (!hasCurrentPath()) {
return;
}
// If for some reason the time is no longer paused, pause it again
if (!global::timeManager->isPaused()) {
global::timeManager->setPause(true);
LINFO("Cannot start simulation time during camera motion");
}
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.
std::string currentAnchor = anchor()->identifier();
if (currentAnchor != newAnchor) {
global::navigationHandler->orbitalNavigator().setAnchorNode(newAnchor);
}
if (!_includeRoll) {
removeRollRotation(newPose, deltaTime);
}
camera()->setPositionVec3(newPose.position);
camera()->setRotation(newPose.rotation);
if (_currentPath->hasReachedEnd()) {
LINFO("Reached end of path");
_isPlaying = false;
return;
}
}
void PathNavigationHandler::createPath(const ghoul::Dictionary& dictionary) {
// TODO: Improve how curve types are handled
const int curveType = _defaultCurveOption;
clearPath();
try {
_currentPath = std::make_unique<Path>(
PathCreator::createPath(dictionary, Path::CurveType(curveType))
);
}
catch (const ghoul::RuntimeError& e) {
LERROR("Could not create path");
return;
}
LINFO("Successfully generated camera path");
}
void PathNavigationHandler::clearPath() {
LINFO("Clearing path...");
_currentPath = nullptr;
}
void PathNavigationHandler::startPath() {
if (!hasCurrentPath()) {
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");
return;
}
LINFO("Starting path...");
_isPlaying = true;
}
void PathNavigationHandler::abortPath() {
if (!_isPlaying) {
LWARNING("No camera path is playing");
return;
}
_isPlaying = false;
LINFO("Aborted camera path");
}
void PathNavigationHandler::pausePath() {
if (hasFinished()) {
LERROR("No path to pause (path is empty or has finished).");
return;
}
if (!_isPlaying) {
LERROR("Cannot pause a path that is not playing");
return;
}
LINFO("Path paused");
_isPlaying = false;
}
void PathNavigationHandler::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...");
_isPlaying = true;
}
// Created for debugging
std::vector<glm::dvec3> PathNavigationHandler::curvePositions(int nSteps) const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dvec3> positions;
const double du = 1.0 / nSteps;
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;
}
// Created for debugging
std::vector<glm::dquat> PathNavigationHandler::curveOrientations(int nSteps) const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dquat> orientations;
const double du = 1.0 / nSteps;
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;
}
// Created for debugging
std::vector<glm::dvec3> PathNavigationHandler::curveViewDirections(int nSteps) const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dvec3> viewDirections;
const double du = 1.0 / nSteps;
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;
}
// Created for debugging
std::vector<glm::dvec3> PathNavigationHandler::controlPoints() const {
if (!hasCurrentPath()) {
LERROR("There is no current path to sample points from.");
return {};
}
std::vector<glm::dvec3> points;
const std::vector<glm::dvec3> curvePoints = _currentPath->controlPoints();
points.insert(points.end(), curvePoints.begin(), curvePoints.end());
return points;
}
double PathNavigationHandler::minValidBoundingSphere() const {
return _minValidBoundingSphere;
}
const std::vector<SceneGraphNode*>& PathNavigationHandler::relevantNodes() {
if (!_hasInitializedRelevantNodes) {
findRelevantNodes();
_hasInitializedRelevantNodes = true;
}
return _relevantNodes;
}
void PathNavigationHandler::findRelevantNodes() {
const std::vector<SceneGraphNode*>& allNodes =
global::renderEngine->scene()->allSceneGraphNodes();
const std::vector<std::string> relevantTags = _relevantNodeTags;
if (allNodes.empty() || relevantTags.empty()) {
_relevantNodes = std::vector<SceneGraphNode*>();
return;
}
auto isRelevant = [&](const SceneGraphNode* node) {
const std::vector<std::string> tags = node->tags();
auto result = std::find_first_of(
relevantTags.begin(),
relevantTags.end(),
tags.begin(),
tags.end()
);
// does not match any tags => not interesting
if (result == relevantTags.end()) {
return false;
}
return node->renderable() && (node->boundingSphere() > 0.0);
};
std::vector<SceneGraphNode*> resultingNodes;
std::copy_if(
allNodes.begin(),
allNodes.end(),
std::back_inserter(resultingNodes),
isRelevant
);
_relevantNodes = resultingNodes;
}
void PathNavigationHandler::removeRollRotation(CameraPose& pose, double deltaTime) {
const glm::dvec3 anchorPos = anchor()->worldPosition();
const glm::dvec3 cameraDir = glm::normalize(
pose.rotation * Camera::ViewDirectionCameraSpace
);
const double anchorToPosDistance = glm::distance(anchorPos, pose.position);
const double notTooCloseDistance = deltaTime * anchorToPosDistance;
glm::dvec3 lookAtPos = pose.position + notTooCloseDistance * cameraDir;
glm::dquat rollFreeRotation = helpers::lookAtQuaternion(
pose.position,
lookAtPos,
camera()->lookUpVectorWorldSpace()
);
pose.rotation = rollFreeRotation;
}
void PathNavigationHandler::applyStopBehavior(double deltaTime) {
switch (_stopBehavior) {
case StopBehavior::None:
// Do nothing
break;
case StopBehavior::Orbit:
orbitAnchorNode(deltaTime);
break;
default:
throw ghoul::MissingCaseException();
}
}
void PathNavigationHandler::orbitAnchorNode(double deltaTime) {
ghoul_assert(anchor() != nullptr, "Node to orbit must be set!");
const glm::dvec3 prevPosition = camera()->positionVec3();
const glm::dquat prevRotation = camera()->rotationQuaternion();
const glm::dvec3 nodeCenter = anchor()->worldPosition();
const double speedFactor = 0.1 * _orbitSpeedFactor;
// Compute orbit speed based on factor and distance to surface
const double orbitRadius = glm::distance(prevPosition, nodeCenter);
const double distanceToSurface = orbitRadius - anchor()->boundingSphere();
const double orbitSpeed = distanceToSurface * speedFactor;
// Compute a new position along the orbit
const glm::dvec3 up = camera()->lookUpVectorWorldSpace();
const glm::dquat lookAtNodeRotation = helpers::lookAtQuaternion(
prevPosition,
nodeCenter,
up
);
const glm::dvec3 targetForward = lookAtNodeRotation * glm::dvec3(0.0, 0.0, -1.0);
const glm::dvec3 rightOrbitTangent = glm::normalize(glm::cross(targetForward, up));
glm::dvec3 newPosition = prevPosition + orbitSpeed * deltaTime * rightOrbitTangent;
// Adjust for numerical error - make sure we stay at the same height
const glm::dvec3 nodeToNewPos = newPosition - nodeCenter;
const double targetHeight = glm::distance(prevPosition, nodeCenter);
const double heightDiff = glm::length(nodeToNewPos) - targetHeight;
newPosition -= heightDiff * glm::normalize(nodeToNewPos);
// Rotate along the orbit, but keep relative orientation with regards to the anchor
const glm::dquat localRotation = glm::inverse(lookAtNodeRotation) * prevRotation;
const glm::dquat newLookAtRotation =
helpers::lookAtQuaternion(newPosition, nodeCenter, up);
const glm::dquat newRotation = newLookAtRotation * localRotation;
camera()->setPositionVec3(newPosition);
camera()->setRotation(newRotation);
}
} // namespace openspace::pathnavigation
@@ -1,107 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___PATHNAVIGATIONHANDLER___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___PATHNAVIGATIONHANDLER___H__
#include <openspace/properties/propertyowner.h>
#include <modules/autonavigation/path.h>
#include <openspace/properties/list/stringlistproperty.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <ghoul/glm.h>
namespace openspace {
class Camera;
} // namespace openspace
namespace openspace::pathnavigation {
class PathNavigationHandler : public properties::PropertyOwner {
public:
enum StopBehavior {
None = 0,
Orbit
};
PathNavigationHandler();
~PathNavigationHandler();
// Accessors
Camera* camera() const;
const SceneGraphNode* anchor() const;
double speedScale() const;
bool hasCurrentPath() const;
bool hasFinished() const;
void updateCamera(double deltaTime);
void createPath(const ghoul::Dictionary& dictionary);
void clearPath();
void startPath();
void abortPath();
void pausePath();
void continuePath();
// TODO: remove functions for debugging
std::vector<glm::dvec3> curvePositions(int nSteps) const;
std::vector<glm::dquat> curveOrientations(int nSteps) const;
std::vector<glm::dvec3> curveViewDirections(int nSteps) const;
std::vector<glm::dvec3> controlPoints() const;
double minValidBoundingSphere() const;
const std::vector<SceneGraphNode*>& relevantNodes();
private:
void findRelevantNodes();
void removeRollRotation(CameraPose& pose, double deltaTime);
void applyStopBehavior(double deltaTime);
void orbitAnchorNode(double deltaTime);
std::unique_ptr<Path> _currentPath = nullptr;
bool _isPlaying = false;
properties::OptionProperty _defaultCurveOption;
properties::BoolProperty _includeRoll;
properties::FloatProperty _speedScale;
properties::FloatProperty _orbitSpeedFactor;
properties::BoolProperty _applyStopBehaviorWhenIdle;
properties::OptionProperty _stopBehavior;
properties::DoubleProperty _minValidBoundingSphere;
properties::StringListProperty _relevantNodeTags;
std::vector<SceneGraphNode*> _relevantNodes;
bool _hasInitializedRelevantNodes = false;
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___PATHNAVIGATIONHANDLER___H__
@@ -1,208 +0,0 @@
openspace.autonavigation.documentation = {
{
Name = "removeRenderedPath",
Arguments = "",
Documentation = "Remove the rendered path, if any."
},
{
Name = "renderPath",
Arguments = "int, [bool], [bool], [number]",
Documentation = "Render the currently active path, using linear segments. " ..
"The first argurment is the number of samples per path segment. " ..
"The optional second argument can be used to render the points of " ..
"the path as spheres, if set to true." ..
"The optional third argument will visualize camera orientation if set to true." ..
"The optional fourth input affects the size of the points and orientation lines."
},
{
Name = "removeControlPoints",
Arguments = "",
Documentation = "Remove the rendered control points, if any."
},
{
Name = "renderControlPoints",
Arguments = "[number]",
Documentation = "Test method for rendering the control points of the camera " ..
"path spline. The optional input is used to specify the radius of the points."
},
}
openspace.autonavigation.removeRenderedPath = function ()
local path_identifier = "Camera_Path"
if openspace.hasSceneGraphNode(path_identifier) then
openspace.removeSceneGraphNode(path_identifier)
end
end
openspace.autonavigation.renderPath = function (nrLinesPerSegment, renderPoints, renderOrientations, sphereRadius)
local path_identifier = "Camera_Path"
local label_point = "Point"
local label_line = "Line"
local lineColor = {1.0, 1.0, 0.0}
local lineWidth = 4
local sphereTexture = openspace.absPath("${MODULES}/autonavigation/textures/red.png")
local sphereSegments = 50
local label_orientation = "Orientation"
local orientationLineColor = {1.0, 0.0, 0.0}
local orientationLineWidth = 2
if (sphereRadius == nil) then
sphereRadius = 2000000 -- TODO: better default
end
local orientationLineLength = 30 * sphereRadius
if openspace.hasSceneGraphNode(path_identifier) then
openspace.removeSceneGraphNode(path_identifier)
end
local path = { Identifier = path_identifier }
openspace.addSceneGraphNode(path)
local points = openspace.autonavigation.getPathPositions(nrLinesPerSegment)
local viewDirections = openspace.autonavigation.getPathViewDirections(nrLinesPerSegment)
local nrPoints = 0
for _ in pairs(points) do
nrPoints = nrPoints + 1
end
-- points
for key, point in pairs(points) do
local node = {
Identifier = label_point .. key,
Transform = {
Translation = {
Type = "StaticTranslation",
Position = point
}
},
Parent = path_identifier
}
if renderPoints then
node.Renderable = {
Type = "RenderableSphere",
Enabled = true,
Segments = sphereSegments,
Size = sphereRadius,
Texture = sphereTexture,
Opacity = 1
}
end
openspace.addSceneGraphNode(node)
end
-- lines between points
for i = 1,(nrPoints-1) do
local node = {
Identifier = label_line .. i,
Renderable = {
Enabled = true,
Type = "RenderableNodeLine",
StartNode = label_point .. i,
EndNode = label_point .. (i+1),
Color = lineColor,
LineWidth = lineWidth,
Opacity = 0.5
},
Parent = path_identifier
}
openspace.addSceneGraphNode(node)
end
-- lines for view direction
if renderOrientations then
for key, point in pairs(points) do
local viewPos = {
tonumber(point[1]) + tonumber(viewDirections[key][1]) * orientationLineLength,
tonumber(point[2]) + tonumber(viewDirections[key][2]) * orientationLineLength,
tonumber(point[3]) + tonumber(viewDirections[key][3]) * orientationLineLength
}
local node = {
Identifier = label_orientation .. label_point .. key,
Transform = {
Translation = {
Type = "StaticTranslation",
Position = viewPos
}
},
Parent = path_identifier
}
openspace.addSceneGraphNode(node)
end
for i = 1,nrPoints do
local node = {
Identifier = label_orientation .. label_line .. i,
Renderable = {
Enabled = true,
Type = "RenderableNodeLine",
StartNode = label_point .. i,
EndNode = label_orientation .. label_point .. i,
Color = orientationLineColor,
LineWidth = orientationLineWidth,
Opacity = 1
},
Parent = path_identifier
}
openspace.addSceneGraphNode(node)
end
end
end
openspace.autonavigation.removeControlPoints = function ()
local base_identifier = "Path_Control_Points"
if openspace.hasSceneGraphNode(base_identifier) then
openspace.removeSceneGraphNode(base_identifier)
end
end
openspace.autonavigation.renderControlPoints = function (sphereRadius)
local base_identifier = "Path_Control_Points"
local label_point = "ControlPoint"
local sphereTexture = openspace.absPath("${MODULES}/autonavigation/textures/yellow.png")
local sphereSegments = 50
if (sphereRadius == nil) then
sphereRadius = 2000000 -- TODO: better default
end
if openspace.hasSceneGraphNode(base_identifier) then
openspace.removeSceneGraphNode(base_identifier)
end
local base = { Identifier = base_identifier}
openspace.addSceneGraphNode(base)
local points = openspace.autonavigation.getControlPoints()
for key, point in pairs(points) do
local node = {
Identifier = label_point .. key,
Transform = {
Translation = {
Type = "StaticTranslation",
Position = point
}
},
Renderable = {
Type = "RenderableSphere",
Enabled = true,
Segments = sphereSegments,
Size = sphereRadius,
Texture = sphereTexture,
Opacity = 1
},
Parent = base_identifier,
GUI = {
Name = "Control Point" .. key,
Path = "/Camera Paths Debug/",
}
}
openspace.addSceneGraphNode(node)
end
end
Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

-145
View File
@@ -1,145 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/autonavigation/waypoint.h>
#include <modules/autonavigation/autonavigationmodule.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* _loggerCat = "Waypoint";
} // namespace
namespace openspace::pathnavigation {
Waypoint::Waypoint(const glm::dvec3& pos, const glm::dquat& rot, const std::string& ref)
: nodeIdentifier(ref)
{
pose.position = pos;
pose.rotation = rot;
const SceneGraphNode* node = sceneGraphNode(nodeIdentifier);
if (!node) {
LERROR(fmt::format("Could not find node '{}'", nodeIdentifier));
return;
}
validBoundingSphere = findValidBoundingSphere(node);
}
Waypoint::Waypoint(const NavigationState& ns) {
// OBS! The following code to get the position and rotation is exactly the same as in
// NavigationHandler::applyNavigationState. Should probably be made into a function.
// TODO: make that function
const SceneGraphNode* referenceFrame = sceneGraphNode(ns.referenceFrame);
const SceneGraphNode* anchorNode = sceneGraphNode(ns.anchor);
if (!anchorNode) {
LERROR(fmt::format("Could not find node '{}' to target", ns.anchor));
return;
}
nodeIdentifier = ns.anchor;
validBoundingSphere = findValidBoundingSphere(anchorNode);
const glm::dvec3 anchorWorldPosition = anchorNode->worldPosition();
const glm::dmat3 referenceFrameTransform = referenceFrame->worldRotationMatrix();
pose.position = 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 - pose.position);
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));
pose.rotation = neutralCameraRotation * yawRotation * pitchRotation;
}
glm::dvec3 Waypoint::position() const {
return pose.position;
}
glm::dquat Waypoint::rotation() const {
return pose.rotation;
}
SceneGraphNode* Waypoint::node() const {
return sceneGraphNode(nodeIdentifier);
}
double Waypoint::findValidBoundingSphere(const SceneGraphNode* node) {
double bs = static_cast<double>(node->boundingSphere());
auto module = global::moduleEngine->module<AutoNavigationModule>();
const double minValidBoundingSphere =
module->PathNavigationHandler().minValidBoundingSphere();
if (bs < minValidBoundingSphere) {
// If the bs of the target is too small, try to find a good value in a child node.
// Only check the closest children, to avoid deep traversal in the scene graph.
// Also, the possibility to find a bounding sphere represents the visual size of
// the target well is higher for these nodes.
for (SceneGraphNode* child : node->children()) {
bs = static_cast<double>(child->boundingSphere());
if (bs > minValidBoundingSphere) {
LWARNING(fmt::format(
"The scene graph node '{}' has no, or a very small, bounding sphere. "
"Using bounding sphere of child node '{}' in computations.",
node->identifier(),
child->identifier()
));
return bs;
}
}
LWARNING(fmt::format(
"The scene graph node '{}' has no, or a very small, bounding sphere. Using "
"minimal value. This might lead to unexpected results.",
node->identifier())
);
bs = minValidBoundingSphere;
}
return bs;
}
} // namespace openspace::pathnavigation
-60
View File
@@ -1,60 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_AUTONAVIGATION___WAYPOINT___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___WAYPOINT___H__
#include <openspace/navigation/navigationhandler.h>
#include <ghoul/glm.h>
namespace openspace::pathnavigation {
struct CameraPose {
glm::dvec3 position;
glm::dquat rotation;
};
struct Waypoint {
using NavigationState = interaction::NavigationHandler::NavigationState;
// TODO: create waypoints from a dictionary and skip instructions?
Waypoint() = default;
Waypoint(const glm::dvec3& pos, const glm::dquat& rot, const std::string& ref);
Waypoint(const NavigationState& ns);
static double findValidBoundingSphere(const SceneGraphNode* node);
glm::dvec3 position() const;
glm::dquat rotation() const;
SceneGraphNode* node() const;
CameraPose pose;
std::string nodeIdentifier;
double validBoundingSphere = 0.0; // to be able to handle nodes with faulty bounding spheres
};
} // namespace openspace::pathnavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___WAYPOINT___H__