diff --git a/include/openspace/navigation/pathnavigator.h b/include/openspace/navigation/pathnavigator.h index b0d0b5cd64..87a191ef27 100644 --- a/include/openspace/navigation/pathnavigator.h +++ b/include/openspace/navigation/pathnavigator.h @@ -61,6 +61,7 @@ public: // Accessors Camera* camera() const; const SceneGraphNode* anchor() const; + const Path* currentPath() const; double speedScale() const; bool hasCurrentPath() const; @@ -75,12 +76,6 @@ public: void pausePath(); void continuePath(); - // TODO: remove functions for debugging - std::vector curvePositions(int nSteps) const; - std::vector curveOrientations(int nSteps) const; - std::vector curveViewDirections(int nSteps) const; - std::vector controlPoints() const; - double minValidBoundingSphere() const; const std::vector& relevantNodes(); diff --git a/modules/debugging/CMakeLists.txt b/modules/debugging/CMakeLists.txt index 74baa55988..37a3af3fe1 100644 --- a/modules/debugging/CMakeLists.txt +++ b/modules/debugging/CMakeLists.txt @@ -25,12 +25,15 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES + debuggingmodule.h rendering/renderabledebugplane.h rendering/debugrenderer.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES + debuggingmodule.cpp + debuggingmodule_lua.inl rendering/renderabledebugplane.cpp rendering/debugrenderer.cpp ) diff --git a/modules/debugging/debuggingmodule.cpp b/modules/debugging/debuggingmodule.cpp index d6b60e2439..82a0837914 100644 --- a/modules/debugging/debuggingmodule.cpp +++ b/modules/debugging/debuggingmodule.cpp @@ -27,10 +27,13 @@ #include #include #include +#include #include #include #include +#include "debuggingmodule_lua.inl" + namespace openspace { DebuggingModule::DebuggingModule() : OpenSpaceModule(Name) {} @@ -48,5 +51,48 @@ std::vector DebuggingModule::documentations() cons }; } +scripting::LuaLibrary DebuggingModule::luaLibrary() const { + scripting::LuaLibrary res; + res.name = "debugging"; + res.functions = { + { + "renderCameraPath", + &luascriptfunctions::renderCameraPath, + {}, + "[number, bool, number]", + "Render the current camera path from the path navigation system. The " + "first optional argument is the number of samples to take along the path " + "(defaults to 100). If a second optional argument is included and set to " + "true, a line indicating the camera view direction along the path will " + "also be rendered. This can be useful when debugging camera orientations. " + "Finally, the third optional argument can be used to set the length " + "(in meter) of the view direction lines" + }, + { + "removeRenderedCameraPath", + &luascriptfunctions::removeRenderedCameraPath, + {}, + "", + "Removes the rendered camera path, if there is one" + }, + { + "renderPathControlPoints", + &luascriptfunctions::renderPathControlPoints, + {}, + "[number]", + "Render the control points for the camera path spline as spheres. The " + "optional argument can be used to set the radius of the created spheres. " + }, + { + "removePathControlPoints", + &luascriptfunctions::removePathControlPoints, + {}, + "", + "Removes the rendered control points" + } + }; + + return res; +} } // namespace openspace diff --git a/modules/debugging/debuggingmodule.h b/modules/debugging/debuggingmodule.h index 4bc2056fc8..6a2e2f2fb0 100644 --- a/modules/debugging/debuggingmodule.h +++ b/modules/debugging/debuggingmodule.h @@ -37,6 +37,8 @@ public: std::vector documentations() const override; + scripting::LuaLibrary luaLibrary() const override; + protected: void internalInitialize(const ghoul::Dictionary&) override; }; diff --git a/modules/debugging/debuggingmodule_lua.inl b/modules/debugging/debuggingmodule_lua.inl new file mode 100644 index 0000000000..759e8bb437 --- /dev/null +++ b/modules/debugging/debuggingmodule_lua.inl @@ -0,0 +1,282 @@ +/***************************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include + +namespace { + constexpr const char RenderedPathIdentifier[] = "CurrentCameraPath"; + constexpr const char RenderedPointsIdentifier[] = "CurrentPathControlPoints"; + constexpr const char DebuggingGuiPath[] = "/Debugging"; + + constexpr const glm::vec3 PathColor = { 1.0, 1.0, 0.0 }; + constexpr const glm::vec3 OrientationLineColor = { 0.0, 1.0, 1.0 }; +} // namespace + +namespace openspace::luascriptfunctions { + +/** + * PathNavigation + * Renders the current camera path + */ +int renderCameraPath(lua_State* L) { + int nArguments = ghoul::lua::checkArgumentsAndThrow( + L, + { 0, 3 }, + "lua::renderCameraPath" + ); + + if (!global::navigationHandler->pathNavigator().hasCurrentPath()) { + LWARNINGC("Debugging: PathNavigation", "There is no current path to render"); + } + + const interaction::Path* currentPath = + global::navigationHandler->pathNavigator().currentPath(); + + const int nSteps = (nArguments > 0) ? ghoul::lua::value(L, 1) : 100; + bool renderDirections = (nArguments > 1) ? ghoul::lua::value(L, 2) : false; + + constexpr const double defaultLineLength = 6e7; + const double directionLineLength = + (nArguments > 2) ? ghoul::lua::value(L, 3) : defaultLineLength; + + // Parent node. Note that we only render one path at a time, so remove the previously + // rendered one, if any + std::string addParentScript = fmt::format( + "if openspace.hasSceneGraphNode('{0}') then " + "openspace.removeSceneGraphNode('{0}') " + "end " + "openspace.addSceneGraphNode( {{ Identifier = '{0}' }} )", + RenderedPathIdentifier + ); + + openspace::global::scriptEngine->queueScript( + addParentScript, + scripting::ScriptEngine::RemoteScripting::Yes + ); + + // Get the poses along the path + std::vector poses; + const double du = 1.0 / nSteps; + const double length = currentPath->pathLength(); + for (double u = 0.0; u < 1.0; u += du) { + const CameraPose p = currentPath->interpolatedPose(u * length); + poses.push_back(p); + } + poses.push_back(currentPath->endPoint().pose); + + // Create node lines between the positions + auto pointIdentifier = [](int i) { + return fmt::format("Point_{}", i); + }; + + auto addPoint = [pointIdentifier] (const std::string& id, glm::dvec3 p) { + const std::string pointNode = "{" + "Identifier = '" + id + "'," + "Parent = '" + RenderedPathIdentifier + "'," + "Transform = { " + "Translation = {" + "Type = 'StaticTranslation'," + "Position = " + ghoul::to_string(p) + "" + "}," + "}" + "}"; + + openspace::global::scriptEngine->queueScript( + fmt::format("openspace.addSceneGraphNode({})", pointNode), + scripting::ScriptEngine::RemoteScripting::Yes + ); + }; + + auto addLineBetweenPoints = [pointIdentifier] (const std::string& id1, + const std::string& id2, + const glm::vec3& color, + float lineWidth) + { + const std::string lineNode = "{" + "Identifier = '" + fmt::format("Line{}", id1) + "'," + "Parent = '" + RenderedPathIdentifier + "'," + "Renderable = {" + "Enabled = true," + "Type = 'RenderableNodeLine'," + "StartNode = '" + id1 + "'," + "EndNode = '" + id2 + "'," + "LineWidth = " + std::to_string(lineWidth) + "," + "Color = " + ghoul::to_string(color) + "" + "}" + "}"; + + openspace::global::scriptEngine->queueScript( + fmt::format("openspace.addSceneGraphNode({})", lineNode), + scripting::ScriptEngine::RemoteScripting::Yes + ); + }; + + auto addDirectionLine = [addPoint, addLineBetweenPoints, directionLineLength] + (const std::string& pointId, const CameraPose& p) + { + const glm::dvec3 dir = glm::normalize(p.rotation * glm::dvec3(0.0, 0.0, -1.0)); + const glm::dvec3 pointPosition = p.position + directionLineLength * dir; + const std::string id = fmt::format("{}_orientation", pointId); + + addPoint(id, pointPosition); + addLineBetweenPoints(id, pointId, OrientationLineColor, 2.f); + }; + + // Add first point separately so that we can create first line in for loop + addPoint(pointIdentifier(0), poses.front().position); + if (renderDirections) { + addDirectionLine(pointIdentifier(0), poses.front()); + } + + for (int i = 1; i < poses.size(); i++) { + addPoint(pointIdentifier(i), poses[i].position); + addLineBetweenPoints(pointIdentifier(i), pointIdentifier(i - 1), PathColor, 4.f); + + if (renderDirections) { + addDirectionLine(pointIdentifier(i), poses[i]); + } + } + + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + return 0; +} + +/** + * PathNavigation + * Removes the currently rendered camera path if there is one + */ +int removeRenderedCameraPath(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removeRenderedCameraPath"); + + openspace::global::scriptEngine->queueScript( + fmt::format("openspace.removeSceneGraphNode('{}') ", RenderedPathIdentifier), + scripting::ScriptEngine::RemoteScripting::Yes + ); + + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + return 0; +} + +/** + * PathNavigation + * Renders the control points of the current camera path + */ +int renderPathControlPoints(lua_State* L) { + int nArguments = ghoul::lua::checkArgumentsAndThrow( + L, + { 0, 1 }, + "lua::renderPathControlPoints" + ); + + if (!global::navigationHandler->pathNavigator().hasCurrentPath()) { + LWARNINGC( + "Debugging: PathNavigation", "There is no current path to sample points from" + ); + } + + const interaction::Path* currentPath = + global::navigationHandler->pathNavigator().currentPath(); + + const double radius = (nArguments > 0) ? ghoul::lua::value(L, 1) : 2000000; + + // Parent node. Note that we only render one set of points at a time, + // so remove any previously rendered ones + std::string addParentScript = fmt::format( + "if openspace.hasSceneGraphNode('{0}') then " + "openspace.removeSceneGraphNode('{0}') " + "end " + "openspace.addSceneGraphNode( {{ Identifier = '{0}' }} )", + RenderedPointsIdentifier + ); + + openspace::global::scriptEngine->queueScript( + addParentScript, + scripting::ScriptEngine::RemoteScripting::Yes + ); + + const std::vector points = currentPath->controlPoints(); + + const std::string guiPath = + fmt::format("{}/Camera Path Control Points", DebuggingGuiPath); + + const char * colorTexturePath = "openspace.absPath(" + "openspace.createSingleColorImage('point_color', { 0.0, 1.0, 0.0 })" + ")"; + + for (int i = 0; i < points.size(); i++) { + const std::string& node = "{" + "Identifier = 'ControlPoint_" + std::to_string(i) + "'," + "Parent = '" + RenderedPointsIdentifier + "'," + "Transform = { " + "Translation = {" + "Type = 'StaticTranslation'," + "Position = " + ghoul::to_string(points[i]) + "" + "}," + "}," + "Renderable = {" + "Type = 'RenderableSphere'," + "Enabled = true," + "Segments = 30," + "Size = " + std::to_string(radius) + "," + "Texture = " + colorTexturePath + "" + "}," + "GUI = {" + "Name = 'Control Point " + std::to_string(i) + "'," + "Path = '" + guiPath + "'" + "}" + "}"; + + openspace::global::scriptEngine->queueScript( + fmt::format("openspace.addSceneGraphNode({})", node), + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + return 0; +} + +/** + * PathNavigation + * Removes the rendered control points + */ +int removePathControlPoints(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removePathControlPoints"); + + openspace::global::scriptEngine->queueScript( + fmt::format("openspace.removeSceneGraphNode('{}') ", RenderedPointsIdentifier), + scripting::ScriptEngine::RemoteScripting::Yes + ); + + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + return 0; +} + +} // namespace openspace::luascriptfunctions + diff --git a/modules/debugging/rendering/debugrenderer.cpp b/modules/debugging/rendering/debugrenderer.cpp index 50721f9987..d604879e41 100644 --- a/modules/debugging/rendering/debugrenderer.cpp +++ b/modules/debugging/rendering/debugrenderer.cpp @@ -30,8 +30,6 @@ #include #include #include -//#include -//#include namespace { constexpr const char* _loggerCat = "DebugRenderer"; diff --git a/src/navigation/pathnavigator.cpp b/src/navigation/pathnavigator.cpp index eb462faea5..c4780ab1a1 100644 --- a/src/navigation/pathnavigator.cpp +++ b/src/navigation/pathnavigator.cpp @@ -163,6 +163,10 @@ const SceneGraphNode* PathNavigator::anchor() const { return global::navigationHandler->anchorNode(); } +const Path* PathNavigator::currentPath() const { + return _currentPath.get(); +} + double PathNavigator::speedScale() const { return _speedScale; } @@ -315,86 +319,6 @@ void PathNavigator::continuePath() { _isPlaying = true; } -// Created for debugging -std::vector PathNavigator::curvePositions(int nSteps) const { - if (!hasCurrentPath()) { - LERROR("There is no current path to sample points from."); - return {}; - } - - std::vector 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 PathNavigator::curveOrientations(int nSteps) const { - if (!hasCurrentPath()) { - LERROR("There is no current path to sample points from."); - return {}; - } - - std::vector 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 PathNavigator::curveViewDirections(int nSteps) const { - if (!hasCurrentPath()) { - LERROR("There is no current path to sample points from."); - return {}; - } - - std::vector 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 PathNavigator::controlPoints() const { - if (!hasCurrentPath()) { - LERROR("There is no current path to sample points from."); - return {}; - } - - std::vector points; - const std::vector curvePoints = _currentPath->controlPoints(); - points.insert(points.end(), curvePoints.begin(), curvePoints.end()); - - return points; -} - double PathNavigator::minValidBoundingSphere() const { return _minValidBoundingSphere; }