From 7d58cf40c2ea56c6b49bb0473f5c78f4dd36d4a2 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Tue, 23 Feb 2021 14:07:34 +0100 Subject: [PATCH 001/251] Add module for skybrowser --- modules/skybrowser/CMakeLists.txt | 50 ++++++++++ modules/skybrowser/skybrowsermodule.cpp | 103 ++++++++++++++++++++ modules/skybrowser/skybrowsermodule.h | 61 ++++++++++++ modules/skybrowser/skybrowsermodule_lua.inl | 78 +++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 modules/skybrowser/CMakeLists.txt create mode 100644 modules/skybrowser/skybrowsermodule.cpp create mode 100644 modules/skybrowser/skybrowsermodule.h create mode 100644 modules/skybrowser/skybrowsermodule_lua.inl diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt new file mode 100644 index 0000000000..04c490df01 --- /dev/null +++ b/modules/skybrowser/CMakeLists.txt @@ -0,0 +1,50 @@ +########################################################################################## +# # +# 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 + + skybrowsermodule.h + +) +source_group("Header Files" FILES ${HEADER_FILES}) + +set(SOURCE_FILES + + skybrowsermodule.cpp + skybrowsermodule_lua.inl + +) +source_group("Source Files" FILES ${SOURCE_FILES}) + + +create_new_module( + "Skybrowser" + skybrowser_module + STATIC + ${HEADER_FILES} ${SOURCE_FILES} +) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp new file mode 100644 index 0000000000..9a8c1c2c55 --- /dev/null +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -0,0 +1,103 @@ +/***************************************************************************************** + * * + * 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 +#include +#include +#include +#include + + +#include "skybrowsermodule_lua.inl" + + +namespace { + constexpr const openspace::properties::Property::PropertyInfo TestInfo = + { + "TestInfo", + "Test Info", + "tjobidabidobidabidopp plopp" + }; + + struct [[codegen::Dictionary(SkybrowserModule)]] Parameters { + + // [[codegen::verbatim(TestInfo.description)]] + std::optional testString; + }; + + #include "skybrowsermodule_codegen.cpp" + + +} // namespace + +namespace openspace { + +SkybrowserModule::SkybrowserModule() + : OpenSpaceModule(Name) + , _testProperty(TestInfo) +{ + addProperty(_testProperty); +} + +scripting::LuaLibrary SkybrowserModule::luaLibrary() const { + scripting::LuaLibrary res; + res.name = "skybrowser"; + res.functions = { + { + "test", + &skybrowser::luascriptfunctions::testFunction, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + } + }; + + return res; +} + +void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { + const Parameters p = codegen::bake(dict); + _testProperty = p.testString.value_or(_testProperty); + + auto fBrowser = FactoryManager::ref().factory(); + ghoul_assert(fBrowser, "No browser factory existed :'-("); + fBrowser->registerClass("ScreenSpaceBrowser"); +} +/* +std::vector SkybrowserModule::documentations() const { + return { + ExoplanetsDataPreparationTask::documentation(), + RenderableOrbitDisc::Documentation() + }; +} +*/ +} // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h new file mode 100644 index 0000000000..6b4eb302ea --- /dev/null +++ b/modules/skybrowser/skybrowsermodule.h @@ -0,0 +1,61 @@ +/***************************************************************************************** + * * + * 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_SKYBROWSER___SKYBROWSERMODULE___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ + + +#include +#include +#include + +#include +#include +#include +#include + + + +namespace openspace { + +class SkybrowserModule : public OpenSpaceModule { +public: + constexpr static const char* Name = "Skybrowser"; + + SkybrowserModule(); + virtual ~SkybrowserModule() = default; + + scripting::LuaLibrary luaLibrary() const override; + //std::vector documentations() const override; + +protected: + void internalInitialize(const ghoul::Dictionary& dict) override; + + properties::StringProperty _testProperty; + +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl new file mode 100644 index 0000000000..676ee684f4 --- /dev/null +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -0,0 +1,78 @@ +#include + + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace { + constexpr const char _loggerCat[] = "SkybrowserModule"; +} // namespace + + +namespace openspace::skybrowser::luascriptfunctions { + + bool testFunction() { + LINFOC(_loggerCat, "yabadadooo"); + return true; + } + + + int testFunction(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::testFunction"); + + + LINFOC(_loggerCat, "hoho"); + testFunction(); + + //std::string _url = "https://wallpaperaccess.com/full/3010132.jpg"; + // 'https://cdn.wallpapersafari.com/6/92/0nbCPw.jpg' + /* + // get url from user + const std::string _url = ghoul::lua::value(L, 1); + + using namespace std::string_literals; + + std::string identifier = "ImageTest"; + std::string guiname = "Test"; + double size = 1.E11; + + // create renderable renderableplaneimageonline + ghoul::Dictionary renderable; + renderable.setValue("Type", "RenderablePlaneImageOnline"s); + renderable.setValue("URL", _url); + renderable.setValue("Origin", "Center"s); + renderable.setValue("Size", size); + + ghoul::Dictionary gui; + gui.setValue("Name", guiname); + gui.setValue("Path", "/Software Integration"s); + + ghoul::Dictionary node; + node.setValue("Identifier", identifier); + node.setValue("Renderable", renderable); + node.setValue("GUI", gui); + + + openspace::global::scriptEngine->queueScript( + "openspace.addSceneGraphNode(" + ghoul::formatLua(node) + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); + */ + + return 1; + } + +} + From 7c83c4e3da70c4aa47f85bd52b20091bcab21a7e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 23 Feb 2021 14:40:48 +0100 Subject: [PATCH 002/251] Add working way of instantiating ScreenSpaceBrowser from LuaScript --- modules/skybrowser/CMakeLists.txt | 3 --- modules/skybrowser/include.cmake | 4 ++++ modules/skybrowser/skybrowsermodule.cpp | 5 ++++- modules/skybrowser/skybrowsermodule.h | 3 +-- modules/skybrowser/skybrowsermodule_lua.inl | 6 +++--- 5 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 modules/skybrowser/include.cmake diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 04c490df01..7157b0828f 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -24,8 +24,6 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) - - set(HEADER_FILES skybrowsermodule.h @@ -37,7 +35,6 @@ set(SOURCE_FILES skybrowsermodule.cpp skybrowsermodule_lua.inl - ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/include.cmake b/modules/skybrowser/include.cmake new file mode 100644 index 0000000000..83fdb5ae82 --- /dev/null +++ b/modules/skybrowser/include.cmake @@ -0,0 +1,4 @@ +set(DEFAULT_MODULE ON) +set(OPENSPACE_DEPENDENCIES + webbrowser +) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 9a8c1c2c55..86954f46df 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -23,6 +23,8 @@ ****************************************************************************************/ #include + //#include + //#include #include @@ -87,10 +89,11 @@ scripting::LuaLibrary SkybrowserModule::luaLibrary() const { void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); _testProperty = p.testString.value_or(_testProperty); - + /* auto fBrowser = FactoryManager::ref().factory(); ghoul_assert(fBrowser, "No browser factory existed :'-("); fBrowser->registerClass("ScreenSpaceBrowser"); + */ } /* std::vector SkybrowserModule::documentations() const { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 6b4eb302ea..49cba25bb7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -27,8 +27,7 @@ #include -#include -#include + #include #include diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 676ee684f4..9a6ae8a79f 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -64,12 +64,12 @@ namespace openspace::skybrowser::luascriptfunctions { node.setValue("Renderable", renderable); node.setValue("GUI", gui); - + */ openspace::global::scriptEngine->queueScript( - "openspace.addSceneGraphNode(" + ghoul::formatLua(node) + ")", + "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - */ + return 1; } From a00013af1cd76ae6d2fd66e49c7a2e95abe7bbf4 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Thu, 25 Feb 2021 11:03:22 +0100 Subject: [PATCH 003/251] Test to setup message communication --- modules/skybrowser/skybrowsermodule.cpp | 32 ++++++++++++-- modules/skybrowser/skybrowsermodule.h | 3 ++ modules/skybrowser/skybrowsermodule_lua.inl | 43 ++++++++----------- .../webbrowser/include/screenspacebrowser.h | 2 + modules/webbrowser/src/screenspacebrowser.cpp | 26 +++++++++++ 5 files changed, 77 insertions(+), 29 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 86954f46df..99ba3bb756 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -44,15 +44,24 @@ namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = { - "TestInfo", + "Test", "Test Info", "tjobidabidobidabidopp plopp" }; + constexpr const openspace::properties::Property::PropertyInfo ZoomInfo = + { + "Zoom", + "Zoom Info", + "tjobidabidobidabidopp plupp" + }; struct [[codegen::Dictionary(SkybrowserModule)]] Parameters { // [[codegen::verbatim(TestInfo.description)]] - std::optional testString; + std::optional test; + + // [[codegen::verbatim(ZoomInfo.description)]] + std::optional zoom; }; #include "skybrowsermodule_codegen.cpp" @@ -65,10 +74,14 @@ namespace openspace { SkybrowserModule::SkybrowserModule() : OpenSpaceModule(Name) , _testProperty(TestInfo) + , _zoomFactor(ZoomInfo, 70.f ,0.f ,150.f) { addProperty(_testProperty); + addProperty(_zoomFactor); } + + scripting::LuaLibrary SkybrowserModule::luaLibrary() const { scripting::LuaLibrary res; res.name = "skybrowser"; @@ -80,15 +93,28 @@ scripting::LuaLibrary SkybrowserModule::luaLibrary() const { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "update", + &skybrowser::luascriptfunctions::updateFunction, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" } }; return res; } +float SkybrowserModule::zoomFactor() const{ + return _zoomFactor; +} + void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); - _testProperty = p.testString.value_or(_testProperty); + _testProperty = p.test.value_or(_testProperty); + _zoomFactor = p.zoom.value_or(_zoomFactor); /* auto fBrowser = FactoryManager::ref().factory(); ghoul_assert(fBrowser, "No browser factory existed :'-("); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 49cba25bb7..aa8c4b2efb 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -45,6 +45,8 @@ public: SkybrowserModule(); virtual ~SkybrowserModule() = default; + float zoomFactor() const; + scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -52,6 +54,7 @@ protected: void internalInitialize(const ghoul::Dictionary& dict) override; properties::StringProperty _testProperty; + properties::FloatProperty _zoomFactor; }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 9a6ae8a79f..d276a6e53c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include @@ -14,7 +16,7 @@ #include #include #include - +#include namespace { constexpr const char _loggerCat[] = "SkybrowserModule"; @@ -23,48 +25,37 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { - bool testFunction() { + int updateFunction(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::updateFunction"); LINFOC(_loggerCat, "yabadadooo"); - return true; - } + ScreenSpaceBrowser* test = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + test->testMessage(); + + return 1; + } int testFunction(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::testFunction"); - + const SkybrowserModule* module = global::moduleEngine->module(); LINFOC(_loggerCat, "hoho"); - testFunction(); + LINFOC(_loggerCat, std::to_string(module->zoomFactor())); //std::string _url = "https://wallpaperaccess.com/full/3010132.jpg"; // 'https://cdn.wallpapersafari.com/6/92/0nbCPw.jpg' /* // get url from user const std::string _url = ghoul::lua::value(L, 1); - + */ using namespace std::string_literals; - std::string identifier = "ImageTest"; - std::string guiname = "Test"; - double size = 1.E11; - - // create renderable renderableplaneimageonline - ghoul::Dictionary renderable; - renderable.setValue("Type", "RenderablePlaneImageOnline"s); - renderable.setValue("URL", _url); - renderable.setValue("Origin", "Center"s); - renderable.setValue("Size", size); - - ghoul::Dictionary gui; - gui.setValue("Name", guiname); - gui.setValue("Path", "/Software Integration"s); - ghoul::Dictionary node; - node.setValue("Identifier", identifier); - node.setValue("Renderable", renderable); - node.setValue("GUI", gui); + node.setValue("Type", "ScreenSpaceBrowser"s); + node.setValue("Identifier", "ScreenSpaceBowser"s); + node.setValue("Name", "Screen Space Bowser"s); + node.setValue("Url", "http://localhost:8000/?origin=localhost:4690"s); - */ openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", scripting::ScriptEngine::RemoteScripting::Yes diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 9dd81e0d63..eb484b5d78 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -72,6 +72,8 @@ public: void update() override; bool isReady() const override; + void testMessage(); + private: class ScreenSpaceRenderHandler : public WebRenderHandler { public: diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index a2c4df95fe..dc52e8bc36 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -57,6 +57,32 @@ namespace { namespace openspace { +void ScreenSpaceBrowser::testMessage() { + LINFOC(_loggerCat, "TJOHO"); + //_browserInstance->reshape(glm::ivec2(1000, 1000)); + + std::string mes2 = "var frame = document.getElementsByTagName('iframe')[0].contentWindow; const message : CenterOnCoordinatesMessage = { event: 'center_on_coordinates', ra : Number(50) , dec : Number(70), fov : Number(120), instant : false,}; frame.postMessage(message, 'https://web.wwtassets.org/research/latest/');"; + + //std::string thisFrame = "var frame = window.frames[0]; "; + //std::string iFrame = "var frame = document.getElementsByTagName('iframe')[0].contentWindow;"; + std::string mes3 = "var message = {\ + event: 'center_on_coordinates',\ + ra : Number(80),\ + dec : Number(50),\ + fov : Number(70),\ + instant : false\ + };\ + window.postMessage(message, 'http://localhost:4690');"; + + + CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); + + frame->ExecuteJavaScript(mes3, + frame->GetURL(), 0); + + +} + void ScreenSpaceBrowser::ScreenSpaceRenderHandler::draw() {} void ScreenSpaceBrowser::ScreenSpaceRenderHandler::render() {} From b24a75e484ff2ca473e1ed041cf92ea17b1725e1 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 1 Mar 2021 13:32:53 +0100 Subject: [PATCH 004/251] Clean up structure so ScreenSpaceBrowser only executes string for javascript --- modules/skybrowser/skybrowsermodule.cpp | 19 ++++++++++++ modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 29 +++++++++++++++---- .../webbrowser/include/screenspacebrowser.h | 2 +- modules/webbrowser/src/screenspacebrowser.cpp | 28 ++++-------------- 5 files changed, 49 insertions(+), 30 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 99ba3bb756..cf8419e880 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include "skybrowsermodule_lua.inl" @@ -121,6 +122,24 @@ void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { fBrowser->registerClass("ScreenSpaceBrowser"); */ } + +glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { + + // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> + // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 + -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 + -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 + }); + + glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; + float l = atan2(rICRS[1], rICRS[0]); + float b = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); + + return glm::dvec2(glm::degrees(l), glm::degrees(b)); +} + /* std::vector SkybrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index aa8c4b2efb..33a5afeab4 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -46,6 +46,7 @@ public: virtual ~SkybrowserModule() = default; float zoomFactor() const; + glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index d276a6e53c..b482dd8033 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -17,6 +17,8 @@ #include #include #include +#include +#include namespace { constexpr const char _loggerCat[] = "SkybrowserModule"; @@ -26,11 +28,22 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { int updateFunction(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::updateFunction"); - LINFOC(_loggerCat, "yabadadooo"); + // Get FOV from argument + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::updateFunction"); + float fov = ghoul::lua::value(L, 1); - ScreenSpaceBrowser* test = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - test->testMessage(); + // Get camera position + //const glm::dvec3 cameraPosition = global::navigationHandler->camera()->positionVec3(); + const glm::dvec3 cameraPosition = global::navigationHandler->camera()->viewDirectionWorldSpace(); + + // Convert to celestial coordinates + const SkybrowserModule* module = global::moduleEngine->module(); + glm::dvec2 celestCoords = module->convertGalacticToCelestial(glm::dvec3(cameraPosition[0], cameraPosition[1], cameraPosition[2])); + + // Execute javascript on browser + ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + std::string script = "vm.onMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(fov) + "), instant : false})"; + browser->executeJavascript(script); return 1; } @@ -39,6 +52,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::testFunction"); const SkybrowserModule* module = global::moduleEngine->module(); + glm::dvec3 testvec = glm::dvec3(0.0, 0.0, 0.0); + module->convertGalacticToCelestial(testvec); + LINFOC(_loggerCat, "hoho"); LINFOC(_loggerCat, std::to_string(module->zoomFactor())); @@ -54,13 +70,14 @@ namespace openspace::skybrowser::luascriptfunctions { node.setValue("Type", "ScreenSpaceBrowser"s); node.setValue("Identifier", "ScreenSpaceBowser"s); node.setValue("Name", "Screen Space Bowser"s); - node.setValue("Url", "http://localhost:8000/?origin=localhost:4690"s); + node.setValue("Url", "http://localhost:8080/?origin=localhost:4690"s); + // node.setValue("Dimensions", "glm::ivec2(1000, 1000)"); openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - + return 1; } diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index eb484b5d78..0f9f9adcd6 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -72,7 +72,7 @@ public: void update() override; bool isReady() const override; - void testMessage(); + void executeJavascript(std::string &script) const; private: class ScreenSpaceRenderHandler : public WebRenderHandler { diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index dc52e8bc36..4d861fdcdb 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -23,6 +23,7 @@ ****************************************************************************************/ #include +#include #include #include @@ -57,30 +58,11 @@ namespace { namespace openspace { -void ScreenSpaceBrowser::testMessage() { - LINFOC(_loggerCat, "TJOHO"); - //_browserInstance->reshape(glm::ivec2(1000, 1000)); - - std::string mes2 = "var frame = document.getElementsByTagName('iframe')[0].contentWindow; const message : CenterOnCoordinatesMessage = { event: 'center_on_coordinates', ra : Number(50) , dec : Number(70), fov : Number(120), instant : false,}; frame.postMessage(message, 'https://web.wwtassets.org/research/latest/');"; - - //std::string thisFrame = "var frame = window.frames[0]; "; - //std::string iFrame = "var frame = document.getElementsByTagName('iframe')[0].contentWindow;"; - std::string mes3 = "var message = {\ - event: 'center_on_coordinates',\ - ra : Number(80),\ - dec : Number(50),\ - fov : Number(70),\ - instant : false\ - };\ - window.postMessage(message, 'http://localhost:4690');"; - - +void ScreenSpaceBrowser::executeJavascript(std::string &script) const { + LINFOC(_loggerCat, "Executing javascript " + script); + CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - - frame->ExecuteJavaScript(mes3, - frame->GetURL(), 0); - - + frame->ExecuteJavaScript(script, frame->GetURL(), 0); } void ScreenSpaceBrowser::ScreenSpaceRenderHandler::draw() {} From 87df6932f8d61347c319c23e717de8425938e83d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 1 Mar 2021 16:50:01 +0100 Subject: [PATCH 005/251] Create functions to look in WWT-window at direction in OpenSpace and some cleanup --- modules/skybrowser/skybrowsermodule.cpp | 34 ++++++++++++--- modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 42 +++++++------------ .../webbrowser/include/screenspacebrowser.h | 1 + modules/webbrowser/src/screenspacebrowser.cpp | 8 +++- 5 files changed, 51 insertions(+), 35 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index cf8419e880..7bfe126c20 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -36,8 +36,7 @@ #include #include #include -#include - +#include // For atan2 #include "skybrowsermodule_lua.inl" @@ -88,16 +87,24 @@ scripting::LuaLibrary SkybrowserModule::luaLibrary() const { res.name = "skybrowser"; res.functions = { { - "test", - &skybrowser::luascriptfunctions::testFunction, + "create", + &skybrowser::luascriptfunctions::createBrowser, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, { - "update", - &skybrowser::luascriptfunctions::updateFunction, + "move", + &skybrowser::luascriptfunctions::moveBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "follow", + &skybrowser::luascriptfunctions::followCamera, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " @@ -123,6 +130,21 @@ void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { */ } +void SkybrowserModule::WWTfollowCamera() const { + // Get camera view direction + const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + + // Convert to celestial coordinates + const SkybrowserModule* module = global::moduleEngine->module(); + glm::dvec2 celestCoords = module->convertGalacticToCelestial(viewDirection); + + // Execute javascript on browser + ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + std::string script = "vm.onMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(_zoomFactor) + "), instant : false})"; + browser->executeJavascript(script); + +} + glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 33a5afeab4..8c02482383 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -47,6 +47,7 @@ public: float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; + void WWTfollowCamera() const; scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b482dd8033..b522dd155d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -27,43 +27,31 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { - int updateFunction(lua_State* L) { - // Get FOV from argument - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::updateFunction"); - float fov = ghoul::lua::value(L, 1); + int followCamera(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); - // Get camera position - //const glm::dvec3 cameraPosition = global::navigationHandler->camera()->positionVec3(); - const glm::dvec3 cameraPosition = global::navigationHandler->camera()->viewDirectionWorldSpace(); - - // Convert to celestial coordinates const SkybrowserModule* module = global::moduleEngine->module(); - glm::dvec2 celestCoords = module->convertGalacticToCelestial(glm::dvec3(cameraPosition[0], cameraPosition[1], cameraPosition[2])); - - // Execute javascript on browser - ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - std::string script = "vm.onMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(fov) + "), instant : false})"; - browser->executeJavascript(script); + module->WWTfollowCamera(); return 1; } - int testFunction(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::testFunction"); + int moveBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); + ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + browser->translate(glm::vec3(-0.8, -0.4, 0.0)); + return 1; + } + + int createBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::createBrowser"); + ghoul::lua::value(L, 1); const SkybrowserModule* module = global::moduleEngine->module(); - glm::dvec3 testvec = glm::dvec3(0.0, 0.0, 0.0); - module->convertGalacticToCelestial(testvec); - - LINFOC(_loggerCat, "hoho"); - LINFOC(_loggerCat, std::to_string(module->zoomFactor())); //std::string _url = "https://wallpaperaccess.com/full/3010132.jpg"; // 'https://cdn.wallpapersafari.com/6/92/0nbCPw.jpg' - /* - // get url from user - const std::string _url = ghoul::lua::value(L, 1); - */ + using namespace std::string_literals; ghoul::Dictionary node; @@ -77,8 +65,6 @@ namespace openspace::skybrowser::luascriptfunctions { "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - - return 1; } diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 0f9f9adcd6..514d989043 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -73,6 +73,7 @@ public: bool isReady() const override; void executeJavascript(std::string &script) const; + void translate(glm::vec3 translation); private: class ScreenSpaceRenderHandler : public WebRenderHandler { diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 4d861fdcdb..dcdee6a601 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -62,7 +62,13 @@ void ScreenSpaceBrowser::executeJavascript(std::string &script) const { LINFOC(_loggerCat, "Executing javascript " + script); CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - frame->ExecuteJavaScript(script, frame->GetURL(), 0); + frame->ExecuteJavaScript(script, frame->GetURL(), 0); +} + +void ScreenSpaceBrowser::translate(glm::vec3 translation) { + glm::vec4 homogenousCoords(glm::vec4(translation, 1.0)); + glm::vec3 position = _cartesianPosition; + _cartesianPosition = glm::translate(glm::mat4(1.f), translation) * glm::vec4(position, 1.0f); } void ScreenSpaceBrowser::ScreenSpaceRenderHandler::draw() {} From 8eadcafce38095464b6f22752ea2363ce8effd21 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 2 Mar 2021 14:27:02 +0100 Subject: [PATCH 006/251] Change skybrowser module to work with one localhost and change variable names to ra and dec --- modules/skybrowser/skybrowsermodule.cpp | 11 ++++++----- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 7bfe126c20..1f87b99aea 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -140,9 +140,8 @@ void SkybrowserModule::WWTfollowCamera() const { // Execute javascript on browser ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - std::string script = "vm.onMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(_zoomFactor) + "), instant : false})"; + std::string script = "window.frames[0].postMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(_zoomFactor) + "), instant : false})"; browser->executeJavascript(script); - } glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { @@ -156,10 +155,12 @@ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { }); glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; - float l = atan2(rICRS[1], rICRS[0]); - float b = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); + float ra = atan2(rICRS[1], rICRS[0]); + float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); - return glm::dvec2(glm::degrees(l), glm::degrees(b)); + std::cout << glm::degrees(dec) << std::endl; + + return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } /* diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b522dd155d..eecd415ca6 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -58,7 +58,7 @@ namespace openspace::skybrowser::luascriptfunctions { node.setValue("Type", "ScreenSpaceBrowser"s); node.setValue("Identifier", "ScreenSpaceBowser"s); node.setValue("Name", "Screen Space Bowser"s); - node.setValue("Url", "http://localhost:8080/?origin=localhost:4690"s); + node.setValue("Url", "http://localhost:7800/sky_browser/index.html"s); // node.setValue("Dimensions", "glm::ivec2(1000, 1000)"); openspace::global::scriptEngine->queueScript( From f444fcfa805cb63a9434812367bf39b54bad825d Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Wed, 3 Mar 2021 10:24:13 +0100 Subject: [PATCH 007/251] Add function to disable faceCamera prpoerty --- modules/skybrowser/skybrowsermodule_lua.inl | 11 ++++++----- modules/webbrowser/include/screenspacebrowser.h | 1 + modules/webbrowser/src/screenspacebrowser.cpp | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index eecd415ca6..d43d89fa6b 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -29,16 +29,17 @@ namespace openspace::skybrowser::luascriptfunctions { int followCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); - const SkybrowserModule* module = global::moduleEngine->module(); - module->WWTfollowCamera(); - + ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + + module->WWTfollowCamera(); return 1; } int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + browser->setFaceCameraPropertyToFalse(); browser->translate(glm::vec3(-0.8, -0.4, 0.0)); return 1; } @@ -47,7 +48,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::createBrowser"); ghoul::lua::value(L, 1); - const SkybrowserModule* module = global::moduleEngine->module(); + const SkybrowserModule* module = global::moduleEngine->module(); //std::string _url = "https://wallpaperaccess.com/full/3010132.jpg"; // 'https://cdn.wallpapersafari.com/6/92/0nbCPw.jpg' @@ -58,7 +59,7 @@ namespace openspace::skybrowser::luascriptfunctions { node.setValue("Type", "ScreenSpaceBrowser"s); node.setValue("Identifier", "ScreenSpaceBowser"s); node.setValue("Name", "Screen Space Bowser"s); - node.setValue("Url", "http://localhost:7800/sky_browser/index.html"s); + node.setValue("Url", "http://localhost:8000/"s); // node.setValue("Dimensions", "glm::ivec2(1000, 1000)"); openspace::global::scriptEngine->queueScript( diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 514d989043..f9c35beec6 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -74,6 +74,7 @@ public: void executeJavascript(std::string &script) const; void translate(glm::vec3 translation); + void setFaceCameraPropertyToFalse(); private: class ScreenSpaceRenderHandler : public WebRenderHandler { diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index dcdee6a601..c21d36ed7d 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -71,6 +71,10 @@ void ScreenSpaceBrowser::translate(glm::vec3 translation) { _cartesianPosition = glm::translate(glm::mat4(1.f), translation) * glm::vec4(position, 1.0f); } +void ScreenSpaceBrowser::setFaceCameraPropertyToFalse() { + _faceCamera = false; +} + void ScreenSpaceBrowser::ScreenSpaceRenderHandler::draw() {} void ScreenSpaceBrowser::ScreenSpaceRenderHandler::render() {} From df5719f39fc99c82fe291d507ac16b4ed54b9d1a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 3 Mar 2021 11:36:23 +0100 Subject: [PATCH 008/251] Change structure of message passing to WWT to more general case with functions --- modules/skybrowser/include.cmake | 1 - modules/skybrowser/skybrowsermodule.cpp | 51 +++++++++++++++------ modules/skybrowser/skybrowsermodule.h | 13 ++++-- modules/skybrowser/skybrowsermodule_lua.inl | 12 +++-- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/modules/skybrowser/include.cmake b/modules/skybrowser/include.cmake index 83fdb5ae82..9f1c8e7b85 100644 --- a/modules/skybrowser/include.cmake +++ b/modules/skybrowser/include.cmake @@ -1,4 +1,3 @@ -set(DEFAULT_MODULE ON) set(OPENSPACE_DEPENDENCIES webbrowser ) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1f87b99aea..6ee67edc62 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -23,15 +23,13 @@ ****************************************************************************************/ #include - //#include - //#include - +#include #include #include #include #include -#include +//#include #include #include #include @@ -40,7 +38,6 @@ #include "skybrowsermodule_lua.inl" - namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = { @@ -75,6 +72,7 @@ SkybrowserModule::SkybrowserModule() : OpenSpaceModule(Name) , _testProperty(TestInfo) , _zoomFactor(ZoomInfo, 70.f ,0.f ,150.f) + //, _skyBrowser(nullptr) { addProperty(_testProperty); addProperty(_zoomFactor); @@ -130,20 +128,46 @@ void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { */ } -void SkybrowserModule::WWTfollowCamera() const { +bool SkybrowserModule::sendMessageToWWT(const std::string& msg) { + ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + if (browser) { + std::string script = "sendMessageToWWT(" + msg + ");"; + browser->executeJavascript(script); + return true; + } + else { + LERROR("No sky browser added! Can't send message."); + return false; + } + +} + +void SkybrowserModule::WWTfollowCamera() { // Get camera view direction const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); // Convert to celestial coordinates - const SkybrowserModule* module = global::moduleEngine->module(); - glm::dvec2 celestCoords = module->convertGalacticToCelestial(viewDirection); - - // Execute javascript on browser - ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - std::string script = "window.frames[0].postMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(_zoomFactor) + "), instant : false})"; - browser->executeJavascript(script); + glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); + std::string message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); + + sendMessageToWWT(message); } +std::string SkybrowserModule::createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly) const { + std::string moveInstString = moveInstantly ? "true" : "false"; + std::string script = "{ event: 'center_on_coordinates' , ra: " + std::to_string(celestCoords[0]) + ", dec : " + std::to_string(celestCoords[1]) + ", fov: " + std::to_string(_zoomFactor) + ", instant: " + moveInstString +"}"; + + return script; +} +/* +void SkybrowserModule::initializeBrowser(ScreenSpaceBrowser* skyBrowser) { + _skyBrowser = skyBrowser; +} + +ScreenSpaceBrowser* SkybrowserModule::skyBrowser() { + return _skyBrowser; +} +*/ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> @@ -158,7 +182,6 @@ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { float ra = atan2(rICRS[1], rICRS[0]); float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); - std::cout << glm::degrees(dec) << std::endl; return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 8c02482383..b25b45e2cd 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -28,14 +28,11 @@ #include - #include #include #include #include - - namespace openspace { class SkybrowserModule : public OpenSpaceModule { @@ -47,8 +44,14 @@ public: float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; - void WWTfollowCamera() const; + void WWTfollowCamera(); + std::string createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly = false) const; + + bool sendMessageToWWT(const std::string& msg); + + //void initializeBrowser(ScreenSpaceBrowser* skyBrowser_); + //ScreenSpaceBrowser* skyBrowser(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -57,7 +60,7 @@ protected: properties::StringProperty _testProperty; properties::FloatProperty _zoomFactor; - + //ScreenSpaceBrowser* _skyBrowser; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index eecd415ca6..4f52e18ffd 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -30,7 +30,7 @@ namespace openspace::skybrowser::luascriptfunctions { int followCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); - const SkybrowserModule* module = global::moduleEngine->module(); + SkybrowserModule* module = global::moduleEngine->module(); module->WWTfollowCamera(); return 1; @@ -38,6 +38,9 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); + + //SkybrowserModule* module = global::moduleEngine->module(); + // module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); browser->translate(glm::vec3(-0.8, -0.4, 0.0)); return 1; @@ -47,7 +50,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::createBrowser"); ghoul::lua::value(L, 1); - const SkybrowserModule* module = global::moduleEngine->module(); + SkybrowserModule* module = global::moduleEngine->module(); //std::string _url = "https://wallpaperaccess.com/full/3010132.jpg"; // 'https://cdn.wallpapersafari.com/6/92/0nbCPw.jpg' @@ -58,13 +61,16 @@ namespace openspace::skybrowser::luascriptfunctions { node.setValue("Type", "ScreenSpaceBrowser"s); node.setValue("Identifier", "ScreenSpaceBowser"s); node.setValue("Name", "Screen Space Bowser"s); - node.setValue("Url", "http://localhost:7800/sky_browser/index.html"s); + node.setValue("Url", "http://localhost:8000/index.html"s); // node.setValue("Dimensions", "glm::ivec2(1000, 1000)"); openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); + ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + // module->initializeBrowser(browser); + return 1; } From 7965ed5d24b014b840221cc1a95342694fb2f298 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 3 Mar 2021 16:45:35 +0100 Subject: [PATCH 009/251] Make WWT follow OpenSpace w thread, change interval for zoom and fix coordinate conversion error --- modules/skybrowser/skybrowsermodule.cpp | 21 ++++++++++++------- modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 12 +++++++++-- modules/webbrowser/src/screenspacebrowser.cpp | 2 +- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 6ee67edc62..23d8d5aa91 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -37,6 +37,7 @@ #include // For atan2 #include "skybrowsermodule_lua.inl" +#include // For sleep namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = @@ -71,7 +72,7 @@ namespace openspace { SkybrowserModule::SkybrowserModule() : OpenSpaceModule(Name) , _testProperty(TestInfo) - , _zoomFactor(ZoomInfo, 70.f ,0.f ,150.f) + , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) //, _skyBrowser(nullptr) { addProperty(_testProperty); @@ -143,14 +144,17 @@ bool SkybrowserModule::sendMessageToWWT(const std::string& msg) { } void SkybrowserModule::WWTfollowCamera() { - // Get camera view direction - const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + while (true) { + // Get camera view direction + const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); - // Convert to celestial coordinates - glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); - std::string message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); - - sendMessageToWWT(message); + // Convert to celestial coordinates + glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); + std::string message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); + + sendMessageToWWT(message); + Sleep(50); + } } std::string SkybrowserModule::createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly) const { @@ -182,6 +186,7 @@ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { float ra = atan2(rICRS[1], rICRS[0]); float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); + ra = ra > 0 ? ra : ra + (2 * glm::pi()); return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index b25b45e2cd..afdb7a7ee7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -46,7 +46,7 @@ public: glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera(); - std::string createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly = false) const; + std::string createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly = true) const; bool sendMessageToWWT(const std::string& msg); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index d2c672d74a..46c7561df8 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -19,6 +19,8 @@ #include #include #include +#include + namespace { constexpr const char _loggerCat[] = "SkybrowserModule"; @@ -31,17 +33,23 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkybrowserModule* module = global::moduleEngine->module(); - module->WWTfollowCamera(); - + std::thread thread(&SkybrowserModule::WWTfollowCamera, module); + thread.detach(); + return 1; } int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); + // SkybrowserModule* module = global::moduleEngine->module(); + // std::string test = module->createMessageForMovingWWTCamera(glm::dvec2(18, -32), 50); + // module->sendMessageToWWT(test); + //SkybrowserModule* module = global::moduleEngine->module(); // module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + browser->setFaceCameraPropertyToFalse(); browser->translate(glm::vec3(-0.8, -0.4, 0.0)); return 1; diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index c21d36ed7d..d2da096ad4 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -59,7 +59,7 @@ namespace { namespace openspace { void ScreenSpaceBrowser::executeJavascript(std::string &script) const { - LINFOC(_loggerCat, "Executing javascript " + script); + //LINFOC(_loggerCat, "Executing javascript " + script); CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); frame->ExecuteJavaScript(script, frame->GetURL(), 0); From 7847111afc77b22d110305c846fc8701e22363ef Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 5 Mar 2021 10:26:45 +0100 Subject: [PATCH 010/251] Add pointer to ScreenSpaceBrowser in SkyBrowserModule and add function to pause time in WWT --- modules/skybrowser/skybrowsermodule.cpp | 13 ++++++++++--- modules/skybrowser/skybrowsermodule.h | 9 ++++++--- modules/skybrowser/skybrowsermodule_lua.inl | 21 ++++++++++----------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 23d8d5aa91..939b024ec1 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -73,7 +73,7 @@ SkybrowserModule::SkybrowserModule() : OpenSpaceModule(Name) , _testProperty(TestInfo) , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) - //, _skyBrowser(nullptr) + , _skyBrowser(nullptr) { addProperty(_testProperty); addProperty(_zoomFactor); @@ -163,7 +163,14 @@ std::string SkybrowserModule::createMessageForMovingWWTCamera(glm::dvec2 celestC return script; } -/* + +std::string SkybrowserModule::createMessageForPausingWWTTime() const { + std::string script = "{ event: 'pause_time'}"; + + return script; +} + + void SkybrowserModule::initializeBrowser(ScreenSpaceBrowser* skyBrowser) { _skyBrowser = skyBrowser; } @@ -171,7 +178,7 @@ void SkybrowserModule::initializeBrowser(ScreenSpaceBrowser* skyBrowser) { ScreenSpaceBrowser* SkybrowserModule::skyBrowser() { return _skyBrowser; } -*/ + glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index afdb7a7ee7..3bd26fe04f 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -35,6 +35,8 @@ namespace openspace { +class ScreenSpaceBrowser; + class SkybrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "Skybrowser"; @@ -47,11 +49,12 @@ public: void WWTfollowCamera(); std::string createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly = true) const; + std::string createMessageForPausingWWTTime() const; bool sendMessageToWWT(const std::string& msg); - //void initializeBrowser(ScreenSpaceBrowser* skyBrowser_); - //ScreenSpaceBrowser* skyBrowser(); + void initializeBrowser(ScreenSpaceBrowser* skyBrowser_); + ScreenSpaceBrowser* skyBrowser(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -60,7 +63,7 @@ protected: properties::StringProperty _testProperty; properties::FloatProperty _zoomFactor; - //ScreenSpaceBrowser* _skyBrowser; + ScreenSpaceBrowser* _skyBrowser; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 46c7561df8..212e506483 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -33,6 +33,8 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkybrowserModule* module = global::moduleEngine->module(); + std::string message = module->createMessageForPausingWWTTime(); + module->sendMessageToWWT(message); std::thread thread(&SkybrowserModule::WWTfollowCamera, module); thread.detach(); @@ -42,16 +44,15 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - // SkybrowserModule* module = global::moduleEngine->module(); - // std::string test = module->createMessageForMovingWWTCamera(glm::dvec2(18, -32), 50); - // module->sendMessageToWWT(test); - //SkybrowserModule* module = global::moduleEngine->module(); - // module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); + SkybrowserModule* module = global::moduleEngine->module(); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + module->initializeBrowser(browser); + //ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - browser->setFaceCameraPropertyToFalse(); - browser->translate(glm::vec3(-0.8, -0.4, 0.0)); + module->skyBrowser()->setFaceCameraPropertyToFalse(); + module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); + return 1; } @@ -78,10 +79,8 @@ namespace openspace::skybrowser::luascriptfunctions { openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", scripting::ScriptEngine::RemoteScripting::Yes - ); - ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - // module->initializeBrowser(browser); - + ); + return 1; } From 913e975acb275e27674c2340b154cdbbac962d4b Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 5 Mar 2021 11:55:51 +0100 Subject: [PATCH 011/251] Change messages to be created in ghoul dictionaries --- modules/skybrowser/skybrowsermodule.cpp | 47 ++++++++++----------- modules/skybrowser/skybrowsermodule.h | 6 +-- modules/skybrowser/skybrowsermodule_lua.inl | 4 +- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 939b024ec1..c7ab21c939 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -29,15 +29,14 @@ #include #include #include -//#include #include #include #include #include -#include // For atan2 - #include "skybrowsermodule_lua.inl" -#include // For sleep + +#include // For atan2 +#include // formatJson namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = @@ -122,25 +121,18 @@ void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); _testProperty = p.test.value_or(_testProperty); _zoomFactor = p.zoom.value_or(_zoomFactor); - /* - auto fBrowser = FactoryManager::ref().factory(); - ghoul_assert(fBrowser, "No browser factory existed :'-("); - fBrowser->registerClass("ScreenSpaceBrowser"); - */ } -bool SkybrowserModule::sendMessageToWWT(const std::string& msg) { - ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - if (browser) { - std::string script = "sendMessageToWWT(" + msg + ");"; - browser->executeJavascript(script); +bool SkybrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { + if (_skyBrowser) { + std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; + _skyBrowser->executeJavascript(script); return true; } else { LERROR("No sky browser added! Can't send message."); return false; } - } void SkybrowserModule::WWTfollowCamera() { @@ -150,24 +142,31 @@ void SkybrowserModule::WWTfollowCamera() { // Convert to celestial coordinates glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); - std::string message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); sendMessageToWWT(message); - Sleep(50); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } -std::string SkybrowserModule::createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly) const { - std::string moveInstString = moveInstantly ? "true" : "false"; - std::string script = "{ event: 'center_on_coordinates' , ra: " + std::to_string(celestCoords[0]) + ", dec : " + std::to_string(celestCoords[1]) + ", fov: " + std::to_string(_zoomFactor) + ", instant: " + moveInstString +"}"; +ghoul::Dictionary SkybrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("ra", static_cast(celestCoords[0])); + msg.setValue("dec", static_cast(celestCoords[1])); + msg.setValue("fov", static_cast(fov)); + msg.setValue("instant", moveInstantly); - return script; + return msg; } -std::string SkybrowserModule::createMessageForPausingWWTTime() const { - std::string script = "{ event: 'pause_time'}"; +ghoul::Dictionary SkybrowserModule::createMessageForPausingWWTTime() const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "pause_time"s); - return script; + return msg; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 3bd26fe04f..d28ec931b8 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -48,10 +48,10 @@ public: glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera(); - std::string createMessageForMovingWWTCamera(glm::dvec2 celestCoords, float fov, bool moveInstantly = true) const; - std::string createMessageForPausingWWTTime() const; + ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; + ghoul::Dictionary createMessageForPausingWWTTime() const; - bool sendMessageToWWT(const std::string& msg); + bool sendMessageToWWT(const ghoul::Dictionary& msg); void initializeBrowser(ScreenSpaceBrowser* skyBrowser_); ScreenSpaceBrowser* skyBrowser(); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 212e506483..567c53c809 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -33,8 +33,8 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkybrowserModule* module = global::moduleEngine->module(); - std::string message = module->createMessageForPausingWWTTime(); - module->sendMessageToWWT(message); + //ghoul::Dictionary message = module->createMessageForPausingWWTTime(); + //module->sendMessageToWWT(message); std::thread thread(&SkybrowserModule::WWTfollowCamera, module); thread.detach(); From 1eb29ab5ca9d3fe2e86d65e02dd3a7b4408bd2d9 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 5 Mar 2021 15:33:48 +0100 Subject: [PATCH 012/251] Add centered target frame --- modules/skybrowser/skybrowsermodule.cpp | 24 ++++++++++++++++++ modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 19 +++++++++----- modules/skybrowser/target.png | Bin 0 -> 2506 bytes .../webbrowser/include/screenspacebrowser.h | 1 - modules/webbrowser/src/screenspacebrowser.cpp | 4 --- 6 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 modules/skybrowser/target.png diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1f87b99aea..01ca83bd3d 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -25,7 +25,11 @@ #include //#include //#include +#include +#include +#include +#include #include #include @@ -138,6 +142,7 @@ void SkybrowserModule::WWTfollowCamera() const { const SkybrowserModule* module = global::moduleEngine->module(); glm::dvec2 celestCoords = module->convertGalacticToCelestial(viewDirection); + showTarget(); // Execute javascript on browser ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); std::string script = "window.frames[0].postMessage({event: 'center_on_coordinates', ra : Number(" + std::to_string(celestCoords[0]) + "), dec : Number(" + std::to_string(celestCoords[1]) + "), fov : Number(" + std::to_string(_zoomFactor) + "), instant : false})"; @@ -163,6 +168,25 @@ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } +void SkybrowserModule::showTarget() const{ + + using namespace std::string_literals; + + + ghoul::Dictionary node; + node.setValue("Type", "ScreenSpaceImageLocal"s); + node.setValue("Identifier", "Target"s); + node.setValue("TexturePath", "D:/Esters/OpenSpace/modules/skybrowser/target.png"s); + node.setValue("Scale", 0.07); + + + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); + +} + /* std::vector SkybrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 8c02482383..b46e74544b 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -48,7 +48,7 @@ public: float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera() const; - + void showTarget() const; scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index d43d89fa6b..979edfe13f 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -31,7 +31,6 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); const SkybrowserModule* module = global::moduleEngine->module(); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - module->WWTfollowCamera(); return 1; } @@ -39,7 +38,6 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - browser->setFaceCameraPropertyToFalse(); browser->translate(glm::vec3(-0.8, -0.4, 0.0)); return 1; } @@ -50,22 +48,29 @@ namespace openspace::skybrowser::luascriptfunctions { const SkybrowserModule* module = global::moduleEngine->module(); - //std::string _url = "https://wallpaperaccess.com/full/3010132.jpg"; - // 'https://cdn.wallpapersafari.com/6/92/0nbCPw.jpg' - using namespace std::string_literals; + std::string node = "{" + "Type = 'ScreenSpaceBrowser'," + "Identifier = 'ScreenSpaceBowser'," + "Name = 'Screen Space Bowser'," + "Url = 'http://localhost:8000/'," + "FaceCamera = false" + "}"; + + /* ghoul::Dictionary node; node.setValue("Type", "ScreenSpaceBrowser"s); node.setValue("Identifier", "ScreenSpaceBowser"s); node.setValue("Name", "Screen Space Bowser"s); node.setValue("Url", "http://localhost:8000/"s); - // node.setValue("Dimensions", "glm::ivec2(1000, 1000)"); + */ openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", + "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); + return 1; } diff --git a/modules/skybrowser/target.png b/modules/skybrowser/target.png new file mode 100644 index 0000000000000000000000000000000000000000..2db4325598d0b5a39820d159e07258aa7e98fed7 GIT binary patch literal 2506 zcmeAS@N?(olHy`uVBq!ia0y~yVA=u1CLC-)k#C!#dVmyTage(c!@6@aFM%AEbVpxD z28NCO+M1MG8 z`1?6esq_GErx;MMitY T?!v{fAOk&J{an^LB{Ts5>xHg5 literal 0 HcmV?d00001 diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index f9c35beec6..514d989043 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -74,7 +74,6 @@ public: void executeJavascript(std::string &script) const; void translate(glm::vec3 translation); - void setFaceCameraPropertyToFalse(); private: class ScreenSpaceRenderHandler : public WebRenderHandler { diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index c21d36ed7d..dcdee6a601 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -71,10 +71,6 @@ void ScreenSpaceBrowser::translate(glm::vec3 translation) { _cartesianPosition = glm::translate(glm::mat4(1.f), translation) * glm::vec4(position, 1.0f); } -void ScreenSpaceBrowser::setFaceCameraPropertyToFalse() { - _faceCamera = false; -} - void ScreenSpaceBrowser::ScreenSpaceRenderHandler::draw() {} void ScreenSpaceBrowser::ScreenSpaceRenderHandler::render() {} From af98784dc40cbc2f2821b2513968c2bf75c06c57 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 5 Mar 2021 16:00:04 +0100 Subject: [PATCH 013/251] Add call to showtarget function --- modules/skybrowser/skybrowsermodule.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f6d9fa6a72..29db7a7461 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -146,6 +146,7 @@ bool SkybrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { } void SkybrowserModule::WWTfollowCamera() { + showTarget(); while (true) { // Get camera view direction const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); From 72a6b3623d0b1cc75d881046f1317348063c7058 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 8 Mar 2021 08:46:57 +0100 Subject: [PATCH 014/251] Add message for loading images and functionality to show a target --- modules/skybrowser/skybrowsermodule.cpp | 32 +++++++++++++++++++++ modules/skybrowser/skybrowsermodule.h | 2 ++ modules/skybrowser/skybrowsermodule_lua.inl | 15 +++++++--- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index c7ab21c939..e366164d11 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -107,6 +107,14 @@ scripting::LuaLibrary SkybrowserModule::luaLibrary() const { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "loacImgCollection", + &skybrowser::luascriptfunctions::loadImgCollection, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" } }; @@ -161,6 +169,17 @@ ghoul::Dictionary SkybrowserModule::createMessageForMovingWWTCamera(const glm::d return msg; } +ghoul::Dictionary SkybrowserModule::createMessageForLoadingWWTImgColl(const std::string& url) const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("url", url); + + return msg; +} + + + ghoul::Dictionary SkybrowserModule::createMessageForPausingWWTTime() const { using namespace std::string_literals; ghoul::Dictionary msg; @@ -197,6 +216,19 @@ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } +void SkybrowserModule::showTarget() const { + using namespace std::string_literals; + ghoul::Dictionary node; + node.setValue("Type", "ScreenSpaceImageLocal"s); + node.setValue("Identifier", "Target"s); + node.setValue("TexturePath", "D:/Ylvas/OpenSpace/modules/skybrowser/target.png"s); + node.setValue("Scale", 0.07); + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + /* std::vector SkybrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index d28ec931b8..6a19dc9ced 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -47,9 +47,11 @@ public: float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera(); + void showTarget() const; ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; + ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; bool sendMessageToWWT(const ghoul::Dictionary& msg); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 567c53c809..a6895ca109 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -28,6 +28,15 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { + + int loadImgCollection(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); + // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml + std::string url = ghoul::lua::value(L, 1); + SkybrowserModule* module = global::moduleEngine->module(); + module->sendMessageToWWT(module->createMessageForLoadingWWTImgColl(url)); + return 1; + } int followCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); @@ -35,6 +44,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkybrowserModule* module = global::moduleEngine->module(); //ghoul::Dictionary message = module->createMessageForPausingWWTTime(); //module->sendMessageToWWT(message); + module->showTarget(); std::thread thread(&SkybrowserModule::WWTfollowCamera, module); thread.detach(); @@ -48,7 +58,6 @@ namespace openspace::skybrowser::luascriptfunctions { SkybrowserModule* module = global::moduleEngine->module(); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); module->initializeBrowser(browser); - //ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); module->skyBrowser()->setFaceCameraPropertyToFalse(); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); @@ -57,9 +66,7 @@ namespace openspace::skybrowser::luascriptfunctions { } int createBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::createBrowser"); - ghoul::lua::value(L, 1); - + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkybrowserModule* module = global::moduleEngine->module(); From c11b66173ee6f27ffa7402461e9bdc4d67d18dc4 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Mon, 8 Mar 2021 13:47:50 +0100 Subject: [PATCH 015/251] Create subclass of ScreenSpaceBrowser in SkyBrowserModule and change name of module Skybrowser to SkyBrowser --- modules/skybrowser/CMakeLists.txt | 4 +- .../include/screenspaceskybrowser.h | 22 +++++++++++ modules/skybrowser/skybrowsermodule.cpp | 36 ++++++++++------- modules/skybrowser/skybrowsermodule.h | 16 ++++---- modules/skybrowser/skybrowsermodule_lua.inl | 17 ++++---- .../skybrowser/src/screenspaceskybrowser.cpp | 39 +++++++++++++++++++ .../webbrowser/include/screenspacebrowser.h | 9 +++-- modules/webbrowser/src/screenspacebrowser.cpp | 15 +------ 8 files changed, 109 insertions(+), 49 deletions(-) create mode 100644 modules/skybrowser/include/screenspaceskybrowser.h create mode 100644 modules/skybrowser/src/screenspaceskybrowser.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 7157b0828f..cc22253a4d 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -27,6 +27,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES skybrowsermodule.h + include/screenspaceskybrowser.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -35,12 +36,13 @@ set(SOURCE_FILES skybrowsermodule.cpp skybrowsermodule_lua.inl + src/screenspaceskybrowser.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) create_new_module( - "Skybrowser" + "SkyBrowser" skybrowser_module STATIC ${HEADER_FILES} ${SOURCE_FILES} diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h new file mode 100644 index 0000000000..0e7e600d25 --- /dev/null +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -0,0 +1,22 @@ +#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ + +#include + +namespace openspace { + + class ScreenSpaceSkyBrowser : public ScreenSpaceBrowser + { + public: + ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); + virtual ~ScreenSpaceSkyBrowser() = default; + void executeJavascript(std::string& script) const; + void translate(glm::vec3 translation); + private: + + + }; +} + +#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ + diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 29db7a7461..264ce2f9e7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -62,7 +62,7 @@ namespace { "tjobidabidobidabidopp plupp" }; - struct [[codegen::Dictionary(SkybrowserModule)]] Parameters { + struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { // [[codegen::verbatim(TestInfo.description)]] std::optional test; @@ -78,8 +78,8 @@ namespace { namespace openspace { -SkybrowserModule::SkybrowserModule() - : OpenSpaceModule(Name) +SkyBrowserModule::SkyBrowserModule() + : OpenSpaceModule(SkyBrowserModule::Name) , _testProperty(TestInfo) , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) @@ -90,7 +90,7 @@ SkybrowserModule::SkybrowserModule() -scripting::LuaLibrary SkybrowserModule::luaLibrary() const { +scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { scripting::LuaLibrary res; res.name = "skybrowser"; res.functions = { @@ -123,17 +123,23 @@ scripting::LuaLibrary SkybrowserModule::luaLibrary() const { return res; } -float SkybrowserModule::zoomFactor() const{ +float SkyBrowserModule::zoomFactor() const{ return _zoomFactor; } -void SkybrowserModule::internalInitialize(const ghoul::Dictionary& dict) { +void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { + const Parameters p = codegen::bake(dict); _testProperty = p.test.value_or(_testProperty); _zoomFactor = p.zoom.value_or(_zoomFactor); + + // register ScreenSpaceBrowser + auto fScreenSpaceRenderable = FactoryManager::ref().factory(); + ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); + fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); } -bool SkybrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { +bool SkyBrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { if (_skyBrowser) { std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; _skyBrowser->executeJavascript(script); @@ -145,7 +151,7 @@ bool SkybrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { } } -void SkybrowserModule::WWTfollowCamera() { +void SkyBrowserModule::WWTfollowCamera() { showTarget(); while (true) { // Get camera view direction @@ -160,7 +166,7 @@ void SkybrowserModule::WWTfollowCamera() { } } -ghoul::Dictionary SkybrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { +ghoul::Dictionary SkyBrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "center_on_coordinates"s); @@ -172,7 +178,7 @@ ghoul::Dictionary SkybrowserModule::createMessageForMovingWWTCamera(const glm::d return msg; } -ghoul::Dictionary SkybrowserModule::createMessageForPausingWWTTime() const { +ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "pause_time"s); @@ -181,15 +187,15 @@ ghoul::Dictionary SkybrowserModule::createMessageForPausingWWTTime() const { } -void SkybrowserModule::initializeBrowser(ScreenSpaceBrowser* skyBrowser) { +void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser) { _skyBrowser = skyBrowser; } -ScreenSpaceBrowser* SkybrowserModule::skyBrowser() { +ScreenSpaceSkyBrowser* SkyBrowserModule::skyBrowser() { return _skyBrowser; } -glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { +glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 @@ -208,7 +214,7 @@ glm::dvec2 SkybrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } -void SkybrowserModule::showTarget() const{ +void SkyBrowserModule::showTarget() const{ using namespace std::string_literals; @@ -228,7 +234,7 @@ void SkybrowserModule::showTarget() const{ } /* -std::vector SkybrowserModule::documentations() const { +std::vector SkyBrowserModule::documentations() const { return { ExoplanetsDataPreparationTask::documentation(), RenderableOrbitDisc::Documentation() diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index ade40d7c8d..80c10e010e 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -35,14 +35,14 @@ namespace openspace { -class ScreenSpaceBrowser; +class ScreenSpaceSkyBrowser; -class SkybrowserModule : public OpenSpaceModule { +class SkyBrowserModule : public OpenSpaceModule { public: - constexpr static const char* Name = "Skybrowser"; + constexpr static const char* Name = "SkyBrowser"; - SkybrowserModule(); - virtual ~SkybrowserModule() = default; + SkyBrowserModule(); + virtual ~SkyBrowserModule() = default; float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; @@ -55,8 +55,8 @@ public: bool sendMessageToWWT(const ghoul::Dictionary& msg); - void initializeBrowser(ScreenSpaceBrowser* skyBrowser_); - ScreenSpaceBrowser* skyBrowser(); + void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser_); + ScreenSpaceSkyBrowser* skyBrowser(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -65,7 +65,7 @@ protected: properties::StringProperty _testProperty; properties::FloatProperty _zoomFactor; - ScreenSpaceBrowser* _skyBrowser; + ScreenSpaceSkyBrowser* _skyBrowser; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 5a91cbecf3..3aebd2c9b2 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -16,14 +17,14 @@ #include #include #include -#include +#include #include #include #include namespace { - constexpr const char _loggerCat[] = "SkybrowserModule"; + constexpr const char _loggerCat[] = "SkyBrowserModule"; } // namespace @@ -32,10 +33,10 @@ namespace openspace::skybrowser::luascriptfunctions { int followCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); - SkybrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule* module = global::moduleEngine->module(); //ghoul::Dictionary message = module->createMessageForPausingWWTTime(); //module->sendMessageToWWT(message); - std::thread thread(&SkybrowserModule::WWTfollowCamera, module); + std::thread thread(&SkyBrowserModule::WWTfollowCamera, module); thread.detach(); return 1; @@ -44,8 +45,8 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - SkybrowserModule* module = global::moduleEngine->module(); - ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + SkyBrowserModule* module = global::moduleEngine->module(); + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); module->initializeBrowser(browser); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); @@ -57,13 +58,13 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::createBrowser"); ghoul::lua::value(L, 1); - SkybrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule* module = global::moduleEngine->module(); using namespace std::string_literals; std::string node = "{" - "Type = 'ScreenSpaceBrowser'," + "Type = 'ScreenSpaceSkyBrowser'," "Identifier = 'ScreenSpaceBowser'," "Name = 'Screen Space Bowser'," "Url = 'http://localhost:8000/'," diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp new file mode 100644 index 0000000000..c866942b23 --- /dev/null +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +namespace { + constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; + +} // namespace + +namespace openspace { + ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) + : ScreenSpaceBrowser(dictionary) + { + std::string identifier; + if (dictionary.hasValue(KeyIdentifier)) { + identifier = dictionary.value(KeyIdentifier); + } + else { + identifier = "ScreenSpaceSkyBrowser"; + } + identifier = makeUniqueIdentifier(identifier); + setIdentifier(identifier); + + } + void ScreenSpaceSkyBrowser::executeJavascript(std::string& script) const { + //LINFOC(_loggerCat, "Executing javascript " + script); + + CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); + frame->ExecuteJavaScript(script, frame->GetURL(), 0); + } + + void ScreenSpaceSkyBrowser::translate(glm::vec3 translation) { + glm::vec4 homogenousCoords(glm::vec4(translation, 1.0)); + glm::vec3 position = _cartesianPosition; + _cartesianPosition = glm::translate(glm::mat4(1.f), translation) * glm::vec4(position, 1.0f); + } +} diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 514d989043..ccac47ef7e 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -72,9 +72,9 @@ public: void update() override; bool isReady() const override; - void executeJavascript(std::string &script) const; - void translate(glm::vec3 translation); - +protected: + + std::unique_ptr _browserInstance; private: class ScreenSpaceRenderHandler : public WebRenderHandler { public: @@ -92,7 +92,8 @@ private: CefRefPtr _renderHandler; CefRefPtr _keyboardHandler; - std::unique_ptr _browserInstance; + + std::unique_ptr _texture; bool _isUrlDirty = false; diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 5ee9cd6fb3..3fee79258b 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -58,19 +58,6 @@ namespace { namespace openspace { -void ScreenSpaceBrowser::executeJavascript(std::string &script) const { - //LINFOC(_loggerCat, "Executing javascript " + script); - - CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - frame->ExecuteJavaScript(script, frame->GetURL(), 0); -} - -void ScreenSpaceBrowser::translate(glm::vec3 translation) { - glm::vec4 homogenousCoords(glm::vec4(translation, 1.0)); - glm::vec3 position = _cartesianPosition; - _cartesianPosition = glm::translate(glm::mat4(1.f), translation) * glm::vec4(position, 1.0f); -} - void ScreenSpaceBrowser::ScreenSpaceRenderHandler::draw() {} void ScreenSpaceBrowser::ScreenSpaceRenderHandler::render() {} @@ -79,6 +66,7 @@ void ScreenSpaceBrowser::ScreenSpaceRenderHandler::setTexture(GLuint t) { _texture = t; } + ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) : ScreenSpaceRenderable(dictionary) , _url(UrlInfo) @@ -160,6 +148,7 @@ bool ScreenSpaceBrowser::deinitializeGL() { return ScreenSpaceRenderable::deinitializeGL(); } + void ScreenSpaceBrowser::render() { if (!_renderHandler->isTextureReady()) { return; From fce49cf4ec411807ba8a9be5e02b0900b3bd294e Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Mon, 8 Mar 2021 14:03:00 +0100 Subject: [PATCH 016/251] Change from SkybrowserModule to SkyBrowserModule in lua function --- modules/skybrowser/skybrowsermodule.h | 1 - modules/skybrowser/skybrowsermodule_lua.inl | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index b290aea906..3f46cd8a59 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -47,7 +47,6 @@ public: float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; - void showTarget() const; void WWTfollowCamera(); void showTarget() const; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 224d8b9ba4..07ac781831 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -34,7 +34,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml std::string url = ghoul::lua::value(L, 1); - SkybrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule* module = global::moduleEngine->module(); module->sendMessageToWWT(module->createMessageForLoadingWWTImgColl(url)); return 1; } From 8ac85466e73a0a75fca40c1afe87621dd7d9bd9c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 8 Mar 2021 15:53:45 +0100 Subject: [PATCH 017/251] Make thread be joined, not detached, and run depending on a flag --- modules/skybrowser/skybrowsermodule.cpp | 45 +++++++++++++------ modules/skybrowser/skybrowsermodule.h | 5 ++- modules/skybrowser/skybrowsermodule_lua.inl | 10 +++-- modules/webbrowser/src/screenspacebrowser.cpp | 12 +++-- 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 41d258a2ba..8040708418 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -83,13 +83,20 @@ SkybrowserModule::SkybrowserModule() , _testProperty(TestInfo) , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) + , _camIsSyncedWWT(true) { addProperty(_testProperty); addProperty(_zoomFactor); +} + +void SkybrowserModule::internalDeinitialize() { + ZoneScoped + // Set flag to false so the thread can exit + _camIsSyncedWWT = false; + _thread.join(); + LINFO("Joined thread"); } - - scripting::LuaLibrary SkybrowserModule::luaLibrary() const { scripting::LuaLibrary res; res.name = "skybrowser"; @@ -155,17 +162,31 @@ bool SkybrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { void SkybrowserModule::WWTfollowCamera() { showTarget(); - while (true) { - // Get camera view direction - const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + //std::thread(&SkybrowserModule::WWTfollowCamera, module) - // Convert to celestial coordinates - glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); + // Start a thread to enable user interaction while sending the calls to WWT + _thread = std::thread([&] { + while (_camIsSyncedWWT) { - sendMessageToWWT(message); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } + // Get camera view direction + const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + + // Convert to celestial coordinates + glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); + if (!_camIsSyncedWWT) { + break; + } + else { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + sendMessageToWWT(message); + } + LINFO("Thread running... " + std::to_string(_camIsSyncedWWT)); + + } + LINFO("Thread finished... " + std::to_string(_camIsSyncedWWT)); + }); + } ghoul::Dictionary SkybrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { @@ -189,8 +210,6 @@ ghoul::Dictionary SkybrowserModule::createMessageForLoadingWWTImgColl(const std: return msg; } - - ghoul::Dictionary SkybrowserModule::createMessageForPausingWWTTime() const { using namespace std::string_literals; ghoul::Dictionary msg; diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 9050906d64..edac11e481 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace openspace { @@ -47,7 +48,6 @@ public: float zoomFactor() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; - void showTarget() const; void WWTfollowCamera(); void showTarget() const; @@ -64,10 +64,13 @@ public: protected: void internalInitialize(const ghoul::Dictionary& dict) override; + void internalDeinitialize() override; properties::StringProperty _testProperty; properties::FloatProperty _zoomFactor; ScreenSpaceBrowser* _skyBrowser; + bool _camIsSyncedWWT; + std::thread _thread; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 301ca5e4a1..915893c5ef 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -45,8 +45,8 @@ namespace openspace::skybrowser::luascriptfunctions { //ghoul::Dictionary message = module->createMessageForPausingWWTTime(); //module->sendMessageToWWT(message); module->showTarget(); - std::thread thread(&SkybrowserModule::WWTfollowCamera, module); - thread.detach(); + module->WWTfollowCamera(); + return 1; } @@ -54,9 +54,10 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - SkybrowserModule* module = global::moduleEngine->module(); + SkybrowserModule* module = global::moduleEngine->module(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); ScreenSpaceBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - module->initializeBrowser(browser); + module->initializeBrowser(browser); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); return 1; @@ -90,6 +91,7 @@ namespace openspace::skybrowser::luascriptfunctions { "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); + return 1; } diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 5ee9cd6fb3..2253f80c1e 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -58,11 +58,17 @@ namespace { namespace openspace { -void ScreenSpaceBrowser::executeJavascript(std::string &script) const { +void ScreenSpaceBrowser::executeJavascript(std::string& script) const { //LINFOC(_loggerCat, "Executing javascript " + script); + CefRefPtr frame; + if (_browserInstance && _browserInstance->getBrowser()) { + frame = _browserInstance->getBrowser()->GetMainFrame(); + if (frame) { + frame->ExecuteJavaScript(script, frame->GetURL(), 0); + } + } - CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - frame->ExecuteJavaScript(script, frame->GetURL(), 0); + } void ScreenSpaceBrowser::translate(glm::vec3 translation) { From 0be1f8d48d67d3219f030fdef655efd6bc3bc73e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 8 Mar 2021 16:29:33 +0100 Subject: [PATCH 018/251] Add check for joining thread so it is joinable --- modules/skybrowser/skybrowsermodule.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f79b0280f3..a19b6bff89 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -90,11 +90,13 @@ SkyBrowserModule::SkyBrowserModule() } void SkyBrowserModule::internalDeinitialize() { - ZoneScoped - // Set flag to false so the thread can exit + // Set flag to false so the thread can exit _camIsSyncedWWT = false; - _thread.join(); - LINFO("Joined thread"); + if (_thread.joinable()) { + _thread.join(); + LINFO("Joined thread"); + } + } scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { From c32c1fff6a63dda9598e08c78921e0f4907ea2a9 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 09:23:10 +0100 Subject: [PATCH 019/251] Add functionality to drag skybrowser --- .../include/screenspaceskybrowser.h | 9 +- modules/skybrowser/skybrowsermodule.cpp | 89 +++++++++++++---- modules/skybrowser/skybrowsermodule.h | 13 ++- modules/skybrowser/skybrowsermodule_lua.inl | 5 +- .../skybrowser/src/screenspaceskybrowser.cpp | 95 ++++++++++++++++++- .../webbrowser/include/screenspacebrowser.h | 4 +- 6 files changed, 185 insertions(+), 30 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 0e7e600d25..492fe8b819 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -11,7 +11,14 @@ namespace openspace { ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyBrowser() = default; void executeJavascript(std::string& script) const; - void translate(glm::vec3 translation); + void translate(glm::vec2 translation); + void translate(glm::vec2 translation, glm::vec2 position); + glm::vec2 getScreenSpacePosition(); + glm::vec2 getScreenSpaceDimensions(); + void sendMouseEvent(CefStructBase event, int x, int y) const; + glm::vec2 getUpperRightCornerScreenSpace(); + glm::vec2 getLowerLeftCornerScreenSpace(); + bool coordIsInsideBrowserScreenSpace(glm::vec2 coord); private: diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index a19b6bff89..fecf4da51f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,8 @@ #include // For atan2 #include // formatJson +#include + namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = @@ -84,19 +87,32 @@ SkyBrowserModule::SkyBrowserModule() , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) , _camIsSyncedWWT(true) + , mouseIsClickedPreviously(false) + , _listenForInteractions(true) { addProperty(_testProperty); addProperty(_zoomFactor); + + createTarget(); + + global::callback::mousePosition->emplace_back( + [&](double x, double y) { + _mousePosition = glm::vec2(static_cast(x), static_cast(y)); + } + ); } void SkyBrowserModule::internalDeinitialize() { // Set flag to false so the thread can exit _camIsSyncedWWT = false; - if (_thread.joinable()) { - _thread.join(); + if (_threadWWTMessages.joinable()) { + _threadWWTMessages.join(); + LINFO("Joined thread"); + } + if (_threadHandleInteractions.joinable()) { + _threadHandleInteractions.join(); LINFO("Joined thread"); } - } scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { @@ -169,12 +185,56 @@ bool SkyBrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { } } -void SkyBrowserModule::WWTfollowCamera() { - showTarget(); - //std::thread(&SkyBrowserModule::WWTfollowCamera, module) +void SkyBrowserModule::handleInteractions() { + /* + float scroll = global::navigationHandler->inputState().mouseScrollDelta(); + bool mouseIsOverBrowser = _skyBrowser->coordIsInsideBrowserScreenSpace(getMousePositionInScreenSpaceCoords()); + LINFO(std::to_string(mouseIsOverBrowser)); + + _zoomFactor = std::clamp(_zoomFactor - scroll, 0.001f, 70.0f); + CefStructBase event; + _skyBrowser->sendMouseEvent(event, scroll, scroll); + */ + _threadHandleInteractions = std::thread([&] { + while (_listenForInteractions) { + bool mouseIsClicked = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Left); + if (mouseIsClicked) { + dragBrowser(); + } + else { + mouseIsClickedPreviously = false; + } + } + }); +} + +glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords() { + glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); + + // Transform pixel coordinates to screen space coordinates [-1,1] + return glm::vec2((_mousePosition - (size / 2.0f)) * glm::vec2(1.0f,-1.0f) / (size / 2.0f)); +} + +void SkyBrowserModule::dragBrowser() { + // First click on browser - user is not holding down the button since last frame + glm::dvec2 mouseCoords = getMousePositionInScreenSpaceCoords(); + bool mouseIsOnBrowser = _skyBrowser->coordIsInsideBrowserScreenSpace(mouseCoords); + + if (mouseIsOnBrowser && !mouseIsClickedPreviously) { + mouseIsClickedPreviously = true; + startDragMousePos = mouseCoords; + startDragObjectPos = _skyBrowser->getScreenSpacePosition(); + } + else if (mouseIsClickedPreviously) { + _skyBrowser->translate(mouseCoords - startDragMousePos, startDragObjectPos); + } +} + +void SkyBrowserModule::WWTfollowCamera() { + // Start a thread to enable user interaction while sending the calls to WWT - _thread = std::thread([&] { + _threadWWTMessages = std::thread([&] { while (_camIsSyncedWWT) { // Get camera view direction @@ -183,17 +243,12 @@ void SkyBrowserModule::WWTfollowCamera() { // Convert to celestial coordinates glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); - if (!_camIsSyncedWWT) { - break; - } - else { - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - sendMessageToWWT(message); - } - LINFO("Thread running... " + std::to_string(_camIsSyncedWWT)); + // Sleep so we don't bombard WWT with too many messages + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + sendMessageToWWT(message); + } - LINFO("Thread finished... " + std::to_string(_camIsSyncedWWT)); }); } @@ -256,7 +311,7 @@ glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } -void SkyBrowserModule::showTarget() const { +void SkyBrowserModule::createTarget() { using namespace std::string_literals; ghoul::Dictionary node; diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 0545e688f2..8991faf503 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -49,13 +49,16 @@ public: glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera(); - void showTarget() const; + void createTarget(); ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; bool sendMessageToWWT(const ghoul::Dictionary& msg); + void handleInteractions(); + glm::vec2 getMousePositionInScreenSpaceCoords(); + void dragBrowser(); void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser_); ScreenSpaceSkyBrowser* skyBrowser(); @@ -70,7 +73,13 @@ protected: properties::FloatProperty _zoomFactor; ScreenSpaceSkyBrowser* _skyBrowser; bool _camIsSyncedWWT; - std::thread _thread; + bool _listenForInteractions; + std::thread _threadWWTMessages; + std::thread _threadHandleInteractions; + glm::dvec2 startDragMousePos; + glm::dvec2 startDragObjectPos; + bool mouseIsClickedPreviously; + glm::vec2 _mousePosition; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index ff1ab53571..8c86e7c96a 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -46,6 +46,7 @@ namespace openspace::skybrowser::luascriptfunctions { //ghoul::Dictionary message = module->createMessageForPausingWWTTime(); //module->sendMessageToWWT(message); module->WWTfollowCamera(); + module->handleInteractions(); return 1; } @@ -62,7 +63,6 @@ namespace openspace::skybrowser::luascriptfunctions { } int createBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); @@ -83,14 +83,11 @@ namespace openspace::skybrowser::luascriptfunctions { node.setValue("Identifier", "ScreenSpaceBowser"s); node.setValue("Name", "Screen Space Bowser"s); node.setValue("Url", "http://localhost:8000/"s); - */ - openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index dbb0bf12f6..5e3ffdfa3b 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -3,6 +3,18 @@ #include #include #include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -33,9 +45,84 @@ namespace openspace { } - void ScreenSpaceSkyBrowser::translate(glm::vec3 translation) { - glm::vec4 homogenousCoords(glm::vec4(translation, 1.0)); - glm::vec3 position = _cartesianPosition; - _cartesianPosition = glm::translate(glm::mat4(1.f), translation) * glm::vec4(position, 1.0f); + void ScreenSpaceSkyBrowser::sendMouseEvent(CefStructBase event, int x, int y) const { + //LINFOC(_loggerCat, "Executing javascript " + script); + LINFO(std::to_string(_objectSize.x) + " " + std::to_string(_objectSize.y)); + if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetHost()) { + + //_browserInstance->getBrowser()->GetHost()->SendMouseWheelEvent(event, x, y); + //LINFOC(_loggerCat, "Sending scroll"); + + } + } + + void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { + + glm::vec3 position = _cartesianPosition; + + _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); + } + + void ScreenSpaceSkyBrowser::translate(glm::vec2 translation, glm::vec2 position) { + + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + windowRatio /= windowRatio.y; + + _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation * windowRatio, 0.0f)) * glm::vec4(position * windowRatio, _cartesianPosition.value().z, 1.0f); + } + + glm::vec2 ScreenSpaceSkyBrowser::getScreenSpacePosition() { + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * + localRotationMatrix() * scaleMatrix(); + glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); + glm::mat4 screenSpaceTransform = viewProj * modelTransform; + + glm::vec3 scale; + glm::quat rotation; + glm::vec3 translation; + glm::vec3 skew; + glm::vec4 perspective; + glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); + + return translation; + } + + glm::vec2 ScreenSpaceSkyBrowser::getScreenSpaceDimensions() { + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * + localRotationMatrix() * scaleMatrix(); + glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); + glm::mat4 screenSpaceTransform = viewProj * modelTransform; + + + glm::vec3 scale; + glm::quat rotation; + glm::vec3 translation; + glm::vec3 skew; + glm::vec4 perspective; + glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); + + // Scale is negative and relative to the whole screen + // Changing to positive and View Coordinates [-1,1] + // E.g. a full screen screenspacebrowser will have [2,2] + scale = -2.0f * scale; + + return scale; + } + + glm::vec2 ScreenSpaceSkyBrowser::getUpperRightCornerScreenSpace() { + + return getScreenSpacePosition() + (getScreenSpaceDimensions()/2.0f); + } + + glm::vec2 ScreenSpaceSkyBrowser::getLowerLeftCornerScreenSpace() { + return getScreenSpacePosition() - (getScreenSpaceDimensions()/2.0f); + } + + bool ScreenSpaceSkyBrowser::coordIsInsideBrowserScreenSpace(glm::vec2 coord) { + bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; + bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; + return lessThanUpperRight && moreThanLowerLeft; + } + } diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index ccac47ef7e..d3f0cc4063 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -73,7 +73,7 @@ public: bool isReady() const override; protected: - + properties::Vec2Property _dimensions; std::unique_ptr _browserInstance; private: class ScreenSpaceRenderHandler : public WebRenderHandler { @@ -87,7 +87,7 @@ private: void bindTexture() override; properties::StringProperty _url; - properties::Vec2Property _dimensions; + properties::TriggerProperty _reload; CefRefPtr _renderHandler; From 8a0e9e6ed0460f1a1924052a82e055e084fe6dbc Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Thu, 11 Mar 2021 10:04:53 +0100 Subject: [PATCH 020/251] Add ScreenSpaceSkyTarget class to handle target --- modules/skybrowser/CMakeLists.txt | 3 + .../include/screenspaceskybrowser.h | 1 - .../skybrowser/include/screenspaceskytarget.h | 29 ++++++++++ modules/skybrowser/shaders/target_fs.glsl | 17 ++++++ modules/skybrowser/shaders/target_vs.glsl | 16 ++++++ modules/skybrowser/skybrowsermodule.cpp | 44 +++++++++++---- modules/skybrowser/skybrowsermodule.h | 6 +- modules/skybrowser/skybrowsermodule_lua.inl | 8 ++- .../skybrowser/src/screenspaceskytarget.cpp | 56 +++++++++++++++++++ 9 files changed, 165 insertions(+), 15 deletions(-) create mode 100644 modules/skybrowser/include/screenspaceskytarget.h create mode 100644 modules/skybrowser/shaders/target_fs.glsl create mode 100644 modules/skybrowser/shaders/target_vs.glsl create mode 100644 modules/skybrowser/src/screenspaceskytarget.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index cc22253a4d..ae29dbfdfc 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADER_FILES skybrowsermodule.h include/screenspaceskybrowser.h + include/screenspaceskytarget.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -37,6 +38,8 @@ set(SOURCE_FILES skybrowsermodule.cpp skybrowsermodule_lua.inl src/screenspaceskybrowser.cpp + src/screenspaceskytarget.cpp + ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 0e7e600d25..72cccd17b4 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -14,7 +14,6 @@ namespace openspace { void translate(glm::vec3 translation); private: - }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h new file mode 100644 index 0000000000..7a923e0838 --- /dev/null +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -0,0 +1,29 @@ +#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ + +#include + +#include +#include + +#include + +namespace openspace::documentation { struct Documentation; } + +namespace openspace { + + class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { + + public: + ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); + virtual ~ScreenSpaceSkyTarget() = default; + + void bindTexture() override; + private: + std::unique_ptr _texture; + + }; +} + +#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ + diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl new file mode 100644 index 0000000000..260888d8f8 --- /dev/null +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -0,0 +1,17 @@ +uniform sampler2D texture1; +uniform float OcclusionDepth; +uniform float Alpha; + +in vec2 vs_st; +in vec4 vs_position; + +#include "fragment.glsl" + +Fragment getFragment() { + Fragment frag; + + vec3 color = vec3(1.0); + frag.color = vec4(color, 1.0); + + return frag; +} \ No newline at end of file diff --git a/modules/skybrowser/shaders/target_vs.glsl b/modules/skybrowser/shaders/target_vs.glsl new file mode 100644 index 0000000000..316cc5adb8 --- /dev/null +++ b/modules/skybrowser/shaders/target_vs.glsl @@ -0,0 +1,16 @@ +#version __CONTEXT__ + +uniform mat4 ModelTransform; +uniform mat4 ViewProjectionMatrix; + +layout(location = 0) in vec4 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; +out vec4 vs_position; + +void main(){ + vs_st = in_st; + vs_position = ViewProjectionMatrix * ModelTransform * in_position * vec4(1.0, -1.0, 1.0, 1.0); + gl_Position = vec4(vs_position); +} diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 642945b9f6..346ac28e6c 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -26,15 +26,12 @@ //#include //#include -#include #include #include -#include #include - #include #include #include @@ -45,6 +42,10 @@ #include #include "skybrowsermodule_lua.inl" +#include +#include +#include + #include // For atan2 #include // formatJson @@ -145,6 +146,11 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { auto fScreenSpaceRenderable = FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); + + // register ScreenSpaceTarget + ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); + fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); + } bool SkyBrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { @@ -160,7 +166,6 @@ bool SkyBrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { } void SkyBrowserModule::WWTfollowCamera() { - showTarget(); while (true) { // Get camera view direction const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); @@ -232,20 +237,37 @@ glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } -void SkyBrowserModule::showTarget() const { +void SkyBrowserModule::checkIfTargetExist() { + ScreenSpaceSkyTarget* target = static_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); + + if (target) { + LINFO("Target is not null!"); + + } + LINFO("Target has been checked!"); +} + +void SkyBrowserModule::createTarget() { using namespace std::string_literals; - ghoul::Dictionary node; - node.setValue("Type", "ScreenSpaceImageLocal"s); - node.setValue("Identifier", "Target"s); - node.setValue("TexturePath", "D:/Ylvas/OpenSpace/modules/skybrowser/target.png"s); - node.setValue("Scale", 0.07); + + // Create target test + std::string node = "{" + "Type = 'ScreenSpaceSkyTarget'," + "Identifier = 'ScreenSpaceTarget'," + "Name = 'Screen Space Target'," + "FaceCamera = false" + "}"; + openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + ghoul::formatLua(node) + ")", + "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); + } + + /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 3f46cd8a59..1332bf63b4 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -36,6 +36,7 @@ namespace openspace { class ScreenSpaceSkyBrowser; +class ScreenSpaceSkyTarget; class SkyBrowserModule : public OpenSpaceModule { public: @@ -48,7 +49,10 @@ public: glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera(); - void showTarget() const; + + // target + void createTarget(); + void checkIfTargetExist(); ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 07ac781831..240670d22b 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -61,14 +62,14 @@ namespace openspace::skybrowser::luascriptfunctions { module->initializeBrowser(browser); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); + module->checkIfTargetExist(); return 1; } int createBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::createBrowser"); - ghoul::lua::value(L, 1); + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); @@ -96,6 +97,9 @@ namespace openspace::skybrowser::luascriptfunctions { scripting::ScriptEngine::RemoteScripting::Yes ); + //test create target + module->createTarget(); + return 1; } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp new file mode 100644 index 0000000000..436403091f --- /dev/null +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -0,0 +1,56 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; + + constexpr const std::array UniformNames = { + "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" + }; + +} //namespace + +namespace openspace { + ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) + : ScreenSpaceRenderable(dictionary) + { + std::string identifier; + if (dictionary.hasValue(KeyIdentifier)) { + identifier = dictionary.value(KeyIdentifier); + } + else { + identifier = "ScreenSpaceSkyTarget"; + } + identifier = makeUniqueIdentifier(identifier); + setIdentifier(identifier); + } + + void ScreenSpaceSkyTarget::bindTexture() { + if (_texture) { + _texture->bind(); + } + } + +} From c16ee0698f29d1e5c0f9b67d5cbbfd623761afa3 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 11:40:55 +0100 Subject: [PATCH 021/251] Implement simple version of scroll --- modules/skybrowser/skybrowsermodule.cpp | 63 ++++++++++++++----- modules/skybrowser/skybrowsermodule.h | 16 +++-- modules/skybrowser/skybrowsermodule_lua.inl | 3 +- .../skybrowser/src/screenspaceskytarget.cpp | 19 ++++++ 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 475092d763..ce42ba3157 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -51,7 +51,6 @@ #include // formatJson #include - namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = { @@ -88,7 +87,7 @@ SkyBrowserModule::SkyBrowserModule() , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) , _camIsSyncedWWT(true) - , mouseIsClickedPreviously(false) + , mouseIsClickedPreviouslyLeft(false) , _listenForInteractions(true) { addProperty(_testProperty); @@ -98,7 +97,20 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mousePosition->emplace_back( [&](double x, double y) { - _mousePosition = glm::vec2(static_cast(x), static_cast(y)); + glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); + _mousePosition = getMousePositionInScreenSpaceCoords(pos); + if (_skyBrowser) { + mouseIsOnBrowser = _skyBrowser->coordIsInsideBrowserScreenSpace(_mousePosition); + } + + } + ); + + global::callback::mouseScrollWheel->emplace_back( + [&](double, double scroll) -> bool { + float zoom = scroll > 0.0 ? -2.0f : 2.0f; + _zoomFactor = std::clamp(_zoomFactor + zoom, 0.001f, 70.0f); + return true; } ); } @@ -203,37 +215,53 @@ void SkyBrowserModule::handleInteractions() { */ _threadHandleInteractions = std::thread([&] { while (_listenForInteractions) { - bool mouseIsClicked = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Left); + LINFO(std::to_string(_mouseScroll)); + bool mouseIsClickedLeft = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Left); + bool mouseIsClickedRight = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Right); - if (mouseIsClicked) { + if (mouseIsClickedLeft && !mouseIsClickedRight) { dragBrowser(); } else { - mouseIsClickedPreviously = false; + mouseIsClickedPreviouslyLeft = false; + } + if (mouseIsClickedRight && !mouseIsClickedLeft) { + moveTarget(); } } }); } -glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords() { +glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); // Transform pixel coordinates to screen space coordinates [-1,1] - return glm::vec2((_mousePosition - (size / 2.0f)) * glm::vec2(1.0f,-1.0f) / (size / 2.0f)); + return glm::vec2((mousePos - (size / 2.0f)) * glm::vec2(1.0f,-1.0f) / (size / 2.0f)); } void SkyBrowserModule::dragBrowser() { // First click on browser - user is not holding down the button since last frame - glm::dvec2 mouseCoords = getMousePositionInScreenSpaceCoords(); - bool mouseIsOnBrowser = _skyBrowser->coordIsInsideBrowserScreenSpace(mouseCoords); - - if (mouseIsOnBrowser && !mouseIsClickedPreviously) { - mouseIsClickedPreviously = true; - startDragMousePos = mouseCoords; + // glm::dvec2 mouseCoords = + if (mouseIsOnBrowser && !mouseIsClickedPreviouslyLeft) { + mouseIsClickedPreviouslyLeft = true; + startDragMousePos = _mousePosition; startDragObjectPos = _skyBrowser->getScreenSpacePosition(); } - else if (mouseIsClickedPreviously) { - _skyBrowser->translate(mouseCoords - startDragMousePos, startDragObjectPos); + else if (mouseIsClickedPreviouslyLeft) { + _skyBrowser->translate(_mousePosition - startDragMousePos, startDragObjectPos); + } +} + +void SkyBrowserModule::moveTarget() { + // First click on browser - user is not holding down the button since last frame + + if (mouseIsOnBrowser && !mouseIsClickedPreviouslyRight) { + mouseIsClickedPreviouslyRight = true; + startDragMousePos = _mousePosition; + // startDragObjectPos = _skyTarget->getScreenSpacePosition(); + } + else if (mouseIsClickedPreviouslyRight) { + // _skyTarget->translate(mouseCoords - startDragMousePos, startDragObjectPos); } } @@ -290,8 +318,9 @@ ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { } -void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser) { +void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget) { _skyBrowser = skyBrowser; + _skyTarget = skyTarget; } ScreenSpaceSkyBrowser* SkyBrowserModule::skyBrowser() { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index cd20b4f7fd..ca2860972c 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -61,10 +61,11 @@ public: bool sendMessageToWWT(const ghoul::Dictionary& msg); void handleInteractions(); - glm::vec2 getMousePositionInScreenSpaceCoords(); + glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void dragBrowser(); + void moveTarget(); - void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser_); + void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget); ScreenSpaceSkyBrowser* skyBrowser(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -76,14 +77,19 @@ protected: properties::StringProperty _testProperty; properties::FloatProperty _zoomFactor; ScreenSpaceSkyBrowser* _skyBrowser; + ScreenSpaceSkyTarget* _skyTarget; bool _camIsSyncedWWT; bool _listenForInteractions; std::thread _threadWWTMessages; std::thread _threadHandleInteractions; - glm::dvec2 startDragMousePos; - glm::dvec2 startDragObjectPos; - bool mouseIsClickedPreviously; + glm::vec2 startDragMousePos; + glm::vec2 startDragObjectPos; + bool mouseIsClickedPreviouslyLeft; + bool mouseIsClickedPreviouslyRight; glm::vec2 _mousePosition; + double _mouseScroll; + bool mouseIsOnBrowser; + }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index fe1fe696b0..16151bacc8 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -57,7 +57,8 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - module->initializeBrowser(browser); + ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("Target")); + module->initializeBrowser(browser, target); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); module->checkIfTargetExist(); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 436403091f..2b382dba23 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -23,6 +23,8 @@ #include #include +#include + namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; @@ -45,6 +47,23 @@ namespace openspace { } identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); + + std::unique_ptr texture = + ghoul::io::TextureReader::ref().loadTexture(absPath("D:/Ylvas/OpenSpace/modules/skybrowser/target.png")); + + if (texture) { + // Images don't need to start on 4-byte boundaries, for example if the + // image is only RGB + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + texture->uploadTexture(); + texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + texture->purgeFromRAM(); + + _texture = std::move(texture); + _objectSize = _texture->dimensions(); + _scale = 0.1f; + } } void ScreenSpaceSkyTarget::bindTexture() { From ebcbce56f5b91aad6e76ea341f21c8de00a88d4e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 14:00:12 +0100 Subject: [PATCH 022/251] Add functionality to drag target --- .../include/screenspaceskybrowser.h | 2 +- .../skybrowser/include/screenspaceskytarget.h | 11 +++- modules/skybrowser/skybrowsermodule.cpp | 46 +++++++------ modules/skybrowser/skybrowsermodule.h | 7 +- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- .../skybrowser/src/screenspaceskybrowser.cpp | 2 +- .../skybrowser/src/screenspaceskytarget.cpp | 65 ++++++++++++++++++- 7 files changed, 107 insertions(+), 28 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index b87900f3f8..525d61bafe 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -18,7 +18,7 @@ namespace openspace { void sendMouseEvent(CefStructBase event, int x, int y) const; glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); - bool coordIsInsideBrowserScreenSpace(glm::vec2 coord); + bool coordIsInsideCornersScreenSpace(glm::vec2 coord); private: }; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 7a923e0838..c9531b31ca 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -17,7 +17,16 @@ namespace openspace { public: ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyTarget() = default; - + glm::vec2 getScreenSpacePosition(); + + void translate(glm::vec2 translation, glm::vec2 position); + + glm::vec2 getScreenSpaceDimensions(); + glm::vec2 getUpperRightCornerScreenSpace(); + glm::vec2 getLowerLeftCornerScreenSpace(); + bool coordIsInsideCornersScreenSpace(glm::vec2 coord); + + void bindTexture() override; private: std::unique_ptr _texture; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index ce42ba3157..acd15c69bc 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -86,30 +86,36 @@ SkyBrowserModule::SkyBrowserModule() , _testProperty(TestInfo) , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) + , _skyTarget(nullptr) , _camIsSyncedWWT(true) , mouseIsClickedPreviouslyLeft(false) , _listenForInteractions(true) + , mouseIsOnBrowser(false) + , mouseIsOnTarget(false) { addProperty(_testProperty); addProperty(_zoomFactor); - createTarget(); - global::callback::mousePosition->emplace_back( [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); _mousePosition = getMousePositionInScreenSpaceCoords(pos); if (_skyBrowser) { - mouseIsOnBrowser = _skyBrowser->coordIsInsideBrowserScreenSpace(_mousePosition); + mouseIsOnBrowser = _skyBrowser->coordIsInsideCornersScreenSpace(_mousePosition); + } + if (_skyTarget) { + mouseIsOnTarget = _skyTarget->coordIsInsideCornersScreenSpace(_mousePosition); } - } ); global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - float zoom = scroll > 0.0 ? -2.0f : 2.0f; - _zoomFactor = std::clamp(_zoomFactor + zoom, 0.001f, 70.0f); + if (mouseIsOnBrowser) { + float zoom = scroll > 0.0 ? -2.0f : 2.0f; + _zoomFactor = std::clamp(_zoomFactor + zoom, 0.001f, 70.0f); + } + return true; } ); @@ -215,7 +221,6 @@ void SkyBrowserModule::handleInteractions() { */ _threadHandleInteractions = std::thread([&] { while (_listenForInteractions) { - LINFO(std::to_string(_mouseScroll)); bool mouseIsClickedLeft = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Left); bool mouseIsClickedRight = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Right); @@ -224,10 +229,14 @@ void SkyBrowserModule::handleInteractions() { } else { mouseIsClickedPreviouslyLeft = false; + } if (mouseIsClickedRight && !mouseIsClickedLeft) { moveTarget(); } + else { + mouseIsClickedPreviouslyRight = false; + } } }); } @@ -241,27 +250,26 @@ glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mouse void SkyBrowserModule::dragBrowser() { // First click on browser - user is not holding down the button since last frame - // glm::dvec2 mouseCoords = if (mouseIsOnBrowser && !mouseIsClickedPreviouslyLeft) { mouseIsClickedPreviouslyLeft = true; - startDragMousePos = _mousePosition; - startDragObjectPos = _skyBrowser->getScreenSpacePosition(); + startDragMousePosBrowser = _mousePosition; + startDragObjectPosBrowser = _skyBrowser->getScreenSpacePosition(); } else if (mouseIsClickedPreviouslyLeft) { - _skyBrowser->translate(_mousePosition - startDragMousePos, startDragObjectPos); + _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); } } void SkyBrowserModule::moveTarget() { // First click on browser - user is not holding down the button since last frame - - if (mouseIsOnBrowser && !mouseIsClickedPreviouslyRight) { + if (mouseIsOnTarget && !mouseIsClickedPreviouslyRight) { mouseIsClickedPreviouslyRight = true; - startDragMousePos = _mousePosition; - // startDragObjectPos = _skyTarget->getScreenSpacePosition(); + startDragMousePosTarget = _mousePosition; + startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); + LINFO(glm::to_string(startDragObjectPosTarget)); } else if (mouseIsClickedPreviouslyRight) { - // _skyTarget->translate(mouseCoords - startDragMousePos, startDragObjectPos); + _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); } } @@ -281,10 +289,8 @@ void SkyBrowserModule::WWTfollowCamera() { // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); sendMessageToWWT(message); - } }); - } ghoul::Dictionary SkyBrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { @@ -317,7 +323,6 @@ ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { return msg; } - void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget) { _skyBrowser = skyBrowser; _skyTarget = skyTarget; @@ -366,7 +371,8 @@ void SkyBrowserModule::createTarget() { "Type = 'ScreenSpaceSkyTarget'," "Identifier = 'ScreenSpaceTarget'," "Name = 'Screen Space Target'," - "FaceCamera = false" + "FaceCamera = false ," + "Scale = 0.25" "}"; openspace::global::scriptEngine->queueScript( diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index ca2860972c..4de0833147 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -82,13 +82,16 @@ protected: bool _listenForInteractions; std::thread _threadWWTMessages; std::thread _threadHandleInteractions; - glm::vec2 startDragMousePos; - glm::vec2 startDragObjectPos; + glm::vec2 startDragMousePosBrowser; + glm::vec2 startDragObjectPosBrowser; + glm::vec2 startDragMousePosTarget; + glm::vec2 startDragObjectPosTarget; bool mouseIsClickedPreviouslyLeft; bool mouseIsClickedPreviouslyRight; glm::vec2 _mousePosition; double _mouseScroll; bool mouseIsOnBrowser; + bool mouseIsOnTarget; }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 16151bacc8..b7e794193d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -57,7 +57,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("Target")); + ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); module->initializeBrowser(browser, target); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); module->checkIfTargetExist(); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 5e3ffdfa3b..c212535e6e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -119,7 +119,7 @@ namespace openspace { return getScreenSpacePosition() - (getScreenSpaceDimensions()/2.0f); } - bool ScreenSpaceSkyBrowser::coordIsInsideBrowserScreenSpace(glm::vec2 coord) { + bool ScreenSpaceSkyBrowser::coordIsInsideCornersScreenSpace(glm::vec2 coord) { bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; return lessThanUpperRight && moreThanLowerLeft; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 2b382dba23..2fc605d0a8 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -24,6 +24,8 @@ #include #include +#include +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; @@ -62,7 +64,6 @@ namespace openspace { _texture = std::move(texture); _objectSize = _texture->dimensions(); - _scale = 0.1f; } } @@ -71,5 +72,65 @@ namespace openspace { _texture->bind(); } } - + + void ScreenSpaceSkyTarget::translate(glm::vec2 translation, glm::vec2 position) { + + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + windowRatio /= windowRatio.y; + + _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation * windowRatio, 0.0f)) * glm::vec4(position * windowRatio, _cartesianPosition.value().z, 1.0f); + } + + glm::vec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * + localRotationMatrix() * scaleMatrix(); + glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); + glm::mat4 screenSpaceTransform = viewProj * modelTransform; + + glm::vec3 scale; + glm::quat rotation; + glm::vec3 translation; + glm::vec3 skew; + glm::vec4 perspective; + glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); + + return translation; + } + + glm::vec2 ScreenSpaceSkyTarget::getScreenSpaceDimensions() { + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * + localRotationMatrix() * scaleMatrix(); + glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); + glm::mat4 screenSpaceTransform = viewProj * modelTransform; + + + glm::vec3 scale; + glm::quat rotation; + glm::vec3 translation; + glm::vec3 skew; + glm::vec4 perspective; + glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); + + // Scale is negative and relative to the whole screen + // Changing to positive and View Coordinates [-1,1] + // E.g. a full screen screenspacebrowser will have [2,2] + scale = -2.0f * scale; + + return scale; + } + + glm::vec2 ScreenSpaceSkyTarget::getUpperRightCornerScreenSpace() { + + return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0f); + } + + glm::vec2 ScreenSpaceSkyTarget::getLowerLeftCornerScreenSpace() { + return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0f); + } + + bool ScreenSpaceSkyTarget::coordIsInsideCornersScreenSpace(glm::vec2 coord) { + bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; + bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; + return lessThanUpperRight && moreThanLowerLeft; + } } From c9fc1765ad3b9da5c88b84831c0b9a66af838ad2 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 16:12:23 +0100 Subject: [PATCH 023/251] Change drag function of target and browser to callback function --- modules/skybrowser/skybrowsermodule.cpp | 118 +++++++++++--------- modules/skybrowser/skybrowsermodule.h | 7 +- modules/skybrowser/skybrowsermodule_lua.inl | 3 +- 3 files changed, 68 insertions(+), 60 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index acd15c69bc..f381f0a476 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -88,23 +88,34 @@ SkyBrowserModule::SkyBrowserModule() , _skyBrowser(nullptr) , _skyTarget(nullptr) , _camIsSyncedWWT(true) - , mouseIsClickedPreviouslyLeft(false) + , currentlyDraggingBrowser(false) + , currentlyDraggingTarget(false) , _listenForInteractions(true) , mouseIsOnBrowser(false) , mouseIsOnTarget(false) + { addProperty(_testProperty); addProperty(_zoomFactor); + + global::callback::mousePosition->emplace_back( - [&](double x, double y) { + [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); _mousePosition = getMousePositionInScreenSpaceCoords(pos); - if (_skyBrowser) { - mouseIsOnBrowser = _skyBrowser->coordIsInsideCornersScreenSpace(_mousePosition); - } + if (_skyTarget) { - mouseIsOnTarget = _skyTarget->coordIsInsideCornersScreenSpace(_mousePosition); + mouseIsOnTarget = _skyTarget->coordIsInsideCornersScreenSpace(_mousePosition); + } + else { + mouseIsOnTarget = false; + } + if (_skyBrowser) { + mouseIsOnBrowser = _skyBrowser->coordIsInsideCornersScreenSpace(_mousePosition); + } + else { + mouseIsOnBrowser = false; } } ); @@ -114,11 +125,49 @@ SkyBrowserModule::SkyBrowserModule() if (mouseIsOnBrowser) { float zoom = scroll > 0.0 ? -2.0f : 2.0f; _zoomFactor = std::clamp(_zoomFactor + zoom, 0.001f, 70.0f); + return true; } - return true; + return false; } ); + + global::callback::mouseButton->emplace_back( + [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { + + if (action == MouseAction::Press) { + + if (mouseIsOnBrowser && button == MouseButton::Left) { + + startDragMousePosBrowser = _mousePosition; + startDragObjectPosBrowser = _skyBrowser->getScreenSpacePosition(); + currentlyDraggingBrowser = true; + return true; + } + else if (mouseIsOnTarget && button == MouseButton::Left) { + + startDragMousePosTarget = _mousePosition; + startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); + currentlyDraggingTarget = true; + return true; + } + } + else if (action == MouseAction::Release) { + if (currentlyDraggingBrowser) { + currentlyDraggingBrowser = false; + return true; + } + if (currentlyDraggingTarget) { + currentlyDraggingTarget = false; + return true; + } + } + + return false; + } + ); + + } void SkyBrowserModule::internalDeinitialize() { @@ -210,32 +259,18 @@ bool SkyBrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { } void SkyBrowserModule::handleInteractions() { - /* - float scroll = global::navigationHandler->inputState().mouseScrollDelta(); - bool mouseIsOverBrowser = _skyBrowser->coordIsInsideBrowserScreenSpace(getMousePositionInScreenSpaceCoords()); - LINFO(std::to_string(mouseIsOverBrowser)); - - _zoomFactor = std::clamp(_zoomFactor - scroll, 0.001f, 70.0f); + /* CefStructBase event; _skyBrowser->sendMouseEvent(event, scroll, scroll); */ _threadHandleInteractions = std::thread([&] { while (_listenForInteractions) { - bool mouseIsClickedLeft = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Left); - bool mouseIsClickedRight = global::navigationHandler->inputState().isMouseButtonPressed(MouseButton::Right); - if (mouseIsClickedLeft && !mouseIsClickedRight) { - dragBrowser(); + if (currentlyDraggingBrowser) { + _skyBrowser->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); } - else { - mouseIsClickedPreviouslyLeft = false; - - } - if (mouseIsClickedRight && !mouseIsClickedLeft) { - moveTarget(); - } - else { - mouseIsClickedPreviouslyRight = false; + if (currentlyDraggingTarget) { + _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); } } }); @@ -248,31 +283,6 @@ glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mouse return glm::vec2((mousePos - (size / 2.0f)) * glm::vec2(1.0f,-1.0f) / (size / 2.0f)); } -void SkyBrowserModule::dragBrowser() { - // First click on browser - user is not holding down the button since last frame - if (mouseIsOnBrowser && !mouseIsClickedPreviouslyLeft) { - mouseIsClickedPreviouslyLeft = true; - startDragMousePosBrowser = _mousePosition; - startDragObjectPosBrowser = _skyBrowser->getScreenSpacePosition(); - } - else if (mouseIsClickedPreviouslyLeft) { - _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); - } -} - -void SkyBrowserModule::moveTarget() { - // First click on browser - user is not holding down the button since last frame - if (mouseIsOnTarget && !mouseIsClickedPreviouslyRight) { - mouseIsClickedPreviouslyRight = true; - startDragMousePosTarget = _mousePosition; - startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); - LINFO(glm::to_string(startDragObjectPosTarget)); - } - else if (mouseIsClickedPreviouslyRight) { - _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); - } -} - void SkyBrowserModule::WWTfollowCamera() { // Start a thread to enable user interaction while sending the calls to WWT @@ -289,8 +299,10 @@ void SkyBrowserModule::WWTfollowCamera() { // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); sendMessageToWWT(message); + } }); + } ghoul::Dictionary SkyBrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { @@ -323,6 +335,7 @@ ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { return msg; } + void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget) { _skyBrowser = skyBrowser; _skyTarget = skyTarget; @@ -371,8 +384,7 @@ void SkyBrowserModule::createTarget() { "Type = 'ScreenSpaceSkyTarget'," "Identifier = 'ScreenSpaceTarget'," "Name = 'Screen Space Target'," - "FaceCamera = false ," - "Scale = 0.25" + "FaceCamera = false" "}"; openspace::global::scriptEngine->queueScript( diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 4de0833147..a6d0e9fc34 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -62,8 +62,6 @@ public: bool sendMessageToWWT(const ghoul::Dictionary& msg); void handleInteractions(); glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); - void dragBrowser(); - void moveTarget(); void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget); ScreenSpaceSkyBrowser* skyBrowser(); @@ -86,13 +84,12 @@ protected: glm::vec2 startDragObjectPosBrowser; glm::vec2 startDragMousePosTarget; glm::vec2 startDragObjectPosTarget; - bool mouseIsClickedPreviouslyLeft; - bool mouseIsClickedPreviouslyRight; + bool currentlyDraggingBrowser; + bool currentlyDraggingTarget; glm::vec2 _mousePosition; double _mouseScroll; bool mouseIsOnBrowser; bool mouseIsOnTarget; - }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b7e794193d..b6616cb928 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -44,8 +44,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkyBrowserModule* module = global::moduleEngine->module(); - //ghoul::Dictionary message = module->createMessageForPausingWWTTime(); - //module->sendMessageToWWT(message); + module->WWTfollowCamera(); module->handleInteractions(); From 06ffdecc90a1577928b53c27f4c4e02726dfa41d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 16:19:17 +0100 Subject: [PATCH 024/251] Fix small error of dragging --- modules/skybrowser/skybrowsermodule.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f381f0a476..ace0487eb7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -99,7 +99,6 @@ SkyBrowserModule::SkyBrowserModule() addProperty(_zoomFactor); - global::callback::mousePosition->emplace_back( [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); @@ -146,6 +145,13 @@ SkyBrowserModule::SkyBrowserModule() } else if (mouseIsOnTarget && button == MouseButton::Left) { + startDragMousePosTarget = _mousePosition; + startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); + currentlyDraggingTarget = true; + return true; + } + else if (mouseIsOnBrowser && button == MouseButton::Right) { + startDragMousePosTarget = _mousePosition; startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); currentlyDraggingTarget = true; @@ -267,7 +273,7 @@ void SkyBrowserModule::handleInteractions() { while (_listenForInteractions) { if (currentlyDraggingBrowser) { - _skyBrowser->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); + _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); } if (currentlyDraggingTarget) { _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); From 3bc5d00aaaf9000826ab96023b83c303663e903f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 16:19:17 +0100 Subject: [PATCH 025/251] Add functionality to drag target when dragging on zoom window --- modules/skybrowser/skybrowsermodule.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f381f0a476..ace0487eb7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -99,7 +99,6 @@ SkyBrowserModule::SkyBrowserModule() addProperty(_zoomFactor); - global::callback::mousePosition->emplace_back( [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); @@ -146,6 +145,13 @@ SkyBrowserModule::SkyBrowserModule() } else if (mouseIsOnTarget && button == MouseButton::Left) { + startDragMousePosTarget = _mousePosition; + startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); + currentlyDraggingTarget = true; + return true; + } + else if (mouseIsOnBrowser && button == MouseButton::Right) { + startDragMousePosTarget = _mousePosition; startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); currentlyDraggingTarget = true; @@ -267,7 +273,7 @@ void SkyBrowserModule::handleInteractions() { while (_listenForInteractions) { if (currentlyDraggingBrowser) { - _skyBrowser->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); + _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); } if (currentlyDraggingTarget) { _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); From a5371776d9f20a54593e2adcec4c3c16cc5e85e5 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 17:11:00 +0100 Subject: [PATCH 026/251] Change view direction to what the target points at --- modules/skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/skybrowsermodule.cpp | 15 ++++++++++++--- modules/skybrowser/src/screenspaceskytarget.cpp | 7 ++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index c9531b31ca..375b638f66 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -18,6 +18,7 @@ namespace openspace { ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyTarget() = default; glm::vec2 getScreenSpacePosition(); + glm::vec2 getAnglePosition(); void translate(glm::vec2 translation, glm::vec2 position); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index ace0487eb7..be22a311af 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -50,6 +50,7 @@ #include // For atan2 #include // formatJson #include +#include namespace { constexpr const openspace::properties::Property::PropertyInfo TestInfo = @@ -295,11 +296,19 @@ void SkyBrowserModule::WWTfollowCamera() { _threadWWTMessages = std::thread([&] { while (_camIsSyncedWWT) { - // Get camera view direction - const glm::dvec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + // Get camera view direction and orthogonal coordinate system of camera view direction + glm::vec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); + glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); + + glm::vec2 angleOffset = _skyTarget->getAnglePosition(); + // Change view if target is moved + glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); + targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); + // Convert to celestial coordinates - glm::dvec2 celestCoords = convertGalacticToCelestial(viewDirection); + glm::dvec2 celestCoords = convertGalacticToCelestial(targetDirection); ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); // Sleep so we don't bombard WWT with too many messages diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 2fc605d0a8..032db8749f 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -96,7 +96,12 @@ namespace openspace { return translation; } - + + glm::vec2 ScreenSpaceSkyTarget::getAnglePosition() { + glm::vec3 pos = _cartesianPosition.value(); + return glm::vec2(atan(pos.x / pos.z), atan(pos.y / pos.z)); + } + glm::vec2 ScreenSpaceSkyTarget::getScreenSpaceDimensions() { glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); From ca93e2990e0e32b3de3548b9e716950812d010ef Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 11 Mar 2021 17:21:18 +0100 Subject: [PATCH 027/251] Change to logarithmic scrolling --- modules/skybrowser/skybrowsermodule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index be22a311af..619a895e56 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -123,7 +123,7 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { if (mouseIsOnBrowser) { - float zoom = scroll > 0.0 ? -2.0f : 2.0f; + float zoom = scroll > 0.0 ? -log(_zoomFactor + 1.1f) : log(_zoomFactor + 1.1f); _zoomFactor = std::clamp(_zoomFactor + zoom, 0.001f, 70.0f); return true; } From 9580c617ef5c2c8d3244a9677987ae8d88a5fc2b Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 12 Mar 2021 14:49:53 +0100 Subject: [PATCH 028/251] Add target square with shader --- .../skybrowser/include/screenspaceskytarget.h | 12 +++ modules/skybrowser/shaders/target_fs.glsl | 19 +++- modules/skybrowser/skybrowsermodule.cpp | 21 +---- modules/skybrowser/skybrowsermodule_lua.inl | 7 +- modules/skybrowser/square.png | Bin 0 -> 409 bytes .../skybrowser/src/screenspaceskytarget.cpp | 89 +++++++++++++++++- 6 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 modules/skybrowser/square.png diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 7a923e0838..0ea57db5fb 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -18,10 +18,22 @@ namespace openspace { ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyTarget() = default; + // from SSR + bool initializeGL() override; + bool isReady() const override; + + void render() override; + void update() override; + + void createShaders(); + void bindTexture() override; private: std::unique_ptr _texture; + UniformCache(modelTransform, viewProj, texture, borderWidth, scale) _uniformCache; + GLuint _vertexArray = 0; + GLuint _vertexBuffer = 0; }; } diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 260888d8f8..5b18ad2483 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,6 +1,6 @@ uniform sampler2D texture1; -uniform float OcclusionDepth; -uniform float Alpha; +uniform float Scale; +uniform float BorderWidth; in vec2 vs_st; in vec4 vs_position; @@ -10,8 +10,17 @@ in vec4 vs_position; Fragment getFragment() { Fragment frag; - vec3 color = vec3(1.0); - frag.color = vec4(color, 1.0); + vec2 bl = step(vec2(BorderWidth),1.0-vs_st); // bottom-left line + vec2 tr = step(vec2(BorderWidth),vs_st); // top-right line + vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); + + frag.color = texture(texture1, vs_st); + + if(border == vec3(1.0)) { + + frag.color.a = 0.0; + } + return frag; -} \ No newline at end of file +} diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 475092d763..147c6e25df 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -94,8 +94,6 @@ SkyBrowserModule::SkyBrowserModule() addProperty(_testProperty); addProperty(_zoomFactor); - createTarget(); - global::callback::mousePosition->emplace_back( [&](double x, double y) { _mousePosition = glm::vec2(static_cast(x), static_cast(y)); @@ -291,6 +289,7 @@ ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser) { + createTarget(); _skyBrowser = skyBrowser; } @@ -317,38 +316,26 @@ glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } - -void SkyBrowserModule::checkIfTargetExist() { - ScreenSpaceSkyTarget* target = static_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); - - if (target) { - LINFO("Target is not null!"); - - } - LINFO("Target has been checked!"); -} - void SkyBrowserModule::createTarget() { using namespace std::string_literals; - // Create target test std::string node = "{" "Type = 'ScreenSpaceSkyTarget'," "Identifier = 'ScreenSpaceTarget'," "Name = 'Screen Space Target'," - "FaceCamera = false" + "FaceCamera = false," + "Scale = 0.04," "}"; openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - + } - /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index fe1fe696b0..68690e1585 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -59,7 +59,6 @@ namespace openspace::skybrowser::luascriptfunctions { ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); module->initializeBrowser(browser); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); - module->checkIfTargetExist(); return 1; } @@ -89,11 +88,7 @@ namespace openspace::skybrowser::luascriptfunctions { openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes - ); - - //test create target - module->createTarget(); - + ); return 1; } diff --git a/modules/skybrowser/square.png b/modules/skybrowser/square.png new file mode 100644 index 0000000000000000000000000000000000000000..79838c1580d5b058ada4b58bc3bffb209e8948cb GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRdwrjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4SJp~jv*CsZ!a1$GAQsI*w9#i{_#QQdCyih z%)2|+;=8#A^9HsA-UCt%rVQB(*BI6?MvPnm)6WbEY0Q76ANP3ygOkD2)z4*}Q$iB} DfoFKK literal 0 HcmV?d00001 diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 436403091f..bf247225a8 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -13,7 +13,7 @@ #include #include - +#include #include #include #include @@ -23,11 +23,14 @@ #include #include +#include +#include + namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; - constexpr const std::array UniformNames = { - "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" + constexpr const std::array UniformNames = { + "ModelTransform", "ViewProjectionMatrix", "texture1", "BorderWidth", "Scale" }; } //namespace @@ -52,5 +55,85 @@ namespace openspace { _texture->bind(); } } + + bool ScreenSpaceSkyTarget::isReady() const { + return _shader != nullptr; + } + + bool ScreenSpaceSkyTarget::initializeGL() { + + glGenVertexArrays(1, &_vertexArray); + glGenBuffers(1, &_vertexBuffer); + + std::unique_ptr texture = ghoul::io::TextureReader::ref().loadTexture(absPath("${MODULE_SKYBROWSER}/square.png")); + + + if (texture) { + // Images don't need to start on 4-byte boundaries, for example if the + // image is only RGB + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + texture->uploadTexture(); + texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + texture->purgeFromRAM(); + + _texture = std::move(texture); + _objectSize = _texture->dimensions(); + } + + createShaders(); + + return isReady(); + } + + void ScreenSpaceSkyTarget::createShaders() { + + _shader = global::renderEngine->buildRenderProgram( + "ScreenSpaceProgram", + absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), + absPath("${MODULE_SKYBROWSER}/shaders/target_fs.glsl") + ); + + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); + + } + + void ScreenSpaceSkyTarget::render() { + + glDisable(GL_CULL_FACE); + + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); + float borderWidth = 0.002f; + + _shader->activate(); + + _shader->setUniform(_uniformCache.borderWidth, borderWidth); + _shader->setUniform(_uniformCache.modelTransform, modelTransform); + + _shader->setUniform( + _uniformCache.viewProj, + global::renderEngine->scene()->camera()->viewProjectionMatrix() + ); + + ghoul::opengl::TextureUnit unit; + unit.activate(); + bindTexture(); + _shader->setUniform(_uniformCache.texture, unit); + + glBindVertexArray(rendering::helper::vertexObjects.square.vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glEnable(GL_CULL_FACE); + + _shader->deactivate(); + unbindTexture(); + } + + void ScreenSpaceSkyTarget::update() { + + + } + + } From 6ac4e594c5c0a1f144e36c1e0e6a758d434436b8 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 12 Mar 2021 14:53:08 +0100 Subject: [PATCH 029/251] Move createtarget function call --- modules/skybrowser/skybrowsermodule.h | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index cd20b4f7fd..90da2a298a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -53,7 +53,6 @@ public: // target void createTarget(); - void checkIfTargetExist(); ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; From c05f8a4e87bfe6b2cbde8a929ee662ab7e729d53 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 18 Mar 2021 09:33:34 +0100 Subject: [PATCH 030/251] Add working resize and dragging functionality --- .../include/screenspaceskybrowser.h | 10 +- modules/skybrowser/skybrowsermodule.cpp | 42 ++++++-- modules/skybrowser/skybrowsermodule.h | 2 + .../skybrowser/src/screenspaceskybrowser.cpp | 98 ++++++++++--------- .../skybrowser/src/screenspaceskytarget.cpp | 48 ++------- 5 files changed, 106 insertions(+), 94 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 525d61bafe..f13457f562 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -19,8 +19,16 @@ namespace openspace { glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::vec2 coord); - private: + bool coordIsOnResizeButton(glm::vec2 coord); + void scale(glm::vec2 scalingFactor); + glm::mat4 scaleMatrix() override; + void saveResizeStartSize(); + void updateBrowserSize(); + void scale(float scalingFactor); + private: + glm::vec2 _startSize; + float _startScale; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 619a895e56..40e82d48e7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -91,6 +91,7 @@ SkyBrowserModule::SkyBrowserModule() , _camIsSyncedWWT(true) , currentlyDraggingBrowser(false) , currentlyDraggingTarget(false) + , currentlyResizingBrowser(false) , _listenForInteractions(true) , mouseIsOnBrowser(false) , mouseIsOnTarget(false) @@ -103,6 +104,7 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mousePosition->emplace_back( [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); + _mousePosition = getMousePositionInScreenSpaceCoords(pos); if (_skyTarget) { @@ -112,7 +114,7 @@ SkyBrowserModule::SkyBrowserModule() mouseIsOnTarget = false; } if (_skyBrowser) { - mouseIsOnBrowser = _skyBrowser->coordIsInsideCornersScreenSpace(_mousePosition); + mouseIsOnBrowser = _skyBrowser->coordIsInsideCornersScreenSpace(_mousePosition); } else { mouseIsOnBrowser = false; @@ -141,7 +143,16 @@ SkyBrowserModule::SkyBrowserModule() startDragMousePosBrowser = _mousePosition; startDragObjectPosBrowser = _skyBrowser->getScreenSpacePosition(); - currentlyDraggingBrowser = true; + // Resize browser if mouse is over resize button + if (_skyBrowser->coordIsOnResizeButton(_mousePosition)) { + _skyBrowser->saveResizeStartSize(); + startResizeBrowserSize = _skyBrowser->getScreenSpaceDimensions(); + currentlyResizingBrowser = true; + } + else { + currentlyDraggingBrowser = true; + } + return true; } else if (mouseIsOnTarget && button == MouseButton::Left) { @@ -168,13 +179,16 @@ SkyBrowserModule::SkyBrowserModule() currentlyDraggingTarget = false; return true; } + if (currentlyResizingBrowser) { + currentlyResizingBrowser = false; + _skyBrowser->updateBrowserSize(); + return true; + } } return false; } ); - - } void SkyBrowserModule::internalDeinitialize() { @@ -279,15 +293,27 @@ void SkyBrowserModule::handleInteractions() { if (currentlyDraggingTarget) { _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); } + if (currentlyResizingBrowser) { + // Calculate scaling factor + glm::vec2 mouseDragVector = _mousePosition - startDragMousePosBrowser; + + glm::vec2 newSizeRelToOld = (startResizeBrowserSize + mouseDragVector) / startResizeBrowserSize; + _skyBrowser->scale(newSizeRelToOld); + _skyBrowser->translate(mouseDragVector/2.f, startDragObjectPosBrowser); + } } }); } glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { - glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); - - // Transform pixel coordinates to screen space coordinates [-1,1] - return glm::vec2((mousePos - (size / 2.0f)) * glm::vec2(1.0f,-1.0f) / (size / 2.0f)); + glm::vec2 size = global::windowDelegate->currentWindowSize(); + // Change origin to middle of the window + glm::vec2 screenSpacePos = glm::vec2((mousePos - (size / 2.0f))); + // Ensure the upper right corner is positive on the y axis + screenSpacePos *= glm::vec2(1.0f, -1.0f); + // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] + screenSpacePos /= (0.5f*size.y); + return screenSpacePos; } void SkyBrowserModule::WWTfollowCamera() { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index a6d0e9fc34..a912136ff6 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -84,7 +84,9 @@ protected: glm::vec2 startDragObjectPosBrowser; glm::vec2 startDragMousePosTarget; glm::vec2 startDragObjectPosTarget; + glm::vec2 startResizeBrowserSize; bool currentlyDraggingBrowser; + bool currentlyResizingBrowser; bool currentlyDraggingTarget; glm::vec2 _mousePosition; double _mouseScroll; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index c212535e6e..c48102137b 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -34,15 +35,17 @@ namespace openspace { } identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - + // The projection plane seems to be located at z = -2.1 so at that place the ScreenSpaceRenderables behaves like + // they are in screen space + _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); } + void ScreenSpaceSkyBrowser::executeJavascript(std::string& script) const { //LINFOC(_loggerCat, "Executing javascript " + script); if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) { CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); frame->ExecuteJavaScript(script, frame->GetURL(), 0); - } - + } } void ScreenSpaceSkyBrowser::sendMouseEvent(CefStructBase event, int x, int y) const { @@ -54,64 +57,26 @@ namespace openspace { //LINFOC(_loggerCat, "Sending scroll"); } - } void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { - - glm::vec3 position = _cartesianPosition; - + glm::vec3 position = _cartesianPosition; _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); } void ScreenSpaceSkyBrowser::translate(glm::vec2 translation, glm::vec2 position) { - - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - windowRatio /= windowRatio.y; - - _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation * windowRatio, 0.0f)) * glm::vec4(position * windowRatio, _cartesianPosition.value().z, 1.0f); + _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); } glm::vec2 ScreenSpaceSkyBrowser::getScreenSpacePosition() { - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * - localRotationMatrix() * scaleMatrix(); - glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); - glm::mat4 screenSpaceTransform = viewProj * modelTransform; - - glm::vec3 scale; - glm::quat rotation; - glm::vec3 translation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); - - return translation; + return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); } glm::vec2 ScreenSpaceSkyBrowser::getScreenSpaceDimensions() { - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * - localRotationMatrix() * scaleMatrix(); - glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); - glm::mat4 screenSpaceTransform = viewProj * modelTransform; - - - glm::vec3 scale; - glm::quat rotation; - glm::vec3 translation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); - - // Scale is negative and relative to the whole screen - // Changing to positive and View Coordinates [-1,1] - // E.g. a full screen screenspacebrowser will have [2,2] - scale = -2.0f * scale; - - return scale; + return glm::vec2(2.f*_scale* static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f*_scale); } glm::vec2 ScreenSpaceSkyBrowser::getUpperRightCornerScreenSpace() { - return getScreenSpacePosition() + (getScreenSpaceDimensions()/2.0f); } @@ -125,4 +90,47 @@ namespace openspace { return lessThanUpperRight && moreThanLowerLeft; } + bool ScreenSpaceSkyBrowser::coordIsOnResizeButton(glm::vec2 coord) { + float resizeButtonSize = 0.05f; + bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; + bool moreThanLowerLeft = coord.x > getUpperRightCornerScreenSpace().x - (getScreenSpaceDimensions().x * resizeButtonSize) && + coord.y > getLowerLeftCornerScreenSpace().y - (getScreenSpaceDimensions().y * resizeButtonSize); + return lessThanUpperRight && moreThanLowerLeft; + } + // Scales the ScreenSpaceBrowser to a new ratio + void ScreenSpaceSkyBrowser::scale(glm::vec2 scalingFactor) { + // Resize the dimensions of the texture on the x axis + glm::vec2 newSize = abs(scalingFactor) * _startSize; + _texture->setDimensions(glm::ivec3(newSize, 1)); + // Scale on the y axis, this is to ensure that _scale = 1 is + // equal to the height of the window + scale(abs(scalingFactor.y)); + } + + glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { + // To ensure the plane has the right ratio + // The _scale us how much of the windows height the + // browser covers: eg a browser that covers 0.25 of the + // height of the window will have scale = 0.25 + float textureRatio = + static_cast(_objectSize.x) / static_cast(_objectSize.y); + + glm::mat4 scale = glm::scale( + glm::mat4(1.f), + glm::vec3(textureRatio * _scale, _scale, 1.f) + ); + return scale; + } + + void ScreenSpaceSkyBrowser::saveResizeStartSize() { + _startSize = glm::vec2(_dimensions.value().x, _dimensions.value().y); + _startScale = _scale.value(); + } + // Updates the browser size to match the size of the texture + void ScreenSpaceSkyBrowser::updateBrowserSize() { + _dimensions = _texture->dimensions(); + } + void ScreenSpaceSkyBrowser::scale(float scalingFactor) { + _scale = _startScale * scalingFactor; + } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 032db8749f..bbcfc1589f 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -65,6 +65,7 @@ namespace openspace { _texture = std::move(texture); _objectSize = _texture->dimensions(); } + _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); } void ScreenSpaceSkyTarget::bindTexture() { @@ -74,27 +75,7 @@ namespace openspace { } void ScreenSpaceSkyTarget::translate(glm::vec2 translation, glm::vec2 position) { - - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - windowRatio /= windowRatio.y; - - _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation * windowRatio, 0.0f)) * glm::vec4(position * windowRatio, _cartesianPosition.value().z, 1.0f); - } - - glm::vec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * - localRotationMatrix() * scaleMatrix(); - glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); - glm::mat4 screenSpaceTransform = viewProj * modelTransform; - - glm::vec3 scale; - glm::quat rotation; - glm::vec3 translation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); - - return translation; + _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); } glm::vec2 ScreenSpaceSkyTarget::getAnglePosition() { @@ -102,26 +83,12 @@ namespace openspace { return glm::vec2(atan(pos.x / pos.z), atan(pos.y / pos.z)); } + glm::vec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { + return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); + } + glm::vec2 ScreenSpaceSkyTarget::getScreenSpaceDimensions() { - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * - localRotationMatrix() * scaleMatrix(); - glm::mat4 viewProj = global::renderEngine->scene()->camera()->viewProjectionMatrix(); - glm::mat4 screenSpaceTransform = viewProj * modelTransform; - - - glm::vec3 scale; - glm::quat rotation; - glm::vec3 translation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(screenSpaceTransform, scale, rotation, translation, skew, perspective); - - // Scale is negative and relative to the whole screen - // Changing to positive and View Coordinates [-1,1] - // E.g. a full screen screenspacebrowser will have [2,2] - scale = -2.0f * scale; - - return scale; + return glm::vec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); } glm::vec2 ScreenSpaceSkyTarget::getUpperRightCornerScreenSpace() { @@ -138,4 +105,5 @@ namespace openspace { bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; return lessThanUpperRight && moreThanLowerLeft; } + } From 1a49b1c4baca991382e9ded906f008ba42f9546d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 18 Mar 2021 09:39:41 +0100 Subject: [PATCH 031/251] Merge in master --- apps/OpenSpace/ext/sgct | 2 +- ext/ghoul | 2 +- support/coding/codegen | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index eefd275cce..fed1f55a0b 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit eefd275ccec15c9316e4bc91d7232f3beea083a2 +Subproject commit fed1f55a0b259a70a5ad8461a4e56f07990609f1 diff --git a/ext/ghoul b/ext/ghoul index 1625701baa..2180f32860 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 1625701baa17a568163d96a3532489d306d18e0e +Subproject commit 2180f32860131b08831f9d4c2be5839b5aa48672 diff --git a/support/coding/codegen b/support/coding/codegen index b3c0a745fa..1ca72c0202 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit b3c0a745fa68e5f762de8a06732038e3a6fd5e02 +Subproject commit 1ca72c0202e3bd4b61510f84797db131591c8ca3 From 3573859ffe6e5e29c87cf824b20b6af9a0564d1a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 18 Mar 2021 16:13:46 +0100 Subject: [PATCH 032/251] Add resizing functionality to all corners and side of browser --- ext/ghoul | 2 +- .../rendering/screenspacerenderable.h | 2 +- .../include/screenspaceskybrowser.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 12 ++++--- modules/skybrowser/skybrowsermodule.h | 1 + .../skybrowser/src/screenspaceskybrowser.cpp | 35 +++++++++++++------ .../webbrowser/include/screenspacebrowser.h | 13 ++++--- src/rendering/screenspacerenderable.cpp | 12 ++----- 8 files changed, 46 insertions(+), 33 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 2180f32860..1625701baa 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 2180f32860131b08831f9d4c2be5839b5aa48672 +Subproject commit 1625701baa17a568163d96a3532489d306d18e0e diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 189ae16d12..8d4d073843 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -77,7 +77,7 @@ protected: void createShaders(); std::string makeUniqueIdentifier(std::string name); - glm::mat4 scaleMatrix(); + virtual glm::mat4 scaleMatrix(); glm::mat4 globalRotationMatrix(); glm::mat4 translationMatrix(); glm::mat4 localRotationMatrix(); diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index f13457f562..999c3508a9 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -19,7 +19,7 @@ namespace openspace { glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::vec2 coord); - bool coordIsOnResizeButton(glm::vec2 coord); + glm::vec2 coordIsOnResizeArea(glm::vec2 coord); void scale(glm::vec2 scalingFactor); glm::mat4 scaleMatrix() override; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1fccb07c50..6a79676681 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -143,7 +143,9 @@ SkyBrowserModule::SkyBrowserModule() startDragMousePosBrowser = _mousePosition; startDragObjectPosBrowser = _skyBrowser->getScreenSpacePosition(); // Resize browser if mouse is over resize button - if (_skyBrowser->coordIsOnResizeButton(_mousePosition)) { + resizeVector = _skyBrowser->coordIsOnResizeArea(_mousePosition); + + if (resizeVector != glm::vec2{0}) { _skyBrowser->saveResizeStartSize(); startResizeBrowserSize = _skyBrowser->getScreenSpaceDimensions(); currentlyResizingBrowser = true; @@ -294,11 +296,13 @@ void SkyBrowserModule::handleInteractions() { } if (currentlyResizingBrowser) { // Calculate scaling factor - glm::vec2 mouseDragVector = _mousePosition - startDragMousePosBrowser; + glm::vec2 mouseDragVector = (_mousePosition - startDragMousePosBrowser); + glm::vec2 scalingVector = mouseDragVector * resizeVector; - glm::vec2 newSizeRelToOld = (startResizeBrowserSize + mouseDragVector) / startResizeBrowserSize; + glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; _skyBrowser->scale(newSizeRelToOld); - _skyBrowser->translate(mouseDragVector/2.f, startDragObjectPosBrowser); + // Make sure the browser doesn't move in directions it's not supposed to + _skyBrowser->translate(mouseDragVector * abs(resizeVector) /2.f, startDragObjectPosBrowser); } } }); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index fe0f227e97..3196b74e8a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -84,6 +84,7 @@ protected: glm::vec2 startDragMousePosTarget; glm::vec2 startDragObjectPosTarget; glm::vec2 startResizeBrowserSize; + glm::vec2 resizeVector; bool currentlyDraggingBrowser; bool currentlyResizingBrowser; bool currentlyDraggingTarget; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index c48102137b..aad89b507b 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -90,30 +90,43 @@ namespace openspace { return lessThanUpperRight && moreThanLowerLeft; } - bool ScreenSpaceSkyBrowser::coordIsOnResizeButton(glm::vec2 coord) { - float resizeButtonSize = 0.05f; - bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; - bool moreThanLowerLeft = coord.x > getUpperRightCornerScreenSpace().x - (getScreenSpaceDimensions().x * resizeButtonSize) && - coord.y > getLowerLeftCornerScreenSpace().y - (getScreenSpaceDimensions().y * resizeButtonSize); - return lessThanUpperRight && moreThanLowerLeft; + glm::vec2 ScreenSpaceSkyBrowser::coordIsOnResizeArea(glm::vec2 coord) { + glm::vec2 resizePosition = glm::vec2{ 0 }; + // Make sure coord is on browser + if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; + + float resizeButtonSize = 0.1f; + + bool isOnTop = coord.y > getUpperRightCornerScreenSpace().y - (getScreenSpaceDimensions().y * resizeButtonSize); + bool isOnBottom = coord.y < getLowerLeftCornerScreenSpace().y + (getScreenSpaceDimensions().y * resizeButtonSize); + bool isOnRight = coord.x > getUpperRightCornerScreenSpace().x - (getScreenSpaceDimensions().x * resizeButtonSize); + bool isOnLeft = coord.x < getLowerLeftCornerScreenSpace().x + (getScreenSpaceDimensions().x * resizeButtonSize); + + resizePosition.x = isOnRight ? 1.f : isOnLeft ? -1.f : 0.f; + resizePosition.y = isOnTop ? 1.f : isOnBottom ? -1.f : 0.f; + + return resizePosition; } // Scales the ScreenSpaceBrowser to a new ratio void ScreenSpaceSkyBrowser::scale(glm::vec2 scalingFactor) { - // Resize the dimensions of the texture on the x axis - glm::vec2 newSize = abs(scalingFactor) * _startSize; - _texture->setDimensions(glm::ivec3(newSize, 1)); + // Scale on the y axis, this is to ensure that _scale = 1 is // equal to the height of the window scale(abs(scalingFactor.y)); + // Resize the dimensions of the texture on the x axis + glm::vec2 newSize = abs(scalingFactor) * _startSize; + _texture->setDimensions(glm::ivec3(newSize, 1)); + // To not make it glitch... Makes it glitch in other ways however + //updateBrowserSize(); } glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { // To ensure the plane has the right ratio - // The _scale us how much of the windows height the + // The _scale tells us how much of the windows height the // browser covers: eg a browser that covers 0.25 of the // height of the window will have scale = 0.25 float textureRatio = - static_cast(_objectSize.x) / static_cast(_objectSize.y); + static_cast(_texture->dimensions().x) / static_cast(_texture->dimensions().y); glm::mat4 scale = glm::scale( glm::mat4(1.f), diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index d3f0cc4063..1c039057df 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -75,7 +75,10 @@ public: protected: properties::Vec2Property _dimensions; std::unique_ptr _browserInstance; -private: + std::unique_ptr _texture; + + + class ScreenSpaceRenderHandler : public WebRenderHandler { public: void draw() override; @@ -84,18 +87,18 @@ private: void setTexture(GLuint t); }; + CefRefPtr _renderHandler; + +private: void bindTexture() override; properties::StringProperty _url; properties::TriggerProperty _reload; - CefRefPtr _renderHandler; + CefRefPtr _keyboardHandler; - - std::unique_ptr _texture; - bool _isUrlDirty = false; bool _isDimensionsDirty = false; }; diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 9f913096a2..a6710b1980 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -553,17 +553,9 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { glm::mat4 scale = glm::scale( glm::mat4(1.f), - glm::vec3(_scale, _scale * textureRatio, 1.f) + glm::vec3(_scale, textureRatio*_scale, 1.f) ); - - // Simulate orthographic projection by distance to plane. - if (!_usePerspectiveProjection) { - float distance = _useRadiusAzimuthElevation ? - _raePosition.value().x : - -_cartesianPosition.value().z; - scale = glm::scale(scale, glm::vec3(distance)); - } - + return scale; } From c728c38daa421a57a805dd6833064d932af416bf Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 19 Mar 2021 09:06:33 +0100 Subject: [PATCH 033/251] Fix problems with submodules --- apps/OpenSpace/ext/sgct | 2 +- support/coding/codegen | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index fed1f55a0b..eefd275cce 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit fed1f55a0b259a70a5ad8461a4e56f07990609f1 +Subproject commit eefd275ccec15c9316e4bc91d7232f3beea083a2 diff --git a/support/coding/codegen b/support/coding/codegen index 1ca72c0202..b3c0a745fa 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit 1ca72c0202e3bd4b61510f84797db131591c8ca3 +Subproject commit b3c0a745fa68e5f762de8a06732038e3a6fd5e02 From ac4fc926a27a0b11d6a0b5d3dd6a0171f284f78f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 19 Mar 2021 09:37:19 +0100 Subject: [PATCH 034/251] Add function to create browser --- modules/skybrowser/skybrowsermodule.cpp | 29 +++++++++++++++++++++ modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 25 +++--------------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 6a79676681..41d9c4608d 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -430,6 +430,35 @@ void SkyBrowserModule::createTarget() { } +void SkyBrowserModule::createBrowser() { + + SkyBrowserModule* module = global::moduleEngine->module(); + + using namespace std::string_literals; + + std::string node = "{" + "Type = 'ScreenSpaceSkyBrowser'," + "Identifier = 'ScreenSpaceBowser'," + "Name = 'Screen Space Bowser'," + "Url = 'http://localhost:8000/'," + "FaceCamera = false" + "}"; + + /* + ghoul::Dictionary node; + node.setValue("Type", "ScreenSpaceBrowser"s); + node.setValue("Identifier", "ScreenSpaceBowser"s); + node.setValue("Name", "Screen Space Bowser"s); + node.setValue("Url", "http://localhost:8000/"s); + */ + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + node + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); + +} + + /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 3196b74e8a..fbd77fc3b7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -53,6 +53,7 @@ public: // target void createTarget(); + void createBrowser(); ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4aa20eb4b6..945269b1b3 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -67,28 +67,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); - - using namespace std::string_literals; - - std::string node = "{" - "Type = 'ScreenSpaceSkyBrowser'," - "Identifier = 'ScreenSpaceBowser'," - "Name = 'Screen Space Bowser'," - "Url = 'http://localhost:8000/'," - "FaceCamera = false" - "}"; - - /* - ghoul::Dictionary node; - node.setValue("Type", "ScreenSpaceBrowser"s); - node.setValue("Identifier", "ScreenSpaceBowser"s); - node.setValue("Name", "Screen Space Bowser"s); - node.setValue("Url", "http://localhost:8000/"s); - */ - openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + node + ")", - scripting::ScriptEngine::RemoteScripting::Yes - ); + module->createBrowser(); + module->createTarget(); + return 1; } From 543e3641ab534e3a49acb665425c667837f7fbba Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 19 Mar 2021 09:57:14 +0100 Subject: [PATCH 035/251] Set target dimensions from browser dimensions --- .../include/screenspaceskybrowser.h | 10 +++ .../skybrowser/include/screenspaceskytarget.h | 15 ++++- modules/skybrowser/shaders/target_fs.glsl | 14 ++--- modules/skybrowser/skybrowsermodule.cpp | 16 +++-- modules/skybrowser/skybrowsermodule.h | 3 +- modules/skybrowser/skybrowsermodule_lua.inl | 19 ++++-- .../skybrowser/src/screenspaceskybrowser.cpp | 28 ++++++++- .../skybrowser/src/screenspaceskytarget.cpp | 62 +++++++++++++++++-- .../webbrowser/include/screenspacebrowser.h | 2 +- 9 files changed, 143 insertions(+), 26 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 999c3508a9..cfa839df55 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -19,16 +19,26 @@ namespace openspace { glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::vec2 coord); +<<<<<<< Updated upstream glm::vec2 coordIsOnResizeArea(glm::vec2 coord); +======= + bool coordIsOnResizeButton(glm::vec2 coord); + +>>>>>>> Stashed changes void scale(glm::vec2 scalingFactor); glm::mat4 scaleMatrix() override; void saveResizeStartSize(); void updateBrowserSize(); void scale(float scalingFactor); + + glm::vec2 getScreenSpaceBrowserDimension(); + bool _browserDimIsDirty; private: glm::vec2 _startSize; float _startScale; + properties::Vec2Property _browserDimensions; + }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index d68be1f7af..fcb1e9d89c 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -3,7 +3,11 @@ #include +#include #include +#include +#include + #include #include @@ -27,6 +31,8 @@ namespace openspace { void createShaders(); + void setScreenSpaceTargetDimension(glm::vec2 currentBrowserDimension); + glm::vec2 getScreenSpacePosition(); glm::vec2 getAnglePosition(); @@ -36,12 +42,17 @@ namespace openspace { glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::vec2 coord); + + glm::mat4 scaleMatrix() override; void bindTexture() override; private: - std::unique_ptr _texture; - UniformCache(modelTransform, viewProj, texture, borderWidth, scale) _uniformCache; + properties::Vec2Property _targetDimensions; + + std::unique_ptr _texture; + //glm::vec2 _browserDimension = glm::vec2(0); + UniformCache(modelTransform, viewProj, texture, borderWidth, targetRatio) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; }; diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 5b18ad2483..7182c50aeb 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,6 +1,6 @@ uniform sampler2D texture1; -uniform float Scale; -uniform float BorderWidth; +uniform float borderWidth; +uniform vec2 targetRatio; in vec2 vs_st; in vec4 vs_position; @@ -10,17 +10,17 @@ in vec4 vs_position; Fragment getFragment() { Fragment frag; - vec2 bl = step(vec2(BorderWidth),1.0-vs_st); // bottom-left line - vec2 tr = step(vec2(BorderWidth),vs_st); // top-right line - + // draw square border + vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line + vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); - frag.color = texture(texture1, vs_st); + frag.color = vec4(1,1,1,1); if(border == vec3(1.0)) { - frag.color.a = 0.0; } return frag; } + diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 41d9c4608d..dbae3abe82 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -182,6 +182,7 @@ SkyBrowserModule::SkyBrowserModule() } if (currentlyResizingBrowser) { currentlyResizingBrowser = false; + _skyBrowser->_browserDimIsDirty = false; _skyBrowser->updateBrowserSize(); return true; } @@ -301,8 +302,12 @@ void SkyBrowserModule::handleInteractions() { glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; _skyBrowser->scale(newSizeRelToOld); + // Make sure the browser doesn't move in directions it's not supposed to _skyBrowser->translate(mouseDragVector * abs(resizeVector) /2.f, startDragObjectPosBrowser); + + _skyTarget->setScreenSpaceTargetDimension(_skyBrowser->getScreenSpaceBrowserDimension()); + } } }); @@ -330,7 +335,7 @@ void SkyBrowserModule::WWTfollowCamera() { glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); - glm::vec2 angleOffset = _skyTarget->getAnglePosition(); + glm::vec2 angleOffset = _skyTarget ? _skyTarget->getAnglePosition() : glm::vec2(0); // Change view if target is moved glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); @@ -410,23 +415,26 @@ glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } -void SkyBrowserModule::createTarget() { +void SkyBrowserModule::createTarget(glm::ivec2 dimension) { + std::string browserDim = fmt::format("{{{},{}}}", dimension.x, dimension.y); + + LINFO(browserDim); using namespace std::string_literals; + std::string node = "{" "Type = 'ScreenSpaceSkyTarget'," "Identifier = 'ScreenSpaceTarget'," "Name = 'Screen Space Target'," "FaceCamera = false," - "Scale = 0.04," + "TargetDimensions = " + browserDim + "" "}"; openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index fbd77fc3b7..78b448e5bd 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -51,9 +51,8 @@ public: void WWTfollowCamera(); - // target - void createTarget(); void createBrowser(); + void createTarget(glm::ivec2 dimension); ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 945269b1b3..7a903388cf 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -44,6 +44,14 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkyBrowserModule* module = global::moduleEngine->module(); + ScreenSpaceSkyTarget* target = nullptr; + while (!target) { + target = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); + } + + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + module->initializeBrowser(browser, target); + module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); module->WWTfollowCamera(); module->handleInteractions(); @@ -54,11 +62,11 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - SkyBrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule* module = global::moduleEngine->module(); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); - module->initializeBrowser(browser, target); - module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); + + // target test + module->createTarget(browser->getScreenSpaceBrowserDimension()); return 1; } @@ -67,9 +75,10 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); + module->createBrowser(); module->createTarget(); - + return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index aad89b507b..78df553183 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -20,12 +20,33 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; + constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = + { + "BrowserDimensions", + "Browser Dimensions Info", + "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " + }; + + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { + + // [[codegen::verbatim(BrowserDimensionInfo.description)]] + std::optional browserDimensions; + }; + +#include "screenspaceskybrowser_codegen.cpp" } // namespace namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) + , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0.f), glm::ivec2(300.f)) { + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _browserDimensions = p.browserDimensions.value_or(_browserDimensions); + _browserDimensions.onChange([&]() { _browserDimIsDirty = true; }); + addProperty(_browserDimensions); + std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -109,13 +130,14 @@ namespace openspace { } // Scales the ScreenSpaceBrowser to a new ratio void ScreenSpaceSkyBrowser::scale(glm::vec2 scalingFactor) { - + // Scale on the y axis, this is to ensure that _scale = 1 is // equal to the height of the window scale(abs(scalingFactor.y)); // Resize the dimensions of the texture on the x axis glm::vec2 newSize = abs(scalingFactor) * _startSize; _texture->setDimensions(glm::ivec3(newSize, 1)); + _browserDimensions = newSize; // To not make it glitch... Makes it glitch in other ways however //updateBrowserSize(); } @@ -146,4 +168,8 @@ namespace openspace { void ScreenSpaceSkyBrowser::scale(float scalingFactor) { _scale = _startScale * scalingFactor; } + + glm::vec2 ScreenSpaceSkyBrowser::getScreenSpaceBrowserDimension() { + return _browserDimensions.value(); + } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index d0a63a38f4..6c1f319960 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -31,16 +31,39 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; - constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture1", "BorderWidth", "Scale" + constexpr const openspace::properties::Property::PropertyInfo TargetDimensionInfo = + { + "TargetDimensions", + "Target Dimensions Info", + "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " }; + constexpr const std::array UniformNames = { + "ModelTransform", "ViewProjectionMatrix", "texture1", "borderWidth", "targetRatio" + }; + + struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { + + // [[codegen::verbatim(TargetDimensionInfo.description)]] + std::optional targetDimensions; + }; + +#include "screenspaceskytarget_codegen.cpp" + } //namespace namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) + , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) { + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _targetDimensions = p.targetDimensions.value_or(_targetDimensions); + + addProperty(_targetDimensions); + + std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -51,6 +74,9 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); + + + /* std::unique_ptr texture = ghoul::io::TextureReader::ref().loadTexture(absPath("D:/Ylvas/OpenSpace/modules/skybrowser/target.png")); @@ -66,7 +92,9 @@ namespace openspace { _texture = std::move(texture); _objectSize = _texture->dimensions(); } + */ _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); + } void ScreenSpaceSkyTarget::bindTexture() { @@ -105,6 +133,22 @@ namespace openspace { return isReady(); } + glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { + // To ensure the plane has the right ratio + // The _scale us how much of the windows height the + // browser covers: eg a browser that covers 0.25 of the + // height of the window will have scale = 0.25 + float textureRatio = + static_cast(_targetDimensions.value().x) / static_cast(_targetDimensions.value().y); + + glm::mat4 scale = glm::scale( + glm::mat4(1.f), + glm::vec3(textureRatio * _scale, _scale, 1.f) + ); + return scale; + } + + void ScreenSpaceSkyTarget::createShaders() { _shader = global::renderEngine->buildRenderProgram( @@ -122,11 +166,14 @@ namespace openspace { glDisable(GL_CULL_FACE); glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float borderWidth = 0.002f; - + float borderWidth = 0.005f / _scale.value(); + glm::vec2 targetRatio; + + _targetDimensions.value() == glm::vec2(0) ? targetRatio = glm::vec2(1) : targetRatio = _targetDimensions.value() / _targetDimensions.value().y; _shader->activate(); _shader->setUniform(_uniformCache.borderWidth, borderWidth); + _shader->setUniform(_uniformCache.targetRatio, targetRatio); _shader->setUniform(_uniformCache.modelTransform, modelTransform); _shader->setUniform( @@ -184,4 +231,11 @@ namespace openspace { bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; return lessThanUpperRight && moreThanLowerLeft; } + + void ScreenSpaceSkyTarget::setScreenSpaceTargetDimension(glm::vec2 currentBrowserDimension) { + _targetDimensions = currentBrowserDimension; // TA IN SOM EN PROP! + } + + + } diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 1c039057df..ca0d1fe981 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -76,8 +76,8 @@ protected: properties::Vec2Property _dimensions; std::unique_ptr _browserInstance; std::unique_ptr _texture; - +private: class ScreenSpaceRenderHandler : public WebRenderHandler { public: From 65c3de6c86666313af18c4b1576a69c225eaee0d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 19 Mar 2021 11:08:37 +0100 Subject: [PATCH 036/251] Merge resolve fix --- modules/skybrowser/include/screenspaceskybrowser.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index cfa839df55..e5b72350d0 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -19,13 +19,7 @@ namespace openspace { glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::vec2 coord); -<<<<<<< Updated upstream glm::vec2 coordIsOnResizeArea(glm::vec2 coord); - -======= - bool coordIsOnResizeButton(glm::vec2 coord); - ->>>>>>> Stashed changes void scale(glm::vec2 scalingFactor); glm::mat4 scaleMatrix() override; void saveResizeStartSize(); From e463e35e1bfa665b8ca90371c3611afda3c4ab55 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 19 Mar 2021 11:26:39 +0100 Subject: [PATCH 037/251] Fix bug with target having flipped y-axis --- modules/skybrowser/shaders/target_vs.glsl | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/skybrowser/shaders/target_vs.glsl b/modules/skybrowser/shaders/target_vs.glsl index 316cc5adb8..ab1eb58a10 100644 --- a/modules/skybrowser/shaders/target_vs.glsl +++ b/modules/skybrowser/shaders/target_vs.glsl @@ -11,6 +11,6 @@ out vec4 vs_position; void main(){ vs_st = in_st; - vs_position = ViewProjectionMatrix * ModelTransform * in_position * vec4(1.0, -1.0, 1.0, 1.0); + vs_position = ViewProjectionMatrix * ModelTransform * in_position; gl_Position = vec4(vs_position); } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 7a903388cf..8b3772b928 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -75,9 +75,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); - module->createBrowser(); - module->createTarget(); return 1; } From d2d6899e7a5d2793c8829bdad9f25f927ceb35f4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 19 Mar 2021 13:50:48 +0100 Subject: [PATCH 038/251] Add draft for creating the browser and target from GUI. Still problem with finding browser after creation --- modules/skybrowser/skybrowsermodule.cpp | 64 ++++++++++++------- modules/skybrowser/skybrowsermodule.h | 6 +- modules/skybrowser/skybrowsermodule_lua.inl | 7 +- .../skybrowser/src/screenspaceskybrowser.cpp | 3 +- .../skybrowser/src/screenspaceskytarget.cpp | 1 - 5 files changed, 46 insertions(+), 35 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index dbae3abe82..c5e814483f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -51,13 +51,14 @@ #include // formatJson #include #include +#include namespace { - constexpr const openspace::properties::Property::PropertyInfo TestInfo = + constexpr const openspace::properties::Property::PropertyInfo ShowSkyBrowserInfo = { - "Test", - "Test Info", - "tjobidabidobidabidopp plopp" + "Show Sky Browser", + "Show Sky Browser", + "Show sky browser and target for WorldWide Telescope imagery." }; constexpr const openspace::properties::Property::PropertyInfo ZoomInfo = { @@ -68,8 +69,8 @@ namespace { struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { - // [[codegen::verbatim(TestInfo.description)]] - std::optional test; + // [[codegen::verbatim(ShowSkyBrowserInfo.description)]] + std::optional show; // [[codegen::verbatim(ZoomInfo.description)]] std::optional zoom; @@ -84,7 +85,7 @@ namespace openspace { SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) - , _testProperty(TestInfo) + , _showBrowserAndTarget(ShowSkyBrowserInfo) , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) , _skyTarget(nullptr) @@ -97,9 +98,25 @@ SkyBrowserModule::SkyBrowserModule() , mouseIsOnTarget(false) { - addProperty(_testProperty); + addProperty(_showBrowserAndTarget); addProperty(_zoomFactor); + _showBrowserAndTarget.onChange([&]() { + if (_showBrowserAndTarget) { + std::string skyBrowserID; + // Tried thread so that the browser would be instantiated... didn't work + std::thread createBrowser = std::thread([&] { + skyBrowserID = this->createBrowser(); + }); + createBrowser.join(); + // Sky browser is still nullptr + _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(skyBrowserID)); + std::string skyTargetID = createTarget(_skyBrowser->getScreenSpaceDimensions()); + _skyTarget = dynamic_cast(global::renderEngine->screenSpaceRenderable(skyTargetID)); + } + }); + + global::callback::mousePosition->emplace_back( [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); @@ -255,7 +272,7 @@ float SkyBrowserModule::zoomFactor() const{ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); - _testProperty = p.test.value_or(_testProperty); + _showBrowserAndTarget = p.show.value_or(_showBrowserAndTarget); _zoomFactor = p.zoom.value_or(_zoomFactor); // register ScreenSpaceBrowser @@ -384,8 +401,6 @@ ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { return msg; } - - void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget) { _skyBrowser = skyBrowser; @@ -415,17 +430,18 @@ glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } -void SkyBrowserModule::createTarget(glm::ivec2 dimension) { +std::string SkyBrowserModule::createTarget(glm::ivec2 dimension) { std::string browserDim = fmt::format("{{{},{}}}", dimension.x, dimension.y); LINFO(browserDim); using namespace std::string_literals; + std::string ID = "'ScreenSpaceTarget'"; std::string node = "{" "Type = 'ScreenSpaceSkyTarget'," - "Identifier = 'ScreenSpaceTarget'," + "Identifier = " + ID + "," "Name = 'Screen Space Target'," "FaceCamera = false," "TargetDimensions = " + browserDim + "" @@ -435,15 +451,13 @@ void SkyBrowserModule::createTarget(glm::ivec2 dimension) { "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); + return ID; } -void SkyBrowserModule::createBrowser() { - - SkyBrowserModule* module = global::moduleEngine->module(); +std::string SkyBrowserModule::createBrowser() { using namespace std::string_literals; - std::string node = "{" "Type = 'ScreenSpaceSkyBrowser'," "Identifier = 'ScreenSpaceBowser'," @@ -451,19 +465,21 @@ void SkyBrowserModule::createBrowser() { "Url = 'http://localhost:8000/'," "FaceCamera = false" "}"; - /* - ghoul::Dictionary node; - node.setValue("Type", "ScreenSpaceBrowser"s); - node.setValue("Identifier", "ScreenSpaceBowser"s); - node.setValue("Name", "Screen Space Bowser"s); - node.setValue("Url", "http://localhost:8000/"s); + ghoul::Dictionary skyBrowser; + std::string ID = "ScreenSpaceSkyBrowser1"; + skyBrowser.setValue("Type", "ScreenSpaceSkyBrowser"s); + skyBrowser.setValue("Identifier", "ScreenSpaceSkyBrowser1"s); + skyBrowser.setValue("Name", "Sky Browser"s); + skyBrowser.setValue("Url", "http://localhost:8000/"s); + skyBrowser.setValue("FaceCamera", "False"s); */ + openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + node + ")", scripting::ScriptEngine::RemoteScripting::Yes ); - + return "ScreenSpaceBowser"; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 78b448e5bd..e50554bf25 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -51,8 +51,8 @@ public: void WWTfollowCamera(); - void createBrowser(); - void createTarget(glm::ivec2 dimension); + std::string createBrowser(); + std::string createTarget(glm::ivec2 dimension); ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; @@ -71,7 +71,7 @@ protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; - properties::StringProperty _testProperty; + properties::BoolProperty _showBrowserAndTarget; properties::FloatProperty _zoomFactor; ScreenSpaceSkyBrowser* _skyBrowser; ScreenSpaceSkyTarget* _skyTarget; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 8b3772b928..e71b5c10cd 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -44,12 +44,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyTarget* target = nullptr; - while (!target) { - target = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); - } - + ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); + module->initializeBrowser(browser, target); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 78df553183..ffad7e9f7e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -137,9 +137,8 @@ namespace openspace { // Resize the dimensions of the texture on the x axis glm::vec2 newSize = abs(scalingFactor) * _startSize; _texture->setDimensions(glm::ivec3(newSize, 1)); + _objectSize = _texture->dimensions(); _browserDimensions = newSize; - // To not make it glitch... Makes it glitch in other ways however - //updateBrowserSize(); } glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 6c1f319960..79a4a007d1 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include From ac105178c8b497f62a1004aff4214a8bdc31cb6b Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 19 Mar 2021 14:42:11 +0100 Subject: [PATCH 039/251] Add scale function to screenspacetarget --- modules/skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/skybrowsermodule.cpp | 1 - modules/skybrowser/src/screenspaceskytarget.cpp | 4 ++++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index fcb1e9d89c..33384b4760 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -35,6 +35,7 @@ namespace openspace { glm::vec2 getScreenSpacePosition(); glm::vec2 getAnglePosition(); + void setScale(float scale); void translate(glm::vec2 translation, glm::vec2 position); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index c5e814483f..872a3baf78 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -116,7 +116,6 @@ SkyBrowserModule::SkyBrowserModule() } }); - global::callback::mousePosition->emplace_back( [&](double x, double y) { glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 79a4a007d1..ed07c4652f 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -102,6 +102,10 @@ namespace openspace { } } + void ScreenSpaceSkyTarget::setScale(float scale) { + _scale = scale; + } + bool ScreenSpaceSkyTarget::isReady() const { return _shader != nullptr; } From b17bb823594dddad99088db5621a3070c99eb132 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 19 Mar 2021 14:43:55 +0100 Subject: [PATCH 040/251] Change target to crosshair in relation to field of view --- .../skybrowser/include/screenspaceskytarget.h | 7 ++- modules/skybrowser/shaders/target_fs.glsl | 56 ++++++++++++++++++- modules/skybrowser/skybrowsermodule.cpp | 22 +++++--- modules/skybrowser/skybrowsermodule.h | 4 +- .../skybrowser/src/screenspaceskytarget.cpp | 13 +++-- 5 files changed, 82 insertions(+), 20 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index fcb1e9d89c..5e5c48e1f4 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -32,6 +32,7 @@ namespace openspace { void createShaders(); void setScreenSpaceTargetDimension(glm::vec2 currentBrowserDimension); + void updateFOV(float fov); glm::vec2 getScreenSpacePosition(); glm::vec2 getAnglePosition(); @@ -47,14 +48,14 @@ namespace openspace { void bindTexture() override; private: - + properties::Vec2Property _targetDimensions; - std::unique_ptr _texture; //glm::vec2 _browserDimension = glm::vec2(0); - UniformCache(modelTransform, viewProj, texture, borderWidth, targetRatio) _uniformCache; + UniformCache(modelTransform, viewProj, texture, fieldOfView, borderWidth, targetRatio) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; + float _fieldOfView = 100.f; }; } diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 7182c50aeb..7ab88be136 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,15 +1,32 @@ uniform sampler2D texture1; uniform float borderWidth; uniform vec2 targetRatio; +uniform float fieldOfView; in vec2 vs_st; in vec4 vs_position; +float box(in vec2 _st, in vec2 _size){ + _size = vec2(0.5) - _size*0.5; + vec2 uv = smoothstep(_size,_size, vs_st); + uv *= smoothstep(_size,_size,vec2(1.0)-vs_st); + return uv.x*uv.y; +} + +float cross(in vec2 _st, float _size){ + return box(vs_st, vec2(_size/.6, _size/3.)) + + box(vs_st, vec2(_size/5.,_size/.4)); +} + #include "fragment.glsl" Fragment getFragment() { Fragment frag; + + // draw cross + vec3 crosshair = vec3(cross(vs_st, 0.1)); + // draw square border vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line @@ -17,10 +34,43 @@ Fragment getFragment() { frag.color = vec4(1,1,1,1); + if(fieldOfView < 10.f) { + frag.color = vec4(1,1,1,1); + if(crosshair == vec3(0.0)) { + frag.color.a = 0.0; + } + } + else { + if(border == vec3(1.0)) { + frag.color.a = 0.0; + + } + } + + return frag; +} + + + /* + if(crosshair == vec3(0.0) { + frag.color.a = 0.0; + } + */ + + + /* + // draw square border + vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line + vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line + vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); + + frag.color = vec4(1,1,1,1); + if(border == vec3(1.0)) { frag.color.a = 0.0; } - - return frag; -} + + */ + + diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index dbae3abe82..ae987eca42 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -85,7 +85,7 @@ namespace openspace { SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _testProperty(TestInfo) - , _zoomFactor(ZoomInfo, 50.f ,0.1f ,70.f) + , _fieldOfView(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) , _skyTarget(nullptr) , _camIsSyncedWWT(true) @@ -98,7 +98,13 @@ SkyBrowserModule::SkyBrowserModule() { addProperty(_testProperty); - addProperty(_zoomFactor); + + _fieldOfView.onChange([&]() { + if (_skyTarget) { + _skyTarget->updateFOV(_fieldOfView); + } + }); + addProperty(_fieldOfView); global::callback::mousePosition->emplace_back( [&](double x, double y) { @@ -124,8 +130,8 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { if (mouseIsOnBrowser) { - float zoom = scroll > 0.0 ? -log(_zoomFactor + 1.1f) : log(_zoomFactor + 1.1f); - _zoomFactor = std::clamp(_zoomFactor + zoom, 0.001f, 70.0f); + float zoom = scroll > 0.0 ? -log(_fieldOfView + 1.1f) : log(_fieldOfView + 1.1f); + _fieldOfView = std::clamp(_fieldOfView + zoom, 0.001f, 70.0f); return true; } @@ -248,15 +254,15 @@ scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { return res; } -float SkyBrowserModule::zoomFactor() const{ - return _zoomFactor; +float SkyBrowserModule::fieldOfView() const{ + return _fieldOfView; } void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); _testProperty = p.test.value_or(_testProperty); - _zoomFactor = p.zoom.value_or(_zoomFactor); + _fieldOfView = p.zoom.value_or(_fieldOfView); // register ScreenSpaceBrowser auto fScreenSpaceRenderable = FactoryManager::ref().factory(); @@ -343,7 +349,7 @@ void SkyBrowserModule::WWTfollowCamera() { // Convert to celestial coordinates glm::dvec2 celestCoords = convertGalacticToCelestial(targetDirection); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _zoomFactor); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _fieldOfView); // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 78b448e5bd..cc565e4536 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -46,7 +46,7 @@ public: SkyBrowserModule(); virtual ~SkyBrowserModule() = default; - float zoomFactor() const; + float fieldOfView() const; glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; void WWTfollowCamera(); @@ -72,7 +72,7 @@ protected: void internalDeinitialize() override; properties::StringProperty _testProperty; - properties::FloatProperty _zoomFactor; + properties::FloatProperty _fieldOfView; ScreenSpaceSkyBrowser* _skyBrowser; ScreenSpaceSkyTarget* _skyTarget; bool _camIsSyncedWWT; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 6c1f319960..0b0652db8d 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -38,8 +38,8 @@ namespace { "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " }; - constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture1", "borderWidth", "targetRatio" + constexpr const std::array UniformNames = { + "ModelTransform", "ViewProjectionMatrix", "texture1", "fieldOfView", "borderWidth", "targetRatio" }; struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { @@ -168,10 +168,11 @@ namespace openspace { glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); float borderWidth = 0.005f / _scale.value(); glm::vec2 targetRatio; - + float fov = _fieldOfView; _targetDimensions.value() == glm::vec2(0) ? targetRatio = glm::vec2(1) : targetRatio = _targetDimensions.value() / _targetDimensions.value().y; _shader->activate(); + _shader->setUniform(_uniformCache.fieldOfView, fov); _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetRatio, targetRatio); _shader->setUniform(_uniformCache.modelTransform, modelTransform); @@ -233,7 +234,11 @@ namespace openspace { } void ScreenSpaceSkyTarget::setScreenSpaceTargetDimension(glm::vec2 currentBrowserDimension) { - _targetDimensions = currentBrowserDimension; // TA IN SOM EN PROP! + _targetDimensions = currentBrowserDimension; + } + + void ScreenSpaceSkyTarget::updateFOV(float fov) { + _fieldOfView = fov; } From 51f40172f7ab267dbb93aa2d10f3d5bfd43d09d4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 22 Mar 2021 09:50:19 +0100 Subject: [PATCH 041/251] Move browser specific functionality to screenspacebrowser --- .../include/screenspaceskybrowser.h | 33 ++- modules/skybrowser/skybrowsermodule.cpp | 280 +++++------------- modules/skybrowser/skybrowsermodule.h | 20 -- modules/skybrowser/skybrowsermodule_lua.inl | 5 +- .../skybrowser/src/screenspaceskybrowser.cpp | 141 ++++++++- 5 files changed, 233 insertions(+), 246 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index e5b72350d0..567fd9f864 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -4,34 +4,59 @@ #include namespace openspace { + class ScreenSpaceSkyTarget; class ScreenSpaceSkyBrowser : public ScreenSpaceBrowser { public: ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyBrowser() = default; + + bool deinitializeGL() override; + + // Communication with the webpage and WWT void executeJavascript(std::string& script) const; + ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; + ghoul::Dictionary createMessageForPausingWWTTime() const; + ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; + bool sendMessageToWWT(const ghoul::Dictionary& msg); + void sendMouseEvent(CefStructBase event, int x, int y) const; + void WWTfollowCamera(); + glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; + float fieldOfView() const; + void scrollZoom(float scroll); + + // Translation void translate(glm::vec2 translation); void translate(glm::vec2 translation, glm::vec2 position); + // Position and dimension and corners glm::vec2 getScreenSpacePosition(); glm::vec2 getScreenSpaceDimensions(); - void sendMouseEvent(CefStructBase event, int x, int y) const; glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); + glm::vec2 getScreenSpaceBrowserDimension(); + + // Mouse interaction bool coordIsInsideCornersScreenSpace(glm::vec2 coord); glm::vec2 coordIsOnResizeArea(glm::vec2 coord); + // Scaling void scale(glm::vec2 scalingFactor); + void scale(float scalingFactor); glm::mat4 scaleMatrix() override; + // Resizing void saveResizeStartSize(); void updateBrowserSize(); - void scale(float scalingFactor); - - glm::vec2 getScreenSpaceBrowserDimension(); + // Flag for dimensions bool _browserDimIsDirty; + properties::FloatProperty _fieldOfView; + ScreenSpaceSkyTarget* _skyTarget; private: glm::vec2 _startSize; float _startScale; properties::Vec2Property _browserDimensions; + bool _camIsSyncedWWT; + + std::thread _threadWWTMessages; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 866bc96ab3..60fef56a55 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -27,11 +27,8 @@ //#include //#include #include - #include - #include - #include #include #include @@ -39,18 +36,13 @@ #include #include #include -#include -#include -#include "skybrowsermodule_lua.inl" +#include "skybrowsermodule_lua.inl" #include #include #include - #include // For atan2 -#include // formatJson #include -#include #include namespace { @@ -60,20 +52,11 @@ namespace { "Show Sky Browser", "Show sky browser and target for WorldWide Telescope imagery." }; - constexpr const openspace::properties::Property::PropertyInfo ZoomInfo = - { - "Zoom", - "Zoom Info", - "tjobidabidobidabidopp plupp" - }; struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { // [[codegen::verbatim(ShowSkyBrowserInfo.description)]] std::optional show; - - // [[codegen::verbatim(ZoomInfo.description)]] - std::optional zoom; }; #include "skybrowsermodule_codegen.cpp" @@ -83,34 +66,62 @@ namespace { namespace openspace { + scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { + + scripting::LuaLibrary res; + res.name = "skybrowser"; + res.functions = { + { + "create", + &skybrowser::luascriptfunctions::createBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "move", + &skybrowser::luascriptfunctions::moveBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "follow", + &skybrowser::luascriptfunctions::followCamera, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "loacImgCollection", + &skybrowser::luascriptfunctions::loadImgCollection, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + } + }; + + return res; + } + + SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _showBrowserAndTarget(ShowSkyBrowserInfo) - , _fieldOfView(ZoomInfo, 50.f ,0.1f ,70.f) , _skyBrowser(nullptr) , _skyTarget(nullptr) - , _camIsSyncedWWT(true) , currentlyDraggingBrowser(false) , currentlyDraggingTarget(false) , currentlyResizingBrowser(false) - , _listenForInteractions(true) , mouseIsOnBrowser(false) , mouseIsOnTarget(false) { - addProperty(_showBrowserAndTarget); - addProperty(_fieldOfView); - - _fieldOfView.onChange([&]() { - if (_skyTarget) { - _skyTarget->updateFOV(_fieldOfView); - float scaleWhenFovIs10 = static_cast(10.f / global::windowDelegate->getHorizFieldOfView()); - _skyTarget->setScale(std::max(static_cast(_fieldOfView / global::windowDelegate->getHorizFieldOfView()), scaleWhenFovIs10)); - } - }); - - _showBrowserAndTarget.onChange([&]() { if (_showBrowserAndTarget) { @@ -145,14 +156,34 @@ SkyBrowserModule::SkyBrowserModule() else { mouseIsOnBrowser = false; } + + if (currentlyDraggingBrowser) { + _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); + } + if (currentlyDraggingTarget) { + _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); + } + if (currentlyResizingBrowser) { + // Calculate scaling factor + glm::vec2 mouseDragVector = (_mousePosition - startDragMousePosBrowser); + glm::vec2 scalingVector = mouseDragVector * resizeVector; + + glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; + _skyBrowser->scale(newSizeRelToOld); + + // Make sure the browser doesn't move in directions it's not supposed to + _skyBrowser->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPosBrowser); + + _skyTarget->setScreenSpaceTargetDimension(_skyBrowser->getScreenSpaceBrowserDimension()); + + } } ); global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { if (mouseIsOnBrowser) { - float zoom = scroll > 0.0 ? -log(_fieldOfView + 1.1f) : log(_fieldOfView + 1.1f); - _fieldOfView = std::clamp(_fieldOfView + zoom, 0.001f, 70.0f); + _skyBrowser->scrollZoom(scroll); return true; } @@ -221,69 +252,14 @@ SkyBrowserModule::SkyBrowserModule() } void SkyBrowserModule::internalDeinitialize() { - // Set flag to false so the thread can exit - _camIsSyncedWWT = false; - if (_threadWWTMessages.joinable()) { - _threadWWTMessages.join(); - LINFO("Joined thread"); - } - if (_threadHandleInteractions.joinable()) { - _threadHandleInteractions.join(); - LINFO("Joined thread"); - } -} -scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "skybrowser"; - res.functions = { - { - "create", - &skybrowser::luascriptfunctions::createBrowser, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, - { - "move", - &skybrowser::luascriptfunctions::moveBrowser, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, - { - "follow", - &skybrowser::luascriptfunctions::followCamera, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, - { - "loacImgCollection", - &skybrowser::luascriptfunctions::loadImgCollection, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - } - }; - - return res; -} - -float SkyBrowserModule::fieldOfView() const{ - return _fieldOfView; } void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); _showBrowserAndTarget = p.show.value_or(_showBrowserAndTarget); - _fieldOfView = p.zoom.value_or(_fieldOfView); // register ScreenSpaceBrowser auto fScreenSpaceRenderable = FactoryManager::ref().factory(); @@ -296,50 +272,6 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { } -bool SkyBrowserModule::sendMessageToWWT(const ghoul::Dictionary& msg) { - if (_skyBrowser) { - std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; - _skyBrowser->executeJavascript(script); - return true; - } - else { - LERROR("No sky browser added! Can't send message."); - return false; - } -} - -void SkyBrowserModule::handleInteractions() { - /* - CefStructBase event; - _skyBrowser->sendMouseEvent(event, scroll, scroll); - */ - _threadHandleInteractions = std::thread([&] { - while (_listenForInteractions) { - - if (currentlyDraggingBrowser) { - _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); - } - if (currentlyDraggingTarget) { - _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); - } - if (currentlyResizingBrowser) { - // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition - startDragMousePosBrowser); - glm::vec2 scalingVector = mouseDragVector * resizeVector; - - glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; - _skyBrowser->scale(newSizeRelToOld); - - // Make sure the browser doesn't move in directions it's not supposed to - _skyBrowser->translate(mouseDragVector * abs(resizeVector) /2.f, startDragObjectPosBrowser); - - _skyTarget->setScreenSpaceTargetDimension(_skyBrowser->getScreenSpaceBrowserDimension()); - - } - } - }); -} - glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { glm::vec2 size = global::windowDelegate->currentWindowSize(); // Change origin to middle of the window @@ -351,95 +283,17 @@ glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mouse return screenSpacePos; } -void SkyBrowserModule::WWTfollowCamera() { - - // Start a thread to enable user interaction while sending the calls to WWT - _threadWWTMessages = std::thread([&] { - while (_camIsSyncedWWT) { - - // Get camera view direction and orthogonal coordinate system of camera view direction - glm::vec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); - glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); - glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); - - glm::vec2 angleOffset = _skyTarget ? _skyTarget->getAnglePosition() : glm::vec2(0); - // Change view if target is moved - glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); - targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); - - - // Convert to celestial coordinates - glm::dvec2 celestCoords = convertGalacticToCelestial(targetDirection); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _fieldOfView); - - // Sleep so we don't bombard WWT with too many messages - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - sendMessageToWWT(message); - - } - }); - -} - -ghoul::Dictionary SkyBrowserModule::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "center_on_coordinates"s); - msg.setValue("ra", static_cast(celestCoords[0])); - msg.setValue("dec", static_cast(celestCoords[1])); - msg.setValue("fov", static_cast(fov)); - msg.setValue("instant", moveInstantly); - - return msg; -} - -ghoul::Dictionary SkyBrowserModule::createMessageForLoadingWWTImgColl(const std::string& url) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "center_on_coordinates"s); - msg.setValue("url", url); - - return msg; -} - -ghoul::Dictionary SkyBrowserModule::createMessageForPausingWWTTime() const { - - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "pause_time"s); - - return msg; -} - void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget) { _skyBrowser = skyBrowser; _skyTarget = skyTarget; + _skyBrowser->_skyTarget = _skyTarget; } ScreenSpaceSkyBrowser* SkyBrowserModule::skyBrowser() { return _skyBrowser; } -glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { - - // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> - // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 - -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 - -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 - }); - - glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; - float ra = atan2(rICRS[1], rICRS[0]); - float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); - - ra = ra > 0 ? ra : ra + (2 * glm::pi()); - - return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); -} - std::string SkyBrowserModule::createTarget(glm::ivec2 dimension) { std::string browserDim = fmt::format("{{{},{}}}", dimension.x, dimension.y); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index eb39fb2cf4..7706f99fda 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -45,21 +45,8 @@ public: SkyBrowserModule(); virtual ~SkyBrowserModule() = default; - - float fieldOfView() const; - glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; - - void WWTfollowCamera(); - std::string createBrowser(); std::string createTarget(glm::ivec2 dimension); - - ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; - ghoul::Dictionary createMessageForPausingWWTTime() const; - ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; - - bool sendMessageToWWT(const ghoul::Dictionary& msg); - void handleInteractions(); glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget); @@ -70,15 +57,9 @@ public: protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; - properties::BoolProperty _showBrowserAndTarget; - properties::FloatProperty _fieldOfView; ScreenSpaceSkyBrowser* _skyBrowser; ScreenSpaceSkyTarget* _skyTarget; - bool _camIsSyncedWWT; - bool _listenForInteractions; - std::thread _threadWWTMessages; - std::thread _threadHandleInteractions; glm::vec2 startDragMousePosBrowser; glm::vec2 startDragObjectPosBrowser; glm::vec2 startDragMousePosTarget; @@ -89,7 +70,6 @@ protected: bool currentlyResizingBrowser; bool currentlyDraggingTarget; glm::vec2 _mousePosition; - double _mouseScroll; bool mouseIsOnBrowser; bool mouseIsOnTarget; }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index e71b5c10cd..b81e657868 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -36,7 +36,7 @@ namespace openspace::skybrowser::luascriptfunctions { // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml std::string url = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - module->sendMessageToWWT(module->createMessageForLoadingWWTImgColl(url)); + module->skyBrowser()->sendMessageToWWT(module->skyBrowser()->createMessageForLoadingWWTImgColl(url)); return 1; } @@ -50,8 +50,7 @@ namespace openspace::skybrowser::luascriptfunctions { module->initializeBrowser(browser, target); module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); - module->WWTfollowCamera(); - module->handleInteractions(); + browser->WWTfollowCamera(); return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index ffad7e9f7e..5b3c97d12e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -1,21 +1,24 @@ #include -#include +#include #include #include #include -#include - #include #include -#include #include -#include - +#include #include #include #include +#include // formatJson +#include +#include #include #include +#include +#include +#include +#include // Milliseconds namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -26,11 +29,21 @@ namespace { "Browser Dimensions Info", "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " }; + constexpr const openspace::properties::Property::PropertyInfo ZoomInfo = + { + "Zoom", + "Zoom Info", + "tjobidabidobidabidopp plupp" + }; + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { // [[codegen::verbatim(BrowserDimensionInfo.description)]] std::optional browserDimensions; + + // [[codegen::verbatim(ZoomInfo.description)]] + std::optional zoom; }; #include "screenspaceskybrowser_codegen.cpp" @@ -40,6 +53,8 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0.f), glm::ivec2(300.f)) + , _fieldOfView(ZoomInfo, 50.f, 0.1f, 70.f) + , _camIsSyncedWWT(true) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -47,6 +62,17 @@ namespace openspace { _browserDimensions.onChange([&]() { _browserDimIsDirty = true; }); addProperty(_browserDimensions); + _fieldOfView = p.zoom.value_or(_fieldOfView); + addProperty(_fieldOfView); + + _fieldOfView.onChange([&]() { + if (_skyTarget) { + _skyTarget->updateFOV(_fieldOfView); + float scaleWhenFovIs10 = static_cast(10.f / global::windowDelegate->getHorizFieldOfView()); + _skyTarget->setScale(std::max(static_cast(_fieldOfView / global::windowDelegate->getHorizFieldOfView()), scaleWhenFovIs10)); + } + }); + std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -61,6 +87,25 @@ namespace openspace { _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); } + bool ScreenSpaceSkyBrowser::deinitializeGL() { + // Set flag to false so the thread can exit + _camIsSyncedWWT = false; + if (_threadWWTMessages.joinable()) { + _threadWWTMessages.join(); + LINFO("Joined thread"); + } + return ScreenSpaceBrowser::deinitializeGL(); + } + + float ScreenSpaceSkyBrowser::fieldOfView() const { + return _fieldOfView; + } + + void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { + float zoom = scroll > 0.0 ? -log(_fieldOfView + 1.1f) : log(_fieldOfView + 1.1f); + _fieldOfView = std::clamp(_fieldOfView + zoom, 0.001f, 70.0f); + } + void ScreenSpaceSkyBrowser::executeJavascript(std::string& script) const { //LINFOC(_loggerCat, "Executing javascript " + script); if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) { @@ -68,6 +113,42 @@ namespace openspace { frame->ExecuteJavaScript(script, frame->GetURL(), 0); } } + bool ScreenSpaceSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) { + std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; + executeJavascript(script); + return true; + } + + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("ra", static_cast(celestCoords[0])); + msg.setValue("dec", static_cast(celestCoords[1])); + msg.setValue("fov", static_cast(fov)); + msg.setValue("instant", moveInstantly); + + return msg; + } + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForLoadingWWTImgColl(const std::string& url) const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("url", url); + + return msg; + } + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForPausingWWTTime() const { + + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "pause_time"s); + + return msg; + } void ScreenSpaceSkyBrowser::sendMouseEvent(CefStructBase event, int x, int y) const { //LINFOC(_loggerCat, "Executing javascript " + script); @@ -80,6 +161,54 @@ namespace openspace { } } + void ScreenSpaceSkyBrowser::WWTfollowCamera() { + + // Start a thread to enable user interaction while sending the calls to WWT + _threadWWTMessages = std::thread([&] { + while (_camIsSyncedWWT) { + + // Get camera view direction and orthogonal coordinate system of camera view direction + glm::vec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); + glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); + + glm::vec2 angleOffset = _skyTarget ? _skyTarget->getAnglePosition() : glm::vec2(0); + // Change view if target is moved + glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); + targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); + + // Convert to celestial coordinates + glm::dvec2 celestCoords = convertGalacticToCelestial(targetDirection); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _fieldOfView); + + // Sleep so we don't bombard WWT with too many messages + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + sendMessageToWWT(message); + + } + }); + + } + + glm::dvec2 ScreenSpaceSkyBrowser::convertGalacticToCelestial(glm::dvec3 rGal) const { + + // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> + // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 + -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 + -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 + }); + + glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; + float ra = atan2(rICRS[1], rICRS[0]); + float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); + + ra = ra > 0 ? ra : ra + (2 * glm::pi()); + + return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); + } + void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { glm::vec3 position = _cartesianPosition; _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); From ac275140c5ea75ea94887e44a9f99b0585fa2331 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 22 Mar 2021 13:54:01 +0100 Subject: [PATCH 042/251] Load browser and target as assets --- data/assets/skyBrowser.asset | 12 +++ data/assets/skyTarget.asset | 11 +++ modules/skybrowser/data/skyBrowser.asset | 11 +++ modules/skybrowser/data/skyTarget.asset | 10 +++ .../include/screenspaceskybrowser.h | 9 ++- .../skybrowser/include/screenspaceskytarget.h | 14 ++-- modules/skybrowser/skybrowsermodule.cpp | 77 ++----------------- modules/skybrowser/skybrowsermodule.h | 6 +- modules/skybrowser/skybrowsermodule_lua.inl | 23 +----- .../skybrowser/src/screenspaceskybrowser.cpp | 52 ++++++++++++- .../skybrowser/src/screenspaceskytarget.cpp | 55 +++++++------ 11 files changed, 150 insertions(+), 130 deletions(-) create mode 100644 data/assets/skyBrowser.asset create mode 100644 data/assets/skyTarget.asset create mode 100644 modules/skybrowser/data/skyBrowser.asset create mode 100644 modules/skybrowser/data/skyTarget.asset diff --git a/data/assets/skyBrowser.asset b/data/assets/skyBrowser.asset new file mode 100644 index 0000000000..fdb723616c --- /dev/null +++ b/data/assets/skyBrowser.asset @@ -0,0 +1,12 @@ +local assetHelper = asset.require('util/asset_helper') + + local spec = { + Type = "ScreenSpaceSkyBrowser", + Identifier = "SkyBrowser1", + Name = "SkyBrowser", + Url = "http://localhost:8000/", + FaceCamera = false, + TargetID = "SkyTarget1" + }; + +assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/data/assets/skyTarget.asset b/data/assets/skyTarget.asset new file mode 100644 index 0000000000..a699553bc2 --- /dev/null +++ b/data/assets/skyTarget.asset @@ -0,0 +1,11 @@ +local assetHelper = asset.require('util/asset_helper') + + local spec = { + Type = "ScreenSpaceSkyTarget", + Identifier = "SkyTarget1", + Name = "Target", + FaceCamera = false, + BrowserID = "SkyBrowser1" + }; + +assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/data/skyBrowser.asset b/modules/skybrowser/data/skyBrowser.asset new file mode 100644 index 0000000000..b672166a03 --- /dev/null +++ b/modules/skybrowser/data/skyBrowser.asset @@ -0,0 +1,11 @@ +local assetHelper = asset.require('util/asset_helper') + + local spec = { + Type = "ScreenSpaceSkyBrowser", + Identifier = "SkyBrowser1", + Name = "SkyBrowser", + Url = "http://localhost:8000/", + FaceCamera = false + }; + +assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/data/skyTarget.asset b/modules/skybrowser/data/skyTarget.asset new file mode 100644 index 0000000000..547b43ad15 --- /dev/null +++ b/modules/skybrowser/data/skyTarget.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') + + local spec = { + Type = "ScreenSpaceSkyTarget", + Identifier = "SkyTarget1", + Name = "Target", + FaceCamera = false + }; + +assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 567fd9f864..51742fbc91 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -2,6 +2,7 @@ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ #include +#include namespace openspace { class ScreenSpaceSkyTarget; @@ -12,7 +13,9 @@ namespace openspace { ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyBrowser() = default; + bool initializeGL() override; bool deinitializeGL() override; + bool setConnectedTarget(); // Communication with the webpage and WWT void executeJavascript(std::string& script) const; @@ -35,7 +38,7 @@ namespace openspace { glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); glm::vec2 getScreenSpaceBrowserDimension(); - + // Mouse interaction bool coordIsInsideCornersScreenSpace(glm::vec2 coord); glm::vec2 coordIsOnResizeArea(glm::vec2 coord); @@ -49,13 +52,13 @@ namespace openspace { // Flag for dimensions bool _browserDimIsDirty; properties::FloatProperty _fieldOfView; - ScreenSpaceSkyTarget* _skyTarget; + properties::StringProperty _skyTargetID; private: glm::vec2 _startSize; float _startScale; properties::Vec2Property _browserDimensions; bool _camIsSyncedWWT; - + ScreenSpaceSkyTarget* _skyTarget; std::thread _threadWWTMessages; }; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 2ab7eb3d2c..2ad017ebe0 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -2,20 +2,20 @@ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ #include - #include #include +#include #include #include - #include - #include namespace openspace::documentation { struct Documentation; } namespace openspace { + class ScreenSpaceSkyBrowser; + class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { public: @@ -31,12 +31,15 @@ namespace openspace { void createShaders(); - void setScreenSpaceTargetDimension(glm::vec2 currentBrowserDimension); + void setBrowser(ScreenSpaceSkyBrowser* browser); + + void setDimensions(glm::vec2 currentBrowserDimensions); void updateFOV(float fov); glm::vec2 getScreenSpacePosition(); glm::vec2 getAnglePosition(); void setScale(float scale); + void setConnectedBrowser(); void translate(glm::vec2 translation, glm::vec2 position); @@ -48,15 +51,16 @@ namespace openspace { glm::mat4 scaleMatrix() override; void bindTexture() override; + properties::StringProperty _skyBrowserID; private: properties::Vec2Property _targetDimensions; std::unique_ptr _texture; - //glm::vec2 _browserDimension = glm::vec2(0); UniformCache(modelTransform, viewProj, texture, fieldOfView, borderWidth, targetRatio) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; float _fieldOfView = 100.f; + ScreenSpaceSkyBrowser* _skyBrowser; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 60fef56a55..7f5cfc4142 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -125,16 +125,8 @@ SkyBrowserModule::SkyBrowserModule() _showBrowserAndTarget.onChange([&]() { if (_showBrowserAndTarget) { - std::string skyBrowserID; - // Tried thread so that the browser would be instantiated... didn't work - std::thread createBrowser = std::thread([&] { - skyBrowserID = this->createBrowser(); - }); - createBrowser.join(); - // Sky browser is still nullptr - _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(skyBrowserID)); - std::string skyTargetID = createTarget(_skyBrowser->getScreenSpaceDimensions()); - _skyTarget = dynamic_cast(global::renderEngine->screenSpaceRenderable(skyTargetID)); + _skyBrowser->setConnectedTarget(); + _skyTarget->setConnectedBrowser(); } }); @@ -174,7 +166,7 @@ SkyBrowserModule::SkyBrowserModule() // Make sure the browser doesn't move in directions it's not supposed to _skyBrowser->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPosBrowser); - _skyTarget->setScreenSpaceTargetDimension(_skyBrowser->getScreenSpaceBrowserDimension()); + // _skyTarget->setDimensions(_skyBrowser->getScreenSpaceBrowserDimension()); } } @@ -240,7 +232,6 @@ SkyBrowserModule::SkyBrowserModule() } if (currentlyResizingBrowser) { currentlyResizingBrowser = false; - _skyBrowser->_browserDimIsDirty = false; _skyBrowser->updateBrowserSize(); return true; } @@ -283,67 +274,13 @@ glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mouse return screenSpacePos; } -void SkyBrowserModule::initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget) { - - _skyBrowser = skyBrowser; - _skyTarget = skyTarget; - _skyBrowser->_skyTarget = _skyTarget; -} - -ScreenSpaceSkyBrowser* SkyBrowserModule::skyBrowser() { - return _skyBrowser; -} - -std::string SkyBrowserModule::createTarget(glm::ivec2 dimension) { - - std::string browserDim = fmt::format("{{{},{}}}", dimension.x, dimension.y); - - LINFO(browserDim); - using namespace std::string_literals; - - std::string ID = "'ScreenSpaceTarget'"; - - std::string node = "{" - "Type = 'ScreenSpaceSkyTarget'," - "Identifier = " + ID + "," - "Name = 'Screen Space Target'," - "FaceCamera = false," - "TargetDimensions = " + browserDim + "" - "}"; - - openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + node + ")", - scripting::ScriptEngine::RemoteScripting::Yes - ); - return ID; +void SkyBrowserModule::addSkyBrowser(ScreenSpaceSkyBrowser* browser) { + _skyBrowser = browser; } -std::string SkyBrowserModule::createBrowser() { - - using namespace std::string_literals; - std::string node = "{" - "Type = 'ScreenSpaceSkyBrowser'," - "Identifier = 'ScreenSpaceBowser'," - "Name = 'Screen Space Bowser'," - "Url = 'http://localhost:8000/'," - "FaceCamera = false" - "}"; - /* - ghoul::Dictionary skyBrowser; - std::string ID = "ScreenSpaceSkyBrowser1"; - skyBrowser.setValue("Type", "ScreenSpaceSkyBrowser"s); - skyBrowser.setValue("Identifier", "ScreenSpaceSkyBrowser1"s); - skyBrowser.setValue("Name", "Sky Browser"s); - skyBrowser.setValue("Url", "http://localhost:8000/"s); - skyBrowser.setValue("FaceCamera", "False"s); - */ - - openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + node + ")", - scripting::ScriptEngine::RemoteScripting::Yes - ); - return "ScreenSpaceBowser"; +void SkyBrowserModule::addSkyTarget(ScreenSpaceSkyTarget* target) { + _skyTarget = target; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 7706f99fda..ad73291af2 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -45,12 +45,10 @@ public: SkyBrowserModule(); virtual ~SkyBrowserModule() = default; - std::string createBrowser(); - std::string createTarget(glm::ivec2 dimension); glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); - void initializeBrowser(ScreenSpaceSkyBrowser* skyBrowser, ScreenSpaceSkyTarget* skyTarget); - ScreenSpaceSkyBrowser* skyBrowser(); + void addSkyBrowser(ScreenSpaceSkyBrowser* browser); + void addSkyTarget(ScreenSpaceSkyTarget* target); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b81e657868..1c068aaf22 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -33,45 +33,24 @@ namespace openspace::skybrowser::luascriptfunctions { int loadImgCollection(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); - // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml - std::string url = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - module->skyBrowser()->sendMessageToWWT(module->skyBrowser()->createMessageForLoadingWWTImgColl(url)); + return 1; } int followCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); - - SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceTarget")); - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - - module->initializeBrowser(browser, target); - module->skyBrowser()->translate(glm::vec3(-0.8, -0.4, 0.0)); - - browser->WWTfollowCamera(); return 1; } int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - - SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("ScreenSpaceBowser")); - - // target test - module->createTarget(browser->getScreenSpaceBrowserDimension()); - return 1; } int createBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); - SkyBrowserModule* module = global::moduleEngine->module(); - module->createBrowser(); return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 5b3c97d12e..017ad0be93 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,6 +9,7 @@ #include #include #include +#include #include #include #include // formatJson @@ -35,6 +37,12 @@ namespace { "Zoom Info", "tjobidabidobidabidopp plupp" }; + constexpr const openspace::properties::Property::PropertyInfo TargetIDInfo = + { + "TargetID", + "Target Info", + "tjobidabidobidabidopp plupp" + }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -44,6 +52,9 @@ namespace { // [[codegen::verbatim(ZoomInfo.description)]] std::optional zoom; + + // [[codegen::verbatim(TargetIDInfo.description)]] + std::optional targetID; }; #include "screenspaceskybrowser_codegen.cpp" @@ -54,17 +65,33 @@ namespace openspace { : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0.f), glm::ivec2(300.f)) , _fieldOfView(ZoomInfo, 50.f, 0.1f, 70.f) + , _skyTargetID(TargetIDInfo) , _camIsSyncedWWT(true) + , _skyTarget(nullptr) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _browserDimensions = p.browserDimensions.value_or(_browserDimensions); - _browserDimensions.onChange([&]() { _browserDimIsDirty = true; }); + _browserDimensions.onChange([&]() { + if (!_skyTarget) { + setConnectedTarget(); + } + else { + _skyTarget->setDimensions(getScreenSpaceBrowserDimension()); + } + }); addProperty(_browserDimensions); _fieldOfView = p.zoom.value_or(_fieldOfView); addProperty(_fieldOfView); + _skyTargetID = p.targetID.value_or(_skyTargetID); + addProperty(_skyTargetID); + + _skyTargetID.onChange([&]() { + setConnectedTarget(); + }); + _fieldOfView.onChange([&]() { if (_skyTarget) { _skyTarget->updateFOV(_fieldOfView); @@ -72,7 +99,7 @@ namespace openspace { _skyTarget->setScale(std::max(static_cast(_fieldOfView / global::windowDelegate->getHorizFieldOfView()), scaleWhenFovIs10)); } }); - + std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -87,6 +114,18 @@ namespace openspace { _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); } + bool ScreenSpaceSkyBrowser::initializeGL() { + global::moduleEngine->module()->addSkyBrowser(this); + setConnectedTarget(); + if (_skyTarget) { + _skyTarget->setDimensions(getScreenSpaceBrowserDimension()); + } + + WWTfollowCamera(); + + return ScreenSpaceBrowser::initializeGL(); + } + bool ScreenSpaceSkyBrowser::deinitializeGL() { // Set flag to false so the thread can exit _camIsSyncedWWT = false; @@ -97,6 +136,11 @@ namespace openspace { return ScreenSpaceBrowser::deinitializeGL(); } + bool ScreenSpaceSkyBrowser::setConnectedTarget() { + _skyTarget = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyTargetID.value())); + return _skyTarget != nullptr; + } + float ScreenSpaceSkyBrowser::fieldOfView() const { return _fieldOfView; } @@ -133,6 +177,7 @@ namespace openspace { } ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForLoadingWWTImgColl(const std::string& url) const { + // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "center_on_coordinates"s); @@ -184,9 +229,8 @@ namespace openspace { // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); sendMessageToWWT(message); - } - }); + }); } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index d087914fc5..113802d770 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,5 +1,6 @@ #include - +#include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include +#include #include #include #include @@ -41,10 +43,20 @@ namespace { "ModelTransform", "ViewProjectionMatrix", "texture1", "fieldOfView", "borderWidth", "targetRatio" }; + constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = + { + "BrowserID", + "Browser Info", + "tjobidabidobidabidopp plupp" + }; + struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { // [[codegen::verbatim(TargetDimensionInfo.description)]] std::optional targetDimensions; + + // [[codegen::verbatim(BrowserIDInfo.description)]] + std::optional browserID; }; #include "screenspaceskytarget_codegen.cpp" @@ -55,12 +67,19 @@ namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) + , _skyBrowserID(BrowserIDInfo) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _targetDimensions = p.targetDimensions.value_or(_targetDimensions); addProperty(_targetDimensions); + _skyBrowserID = p.browserID.value_or(_skyBrowserID); + addProperty(_skyBrowserID); + + _skyBrowserID.onChange([&]() { + setConnectedBrowser(); + }); std::string identifier; @@ -73,25 +92,6 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - - - /* - std::unique_ptr texture = - ghoul::io::TextureReader::ref().loadTexture(absPath("D:/Ylvas/OpenSpace/modules/skybrowser/target.png")); - - if (texture) { - // Images don't need to start on 4-byte boundaries, for example if the - // image is only RGB - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); - texture->purgeFromRAM(); - - _texture = std::move(texture); - _objectSize = _texture->dimensions(); - } - */ _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); } @@ -106,11 +106,18 @@ namespace openspace { _scale = scale; } + void ScreenSpaceSkyTarget::setConnectedBrowser() { + _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + } + bool ScreenSpaceSkyTarget::isReady() const { return _shader != nullptr; } bool ScreenSpaceSkyTarget::initializeGL() { + global::moduleEngine->module()->addSkyTarget(this); + + setConnectedBrowser(); glGenVertexArrays(1, &_vertexArray); glGenBuffers(1, &_vertexBuffer); @@ -164,6 +171,10 @@ namespace openspace { } + void ScreenSpaceSkyTarget::setBrowser(ScreenSpaceSkyBrowser* browser) { + _skyBrowser = browser; + } + void ScreenSpaceSkyTarget::render() { glDisable(GL_CULL_FACE); @@ -236,8 +247,8 @@ namespace openspace { return lessThanUpperRight && moreThanLowerLeft; } - void ScreenSpaceSkyTarget::setScreenSpaceTargetDimension(glm::vec2 currentBrowserDimension) { - _targetDimensions = currentBrowserDimension; + void ScreenSpaceSkyTarget::setDimensions(glm::vec2 currentBrowserDimensions) { + _targetDimensions = currentBrowserDimensions; } void ScreenSpaceSkyTarget::updateFOV(float fov) { From fbc05244e1125cfa3314e2607e98329314be2d17 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 23 Mar 2021 09:44:14 +0100 Subject: [PATCH 043/251] Make it possible to add many browsers and targets by moving functionality to ScreenSpaceRenderable --- .../rendering/screenspacerenderable.h | 12 ++ .../include/screenspaceskybrowser.h | 13 +- .../skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/skybrowsermodule.cpp | 178 ++++++++---------- modules/skybrowser/skybrowsermodule.h | 33 ++-- .../skybrowser/src/screenspaceskybrowser.cpp | 39 +--- .../skybrowser/src/screenspaceskytarget.cpp | 8 +- src/rendering/screenspacerenderable.cpp | 30 +++ 8 files changed, 158 insertions(+), 156 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 8d4d073843..5e79c90c74 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -71,6 +71,18 @@ public: bool isEnabled() const; float depth(); + // Added by skybrowser team + // Screen space functionality in these coords: [-1,1][-ratio,ratio] + glm::vec2 getScreenSpacePosition(); + glm::vec2 getScreenSpaceDimensions(); + glm::vec2 getUpperRightCornerScreenSpace(); + glm::vec2 getLowerLeftCornerScreenSpace(); + bool coordIsInsideCornersScreenSpace(glm::vec2 coord); + void translate(glm::vec2 translation, glm::vec2 position); + friend bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs); + + // End of addition by skybrowser team + static documentation::Documentation Documentation(); protected: diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 51742fbc91..8b2d43459e 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -30,17 +30,12 @@ namespace openspace { void scrollZoom(float scroll); // Translation - void translate(glm::vec2 translation); - void translate(glm::vec2 translation, glm::vec2 position); + //void translate(glm::vec2 translation); + // Position and dimension and corners - glm::vec2 getScreenSpacePosition(); - glm::vec2 getScreenSpaceDimensions(); - glm::vec2 getUpperRightCornerScreenSpace(); - glm::vec2 getLowerLeftCornerScreenSpace(); + glm::vec2 getScreenSpaceBrowserDimension(); - // Mouse interaction - bool coordIsInsideCornersScreenSpace(glm::vec2 coord); glm::vec2 coordIsOnResizeArea(glm::vec2 coord); // Scaling void scale(glm::vec2 scalingFactor); @@ -54,7 +49,7 @@ namespace openspace { properties::FloatProperty _fieldOfView; properties::StringProperty _skyTargetID; private: - glm::vec2 _startSize; + glm::vec2 _startDimensionsSize; float _startScale; properties::Vec2Property _browserDimensions; bool _camIsSyncedWWT; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 2ad017ebe0..76b8d11f37 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -32,6 +32,7 @@ namespace openspace { void createShaders(); void setBrowser(ScreenSpaceSkyBrowser* browser); + ScreenSpaceSkyBrowser* getSkyBrowser(); void setDimensions(glm::vec2 currentBrowserDimensions); void updateFOV(float fov); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 7f5cfc4142..6e9461b68a 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -31,14 +31,13 @@ #include #include #include -#include +#include #include #include +#include #include #include - #include "skybrowsermodule_lua.inl" -#include #include #include #include // For atan2 @@ -46,26 +45,18 @@ #include namespace { - constexpr const openspace::properties::Property::PropertyInfo ShowSkyBrowserInfo = - { - "Show Sky Browser", - "Show Sky Browser", - "Show sky browser and target for WorldWide Telescope imagery." - }; + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { - - // [[codegen::verbatim(ShowSkyBrowserInfo.description)]] - std::optional show; }; #include "skybrowsermodule_codegen.cpp" + } // namespace namespace openspace { - + scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { scripting::LuaLibrary res; @@ -111,74 +102,66 @@ namespace openspace { SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) - , _showBrowserAndTarget(ShowSkyBrowserInfo) - , _skyBrowser(nullptr) - , _skyTarget(nullptr) - , currentlyDraggingBrowser(false) - , currentlyDraggingTarget(false) + , _mouseOnObject(nullptr) , currentlyResizingBrowser(false) - , mouseIsOnBrowser(false) - , mouseIsOnTarget(false) - + , currentlyDraggingObject(false) + , resizeVector(0.f, 0.f) + , shouldInitialize(true) { - addProperty(_showBrowserAndTarget); - - _showBrowserAndTarget.onChange([&]() { - if (_showBrowserAndTarget) { - _skyBrowser->setConnectedTarget(); - _skyTarget->setConnectedBrowser(); - } - }); - global::callback::mousePosition->emplace_back( - [&](double x, double y) { + [&](double x, double y) { + // Quick fix to make all renderables find its corresponding partner + if (shouldInitialize) { + std::for_each(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { + if (to_target(obj)) { + to_target(obj)->setConnectedBrowser(); + } + else if (to_browser(obj)) { + to_browser(obj)->setConnectedTarget(); + } + }); + shouldInitialize = false; + } + glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); - _mousePosition = getMousePositionInScreenSpaceCoords(pos); - if (_skyTarget) { - mouseIsOnTarget = _skyTarget->coordIsInsideCornersScreenSpace(_mousePosition); + if (currentlyDraggingObject) { + _mouseOnObject->translate(_mousePosition - startDragMousePos, startDragObjectPos); } - else { - mouseIsOnTarget = false; - } - if (_skyBrowser) { - mouseIsOnBrowser = _skyBrowser->coordIsInsideCornersScreenSpace(_mousePosition); - } - else { - mouseIsOnBrowser = false; - } - - if (currentlyDraggingBrowser) { - _skyBrowser->translate(_mousePosition - startDragMousePosBrowser, startDragObjectPosBrowser); - } - if (currentlyDraggingTarget) { - _skyTarget->translate(_mousePosition - startDragMousePosTarget, startDragObjectPosTarget); - } - if (currentlyResizingBrowser) { + else if (currentlyResizingBrowser) { // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition - startDragMousePosBrowser); + glm::vec2 mouseDragVector = (_mousePosition - startDragMousePos); glm::vec2 scalingVector = mouseDragVector * resizeVector; - glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; - _skyBrowser->scale(newSizeRelToOld); + // Scale the browser + to_browser(_mouseOnObject)->scale(newSizeRelToOld); + // For dragging functionality, translate so it looks like the browser isn't moving // Make sure the browser doesn't move in directions it's not supposed to - _skyBrowser->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPosBrowser); - - // _skyTarget->setDimensions(_skyBrowser->getScreenSpaceBrowserDimension()); - + _mouseOnObject->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPos); + } + // If there is no dragging or resizing, look for new objects + else { + auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { + return obj->coordIsInsideCornersScreenSpace(_mousePosition); + }); + _mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr; } } ); global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - if (mouseIsOnBrowser) { - _skyBrowser->scrollZoom(scroll); + // If mouse is on browser, apply zoom + if (to_browser(_mouseOnObject)) { + to_browser(_mouseOnObject)->scrollZoom(scroll); return true; } - + else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { + to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); + } + return false; } ); @@ -187,52 +170,42 @@ SkyBrowserModule::SkyBrowserModule() [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { if (action == MouseAction::Press) { - - if (mouseIsOnBrowser && button == MouseButton::Left) { - - startDragMousePosBrowser = _mousePosition; - startDragObjectPosBrowser = _skyBrowser->getScreenSpacePosition(); - // Resize browser if mouse is over resize button - resizeVector = _skyBrowser->coordIsOnResizeArea(_mousePosition); - if (resizeVector != glm::vec2{0}) { - _skyBrowser->saveResizeStartSize(); - startResizeBrowserSize = _skyBrowser->getScreenSpaceDimensions(); - currentlyResizingBrowser = true; + if (_mouseOnObject && button == MouseButton::Left) { + startDragMousePos = _mousePosition; + startDragObjectPos = _mouseOnObject->getScreenSpacePosition(); + + // If current object is browser, check for resizing + if (to_browser(_mouseOnObject)) { + // Resize browser if mouse is over resize button + resizeVector = to_browser(_mouseOnObject)->coordIsOnResizeArea(_mousePosition); + if (resizeVector != glm::vec2{ 0 }) { + to_browser(_mouseOnObject)->saveResizeStartSize(); + startResizeBrowserSize = to_browser(_mouseOnObject)->getScreenSpaceDimensions(); + currentlyResizingBrowser = true; + return true; + } } - else { - currentlyDraggingBrowser = true; - } - + currentlyDraggingObject = true; + return true; } - else if (mouseIsOnTarget && button == MouseButton::Left) { - - startDragMousePosTarget = _mousePosition; - startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); - currentlyDraggingTarget = true; - return true; - } - else if (mouseIsOnBrowser && button == MouseButton::Right) { + else if (to_browser(_mouseOnObject) && button == MouseButton::Right) { - startDragMousePosTarget = _mousePosition; - startDragObjectPosTarget = _skyTarget->getScreenSpacePosition(); - currentlyDraggingTarget = true; + //startDragMousePos = _mousePosition; + //startDragObjectPos = dynamic_cast(_mouseOnObject)->->getScreenSpacePosition(); + //currentlyDraggingObject = true; return true; } } else if (action == MouseAction::Release) { - if (currentlyDraggingBrowser) { - currentlyDraggingBrowser = false; - return true; - } - if (currentlyDraggingTarget) { - currentlyDraggingTarget = false; + if (currentlyDraggingObject) { + currentlyDraggingObject = false; return true; } if (currentlyResizingBrowser) { currentlyResizingBrowser = false; - _skyBrowser->updateBrowserSize(); + to_browser(_mouseOnObject)->updateBrowserSize(); return true; } } @@ -250,7 +223,6 @@ void SkyBrowserModule::internalDeinitialize() { void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); - _showBrowserAndTarget = p.show.value_or(_showBrowserAndTarget); // register ScreenSpaceBrowser auto fScreenSpaceRenderable = FactoryManager::ref().factory(); @@ -274,13 +246,17 @@ glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mouse return screenSpacePos; } -void SkyBrowserModule::addSkyBrowser(ScreenSpaceSkyBrowser* browser) { - _skyBrowser = browser; +void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { + renderables.push_back(object); + // Sort on z coordinate, objects closer to camera are in beginning of list + std::sort(renderables.begin(), renderables.end()); } - -void SkyBrowserModule::addSkyTarget(ScreenSpaceSkyTarget* target) { - _skyTarget = target; +ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { + return dynamic_cast(ptr); +} +ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { + return dynamic_cast(ptr); } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index ad73291af2..aa26181e56 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -38,6 +38,7 @@ namespace openspace { class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; +class ScreenSpaceRenderable; class SkyBrowserModule : public OpenSpaceModule { public: @@ -46,30 +47,34 @@ public: SkyBrowserModule(); virtual ~SkyBrowserModule() = default; glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); + void addRenderable(ScreenSpaceRenderable* object); - void addSkyBrowser(ScreenSpaceSkyBrowser* browser); - void addSkyTarget(ScreenSpaceSkyTarget* target); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; - properties::BoolProperty _showBrowserAndTarget; - ScreenSpaceSkyBrowser* _skyBrowser; - ScreenSpaceSkyTarget* _skyTarget; - glm::vec2 startDragMousePosBrowser; - glm::vec2 startDragObjectPosBrowser; - glm::vec2 startDragMousePosTarget; - glm::vec2 startDragObjectPosTarget; + // Using snake case on these casting functions to make them similar to eg std::to_string + ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr); + ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr); + + bool shouldInitialize; + + // Renderable vector and ptr to where mouse is + std::vector renderables; + ScreenSpaceRenderable* _mouseOnObject; + // Dragging + glm::vec2 startDragMousePos; + glm::vec2 startDragObjectPos; + // Resizing glm::vec2 startResizeBrowserSize; glm::vec2 resizeVector; - bool currentlyDraggingBrowser; - bool currentlyResizingBrowser; - bool currentlyDraggingTarget; + // The current mouse position in screenspace coordinates glm::vec2 _mousePosition; - bool mouseIsOnBrowser; - bool mouseIsOnTarget; + // Current interaction status + bool currentlyResizingBrowser; + bool currentlyDraggingObject; }; } // namespace openspace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 017ad0be93..5a124e7b5e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -61,6 +61,7 @@ namespace { } // namespace namespace openspace { + ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0.f), glm::ivec2(300.f)) @@ -115,7 +116,7 @@ namespace openspace { } bool ScreenSpaceSkyBrowser::initializeGL() { - global::moduleEngine->module()->addSkyBrowser(this); + global::moduleEngine->module()->addRenderable(this); setConnectedTarget(); if (_skyTarget) { _skyTarget->setDimensions(getScreenSpaceBrowserDimension()); @@ -229,13 +230,13 @@ namespace openspace { // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); sendMessageToWWT(message); + } }); } - glm::dvec2 ScreenSpaceSkyBrowser::convertGalacticToCelestial(glm::dvec3 rGal) const { - + glm::dvec2 ScreenSpaceSkyBrowser::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 const glm::dmat3 conversionMatrix = glm::dmat3({ @@ -252,37 +253,14 @@ namespace openspace { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } - + /* void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { glm::vec3 position = _cartesianPosition; _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); - } + }*/ - void ScreenSpaceSkyBrowser::translate(glm::vec2 translation, glm::vec2 position) { - _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); - } - glm::vec2 ScreenSpaceSkyBrowser::getScreenSpacePosition() { - return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); - } - glm::vec2 ScreenSpaceSkyBrowser::getScreenSpaceDimensions() { - return glm::vec2(2.f*_scale* static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f*_scale); - } - - glm::vec2 ScreenSpaceSkyBrowser::getUpperRightCornerScreenSpace() { - return getScreenSpacePosition() + (getScreenSpaceDimensions()/2.0f); - } - - glm::vec2 ScreenSpaceSkyBrowser::getLowerLeftCornerScreenSpace() { - return getScreenSpacePosition() - (getScreenSpaceDimensions()/2.0f); - } - - bool ScreenSpaceSkyBrowser::coordIsInsideCornersScreenSpace(glm::vec2 coord) { - bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; - bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; - return lessThanUpperRight && moreThanLowerLeft; - } glm::vec2 ScreenSpaceSkyBrowser::coordIsOnResizeArea(glm::vec2 coord) { glm::vec2 resizePosition = glm::vec2{ 0 }; @@ -308,7 +286,7 @@ namespace openspace { // equal to the height of the window scale(abs(scalingFactor.y)); // Resize the dimensions of the texture on the x axis - glm::vec2 newSize = abs(scalingFactor) * _startSize; + glm::vec2 newSize = abs(scalingFactor) * _startDimensionsSize; _texture->setDimensions(glm::ivec3(newSize, 1)); _objectSize = _texture->dimensions(); _browserDimensions = newSize; @@ -330,9 +308,10 @@ namespace openspace { } void ScreenSpaceSkyBrowser::saveResizeStartSize() { - _startSize = glm::vec2(_dimensions.value().x, _dimensions.value().y); + _startDimensionsSize = glm::vec2(_dimensions.value().x, _dimensions.value().y); _startScale = _scale.value(); } + // Updates the browser size to match the size of the texture void ScreenSpaceSkyBrowser::updateBrowserSize() { _dimensions = _texture->dimensions(); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 113802d770..30d97e479e 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -92,7 +92,7 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); + _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.11f)); } @@ -115,7 +115,7 @@ namespace openspace { } bool ScreenSpaceSkyTarget::initializeGL() { - global::moduleEngine->module()->addSkyTarget(this); + global::moduleEngine->module()->addRenderable(this); setConnectedBrowser(); @@ -175,6 +175,10 @@ namespace openspace { _skyBrowser = browser; } + ScreenSpaceSkyBrowser* ScreenSpaceSkyTarget::getSkyBrowser() { + return _skyBrowser; + } + void ScreenSpaceSkyTarget::render() { glDisable(GL_CULL_FACE); diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index a6710b1980..aa6d868b05 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -558,6 +558,36 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { return scale; } +glm::vec2 ScreenSpaceRenderable::getScreenSpacePosition() { + return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); +} + +glm::vec2 ScreenSpaceRenderable::getScreenSpaceDimensions() { + return glm::vec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); +} + +glm::vec2 ScreenSpaceRenderable::getUpperRightCornerScreenSpace() { + return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0f); +} + +glm::vec2 ScreenSpaceRenderable::getLowerLeftCornerScreenSpace() { + return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0f); +} + +bool ScreenSpaceRenderable::coordIsInsideCornersScreenSpace(glm::vec2 coord) { + bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; + bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; + return lessThanUpperRight && moreThanLowerLeft; +} + +void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) { + _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); +} + +bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs) { + // Sort on depth coordinate, larger values are closer to camera + return lhs._cartesianPosition.value().z > rhs._cartesianPosition.value().z; +} glm::mat4 ScreenSpaceRenderable::globalRotationMatrix() { // We do not want the screen space planes to be affected by From 6ff0e6475a818f0be583aa2bcc1205c66247b50e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 23 Mar 2021 09:51:15 +0100 Subject: [PATCH 044/251] Ensure target and browser always are visible together by using the enabled flag --- modules/skybrowser/src/screenspaceskybrowser.cpp | 7 +++++++ modules/skybrowser/src/screenspaceskytarget.cpp | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 5a124e7b5e..b0dff464c2 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -113,6 +113,13 @@ namespace openspace { // The projection plane seems to be located at z = -2.1 so at that place the ScreenSpaceRenderables behaves like // they are in screen space _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); + + // Always make sure that the target and browser are visible together + _enabled.onChange([&]() { + if (_skyTarget) { + _skyTarget->property("Enabled")->set(_enabled.value()); + } + }); } bool ScreenSpaceSkyBrowser::initializeGL() { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 30d97e479e..55b78f8f76 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -92,8 +92,16 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); + // Projection plane seems to be at -2.1. The browser is at -2.1 and the browser should have precedence over target _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.11f)); + // Always make sure that the target and browser are visible together + _enabled.onChange([&]() { + if (_skyBrowser) { + _skyBrowser->property("Enabled")->set(_enabled.value()); + } + }); + } void ScreenSpaceSkyTarget::bindTexture() { From 74609230b66272e35f00fa6420ececd9b6d38888 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 23 Mar 2021 15:01:40 +0100 Subject: [PATCH 045/251] Make browser and target highlight when the mouse is hovering on them --- .../include/screenspaceskybrowser.h | 3 +++ .../skybrowser/include/screenspaceskytarget.h | 5 +++- modules/skybrowser/shaders/target_fs.glsl | 13 +++++----- modules/skybrowser/skybrowsermodule.cpp | 25 +++++++++++++++++++ .../skybrowser/src/screenspaceskybrowser.cpp | 14 ++++++++++- .../skybrowser/src/screenspaceskytarget.cpp | 14 +++++++++-- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 8b2d43459e..0313dceb58 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -44,6 +44,8 @@ namespace openspace { // Resizing void saveResizeStartSize(); void updateBrowserSize(); + void setBorderColor(glm::ivec3 addColor); + glm::ivec3 getColor(); // Flag for dimensions bool _browserDimIsDirty; properties::FloatProperty _fieldOfView; @@ -55,6 +57,7 @@ namespace openspace { bool _camIsSyncedWWT; ScreenSpaceSkyTarget* _skyTarget; std::thread _threadWWTMessages; + glm::ivec3 _borderColor; }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 76b8d11f37..8b2dc5cb12 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -41,6 +41,8 @@ namespace openspace { glm::vec2 getAnglePosition(); void setScale(float scale); void setConnectedBrowser(); + void setBorderColor(glm::ivec3 color); + glm::ivec3 getColor(); void translate(glm::vec2 translation, glm::vec2 position); @@ -57,11 +59,12 @@ namespace openspace { properties::Vec2Property _targetDimensions; std::unique_ptr _texture; - UniformCache(modelTransform, viewProj, texture, fieldOfView, borderWidth, targetRatio) _uniformCache; + UniformCache(modelTransform, viewProj, texture, fieldOfView, borderWidth, targetRatio, borderColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; float _fieldOfView = 100.f; ScreenSpaceSkyBrowser* _skyBrowser; + glm::vec3 _borderColor; }; } diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 7ab88be136..ef4c39e7fc 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -2,6 +2,7 @@ uniform sampler2D texture1; uniform float borderWidth; uniform vec2 targetRatio; uniform float fieldOfView; +uniform vec3 borderColor; in vec2 vs_st; in vec4 vs_position; @@ -28,11 +29,12 @@ Fragment getFragment() { vec3 crosshair = vec3(cross(vs_st, 0.1)); // draw square border - vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line - vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line + vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line + vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); frag.color = vec4(1,1,1,1); + frag.color.rgb = vec3(borderColor / 255); if(fieldOfView < 10.f) { frag.color = vec4(1,1,1,1); @@ -60,8 +62,8 @@ Fragment getFragment() { /* // draw square border - vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line - vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line + vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line + vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); frag.color = vec4(1,1,1,1); @@ -71,6 +73,3 @@ Fragment getFragment() { } */ - - - diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 6e9461b68a..79ffc0851a 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -143,10 +143,35 @@ SkyBrowserModule::SkyBrowserModule() } // If there is no dragging or resizing, look for new objects else { + // Save old selection for removing highlight + ScreenSpaceRenderable* lastObj = _mouseOnObject; + + // Find and save what mouse is currently hovering on auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { return obj->coordIsInsideCornersScreenSpace(_mousePosition); }); _mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr; + + // Selection has changed + if (lastObj != _mouseOnObject) { + glm::ivec3 highlightAddition{ 35, 35, 35 }; + // Remove highlight + if (to_browser(lastObj)) { + to_browser(lastObj)->setBorderColor(to_browser(lastObj)->getColor() - highlightAddition); + } + else if (to_target(lastObj)) { + to_target(lastObj)->setBorderColor(to_target(lastObj)->getColor() - highlightAddition); + } + + // Add highlight + if (to_browser(_mouseOnObject)) { + to_browser(_mouseOnObject)->setBorderColor(to_browser(_mouseOnObject)->getColor() + highlightAddition); + } + else if (to_target(_mouseOnObject)) { + to_target(_mouseOnObject)->setBorderColor(to_target(_mouseOnObject)->getColor() + highlightAddition); + } + } + } } ); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index b0dff464c2..442724bc32 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -69,6 +69,7 @@ namespace openspace { , _skyTargetID(TargetIDInfo) , _camIsSyncedWWT(true) , _skyTarget(nullptr) + , _borderColor(220, 220, 220) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -119,7 +120,7 @@ namespace openspace { if (_skyTarget) { _skyTarget->property("Enabled")->set(_enabled.value()); } - }); + }); } bool ScreenSpaceSkyBrowser::initializeGL() { @@ -165,6 +166,17 @@ namespace openspace { frame->ExecuteJavaScript(script, frame->GetURL(), 0); } } + + glm::ivec3 ScreenSpaceSkyBrowser::getColor() { + return _borderColor; + } + + void ScreenSpaceSkyBrowser::setBorderColor(glm::ivec3 col) { + std::string stringColor = std::to_string(col.x) + "," + std::to_string(col.y) + "," + std::to_string(col.z); + std::string script = "document.body.style.backgroundColor = 'rgb(" + stringColor + ")';"; + executeJavascript(script); + } + bool ScreenSpaceSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) { std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; executeJavascript(script); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 55b78f8f76..0bd30bab10 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -39,8 +39,8 @@ namespace { "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " }; - constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture1", "fieldOfView", "borderWidth", "targetRatio" + constexpr const std::array UniformNames = { + "ModelTransform", "ViewProjectionMatrix", "texture1", "fieldOfView", "borderWidth", "targetRatio", "borderColor" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = @@ -68,6 +68,7 @@ namespace openspace { : ScreenSpaceRenderable(dictionary) , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) + , _borderColor(220.f, 220.f, 220.f) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -179,6 +180,14 @@ namespace openspace { } + void ScreenSpaceSkyTarget::setBorderColor(glm::ivec3 color) { + _borderColor = color; + } + + glm::ivec3 ScreenSpaceSkyTarget::getColor() { + return _borderColor; + } + void ScreenSpaceSkyTarget::setBrowser(ScreenSpaceSkyBrowser* browser) { _skyBrowser = browser; } @@ -202,6 +211,7 @@ namespace openspace { _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetRatio, targetRatio); _shader->setUniform(_uniformCache.modelTransform, modelTransform); + _shader->setUniform(_uniformCache.borderColor, _borderColor); _shader->setUniform( _uniformCache.viewProj, From 18e5916a04619f0da2efbb1b5e9198491ddf31b2 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Tue, 23 Mar 2021 16:46:52 +0100 Subject: [PATCH 046/251] Set the crosshair of target to have fixed linewidth --- .../skybrowser/include/screenspaceskytarget.h | 6 +- modules/skybrowser/shaders/target_fs.glsl | 38 ++++---- .../skybrowser/src/screenspaceskybrowser.cpp | 5 +- .../skybrowser/src/screenspaceskytarget.cpp | 88 ++++++++++--------- 4 files changed, 70 insertions(+), 67 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 2ad017ebe0..53f9e9abed 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -34,11 +34,10 @@ namespace openspace { void setBrowser(ScreenSpaceSkyBrowser* browser); void setDimensions(glm::vec2 currentBrowserDimensions); - void updateFOV(float fov); + void updateFOV(float browserFOV); glm::vec2 getScreenSpacePosition(); glm::vec2 getAnglePosition(); - void setScale(float scale); void setConnectedBrowser(); void translate(glm::vec2 translation, glm::vec2 position); @@ -55,8 +54,9 @@ namespace openspace { private: properties::Vec2Property _targetDimensions; + properties::FloatProperty _showCrosshairThreshold; std::unique_ptr _texture; - UniformCache(modelTransform, viewProj, texture, fieldOfView, borderWidth, targetRatio) _uniformCache; + UniformCache(modelTransform, viewProj, texture, showCrosshair, borderWidth, targetDimensions) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; float _fieldOfView = 100.f; diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 7ab88be136..5ae5edc9f0 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,21 +1,20 @@ uniform sampler2D texture1; uniform float borderWidth; -uniform vec2 targetRatio; -uniform float fieldOfView; +uniform vec2 targetDimensions; +uniform bool showCrosshair; in vec2 vs_st; in vec4 vs_position; -float box(in vec2 _st, in vec2 _size){ - _size = vec2(0.5) - _size*0.5; - vec2 uv = smoothstep(_size,_size, vs_st); - uv *= smoothstep(_size,_size,vec2(1.0)-vs_st); - return uv.x*uv.y; -} -float cross(in vec2 _st, float _size){ - return box(vs_st, vec2(_size/.6, _size/3.)) + - box(vs_st, vec2(_size/5.,_size/.4)); +float crossLine(in float _width, in float _coord) { + + float center = 0.5f; + + float line = smoothstep(center, center+(_width/2) , _coord) - + smoothstep(center-(_width/2), center, _coord); + + return line; } #include "fragment.glsl" @@ -23,18 +22,20 @@ float cross(in vec2 _st, float _size){ Fragment getFragment() { Fragment frag; - - // draw cross - vec3 crosshair = vec3(cross(vs_st, 0.1)); + // draw crosshair + float crossWidth = 0.1f; + float ratio = targetDimensions.y / targetDimensions.x; + vec3 crosshair = vec3(crossLine(crossWidth*ratio, (vs_st).x) + crossLine(crossWidth, (vs_st).y)); // draw square border - vec2 bl = step(vec2(borderWidth),(1.0-vs_st)*targetRatio); // bottom-left line - vec2 tr = step(vec2(borderWidth),vs_st*targetRatio); // top-right line + vec2 bl = step(vec2(borderWidth),(1.0-vs_st)); // bottom-left line + vec2 tr = step(vec2(borderWidth),vs_st); // top-right line vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); frag.color = vec4(1,1,1,1); - - if(fieldOfView < 10.f) { + + // show crosshair or border + if(showCrosshair) { frag.color = vec4(1,1,1,1); if(crosshair == vec3(0.0)) { frag.color.a = 0.0; @@ -43,7 +44,6 @@ Fragment getFragment() { else { if(border == vec3(1.0)) { frag.color.a = 0.0; - } } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 017ad0be93..ae19c5f5e2 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -77,7 +77,8 @@ namespace openspace { setConnectedTarget(); } else { - _skyTarget->setDimensions(getScreenSpaceBrowserDimension()); + glm::vec2 dim = getScreenSpaceBrowserDimension(); + _skyTarget->setDimensions(dim); } }); addProperty(_browserDimensions); @@ -95,8 +96,6 @@ namespace openspace { _fieldOfView.onChange([&]() { if (_skyTarget) { _skyTarget->updateFOV(_fieldOfView); - float scaleWhenFovIs10 = static_cast(10.f / global::windowDelegate->getHorizFieldOfView()); - _skyTarget->setScale(std::max(static_cast(_fieldOfView / global::windowDelegate->getHorizFieldOfView()), scaleWhenFovIs10)); } }); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 113802d770..417ce224a3 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -2,32 +2,26 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include #include -#include #include -#include - #include -#include +#include +#include +#include #include - +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; @@ -40,7 +34,7 @@ namespace { }; constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture1", "fieldOfView", "borderWidth", "targetRatio" + "ModelTransform", "ViewProjectionMatrix", "texture1", "showCrosshair", "borderWidth", "targetDimensions" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = @@ -50,6 +44,13 @@ namespace { "tjobidabidobidabidopp plupp" }; + constexpr const openspace::properties::Property::PropertyInfo CrosshairThresholdInfo = + { + "CrosshairThreshold", + "Crosshair Threshold Info", + "tjobidabidobidabidopp plupp" + }; + struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { // [[codegen::verbatim(TargetDimensionInfo.description)]] @@ -57,6 +58,9 @@ namespace { // [[codegen::verbatim(BrowserIDInfo.description)]] std::optional browserID; + + // [[codegen::verbatim(CrosshairThresholdInfo.description)]] + std::optional crosshairThreshold; }; #include "screenspaceskytarget_codegen.cpp" @@ -68,14 +72,17 @@ namespace openspace { : ScreenSpaceRenderable(dictionary) , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) + , _showCrosshairThreshold(CrosshairThresholdInfo, 3.f, 1.f, 70.f) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _targetDimensions = p.targetDimensions.value_or(_targetDimensions); - - addProperty(_targetDimensions); _skyBrowserID = p.browserID.value_or(_skyBrowserID); + _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); + + addProperty(_targetDimensions); addProperty(_skyBrowserID); + addProperty(_showCrosshairThreshold); _skyBrowserID.onChange([&]() { setConnectedBrowser(); @@ -102,10 +109,6 @@ namespace openspace { } } - void ScreenSpaceSkyTarget::setScale(float scale) { - _scale = scale; - } - void ScreenSpaceSkyTarget::setConnectedBrowser() { _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); } @@ -137,7 +140,7 @@ namespace openspace { _texture = std::move(texture); _objectSize = _texture->dimensions(); } - + createShaders(); return isReady(); @@ -180,15 +183,19 @@ namespace openspace { glDisable(GL_CULL_FACE); glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float borderWidth = 0.005f / (_scale.value() * 2.f); - glm::vec2 targetRatio; - float fov = _fieldOfView; - _targetDimensions.value() == glm::vec2(0) ? targetRatio = glm::vec2(1) : targetRatio = _targetDimensions.value() / _targetDimensions.value().y; + float borderWidth = 0.004f /(_scale.value()); + glm::vec2 targetDim; + bool showCrosshair; + _targetDimensions.value() == glm::vec2(0) ? targetDim = glm::vec2(1) : targetDim = _targetDimensions.value(); _shader->activate(); - _shader->setUniform(_uniformCache.fieldOfView, fov); + LINFO(glm::to_string(targetDim)); + + _fieldOfView < _showCrosshairThreshold ? showCrosshair = true : showCrosshair = false; + + _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); _shader->setUniform(_uniformCache.borderWidth, borderWidth); - _shader->setUniform(_uniformCache.targetRatio, targetRatio); + _shader->setUniform(_uniformCache.targetDimensions, targetDim); _shader->setUniform(_uniformCache.modelTransform, modelTransform); _shader->setUniform( @@ -201,6 +208,7 @@ namespace openspace { bindTexture(); _shader->setUniform(_uniformCache.texture, unit); + glBindVertexArray(rendering::helper::vertexObjects.square.vao); glDrawArrays(GL_TRIANGLES, 0, 6); @@ -210,11 +218,6 @@ namespace openspace { unbindTexture(); } - void ScreenSpaceSkyTarget::update() { - - - } - void ScreenSpaceSkyTarget::translate(glm::vec2 translation, glm::vec2 position) { _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); } @@ -248,13 +251,14 @@ namespace openspace { } void ScreenSpaceSkyTarget::setDimensions(glm::vec2 currentBrowserDimensions) { - _targetDimensions = currentBrowserDimensions; + _targetDimensions = currentBrowserDimensions; + } - void ScreenSpaceSkyTarget::updateFOV(float fov) { - _fieldOfView = fov; + void ScreenSpaceSkyTarget::updateFOV(float browserFOV) { + float horizFOV = global::windowDelegate->getHorizFieldOfView(); + _scale = std::max((browserFOV/horizFOV),(_showCrosshairThreshold.value()/horizFOV)); + _fieldOfView = browserFOV; } - - } From bb5042cd50736d93e572ec03a7795c18c15fa729 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 29 Mar 2021 08:27:40 +0200 Subject: [PATCH 047/251] Create functions to display WWT images --- .../include/screenspaceskybrowser.h | 2 ++ modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 8 +++++- .../skybrowser/src/screenspaceskybrowser.cpp | 26 +++++++++++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 0313dceb58..133b7bf6e8 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -22,6 +22,8 @@ namespace openspace { ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; + ghoul::Dictionary createMessageForSettingForegroundWWT(const std::string& name) const; + ghoul::Dictionary createMessageForSettingForegroundOpacityWWT(double val) const; bool sendMessageToWWT(const ghoul::Dictionary& msg); void sendMouseEvent(CefStructBase event, int x, int y) const; void WWTfollowCamera(); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 79ffc0851a..1d703edc65 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -87,7 +87,7 @@ namespace openspace { "input. An input string should be the name of the system host star" }, { - "loacImgCollection", + "loadCollection", &skybrowser::luascriptfunctions::loadImgCollection, {}, "string or list of strings", diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 1c068aaf22..4d45bbe0f7 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -32,8 +32,14 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { int loadImgCollection(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::loadCollection"); + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + std::string url = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=wise"; + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); + browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT("Andromeda Galaxy")); + // browser->sendMessageToWWT(browser->createMessageForMovingWWTCamera(glm::vec2(0.712305533333333, 41.269167), 24.0f)); + browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 442724bc32..9b7be51e75 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -93,7 +93,7 @@ namespace openspace { _skyTargetID.onChange([&]() { setConnectedTarget(); }); - + _fieldOfView.onChange([&]() { if (_skyTarget) { _skyTarget->updateFOV(_fieldOfView); @@ -200,12 +200,34 @@ namespace openspace { // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml using namespace std::string_literals; ghoul::Dictionary msg; - msg.setValue("event", "center_on_coordinates"s); + msg.setValue("event", "load_image_collection"s); msg.setValue("url", url); return msg; } + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundWWT(const std::string& name) const { + // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_by_name"s); + msg.setValue("name", name); + + return msg; + } + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundOpacityWWT(double val) const { + // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_opacity"s); + msg.setValue("value", val); + + return msg; + } + + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForPausingWWTTime() const { using namespace std::string_literals; From 19aa6895fdb667437d51612120366123a675f0d7 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Mon, 29 Mar 2021 09:57:55 +0200 Subject: [PATCH 048/251] Set fixed width of square target border --- modules/skybrowser/shaders/target_fs.glsl | 15 ++++++--------- modules/skybrowser/src/screenspaceskytarget.cpp | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index ad49d3a1b6..047eaf847a 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -10,12 +10,9 @@ in vec4 vs_position; float crossLine(in float _width, in float _coord) { - float center = 0.5f; - float line = smoothstep(center, center+(_width/2) , _coord) - smoothstep(center-(_width/2), center, _coord); - return line; } @@ -24,23 +21,23 @@ float crossLine(in float _width, in float _coord) { Fragment getFragment() { Fragment frag; + float ratio = targetDimensions.y / targetDimensions.x; + // draw crosshair float crossWidth = 0.1f; - float ratio = targetDimensions.y / targetDimensions.x; vec3 crosshair = vec3(crossLine(crossWidth*ratio, (vs_st).x) + crossLine(crossWidth, (vs_st).y)); // draw square border - vec2 bl = step(vec2(borderWidth),(1.0-vs_st)); // bottom-left line - vec2 tr = step(vec2(borderWidth),vs_st); // top-right line - vec3 border = vec3(tr.x * tr.y * bl.x * bl.y); + float borderBottomLeft = step(borderWidth*ratio, vs_st.x) * step(borderWidth*ratio, (1.0)-vs_st.x); + float borderTopRight = step(borderWidth, vs_st.y) * step(borderWidth, (1.0)-vs_st.y); + vec3 border = vec3(borderBottomLeft*borderTopRight); // show crosshair or border frag.color = vec4(1,1,1,1); frag.color.rgb = vec3(borderColor / 255); if(showCrosshair) { - - frag.color = vec4(1,1,1,1); + frag.color.rgb = vec3(borderColor / 255); if(crosshair == vec3(0.0)) { frag.color.a = 0.0; } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index ba35de2f51..00f2cbd417 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -204,7 +204,7 @@ namespace openspace { glDisable(GL_CULL_FACE); glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float borderWidth = 0.004f /(_scale.value()); + float borderWidth = 0.005f/_scale.value(); glm::vec2 targetDim; bool showCrosshair; _targetDimensions.value() == glm::vec2(0) ? targetDim = glm::vec2(1) : targetDim = _targetDimensions.value(); From 0b85180bb56da169d0651e3a8830f3f07adf7b6d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 30 Mar 2021 08:24:22 +0200 Subject: [PATCH 049/251] Add rapid xml parser --- modules/skybrowser/rapidxmlparser/license.txt | 52 + modules/skybrowser/rapidxmlparser/manual.html | 406 +++ .../skybrowser/rapidxmlparser/rapidxml.hpp | 2596 +++++++++++++++++ .../rapidxmlparser/rapidxml_iterators.hpp | 174 ++ .../rapidxmlparser/rapidxml_print.hpp | 421 +++ .../rapidxmlparser/rapidxml_utils.hpp | 122 + 6 files changed, 3771 insertions(+) create mode 100644 modules/skybrowser/rapidxmlparser/license.txt create mode 100644 modules/skybrowser/rapidxmlparser/manual.html create mode 100644 modules/skybrowser/rapidxmlparser/rapidxml.hpp create mode 100644 modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp create mode 100644 modules/skybrowser/rapidxmlparser/rapidxml_print.hpp create mode 100644 modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp diff --git a/modules/skybrowser/rapidxmlparser/license.txt b/modules/skybrowser/rapidxmlparser/license.txt new file mode 100644 index 0000000000..140983180b --- /dev/null +++ b/modules/skybrowser/rapidxmlparser/license.txt @@ -0,0 +1,52 @@ +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +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. diff --git a/modules/skybrowser/rapidxmlparser/manual.html b/modules/skybrowser/rapidxmlparser/manual.html new file mode 100644 index 0000000000..2c422703f4 --- /dev/null +++ b/modules/skybrowser/rapidxmlparser/manual.html @@ -0,0 +1,406 @@ +

RAPIDXML Manual

Version 1.13

Copyright (C) 2006, 2009 Marcin Kalicinski
See accompanying file license.txt for license information.

Table of Contents

1. What is RapidXml?
1.1 Dependencies And Compatibility
1.2 Character Types And Encodings
1.3 Error Handling
1.4 Memory Allocation
1.5 W3C Compliance
1.6 API Design
1.7 Reliability
1.8 Acknowledgements
2. Two Minute Tutorial
2.1 Parsing
2.2 Accessing The DOM Tree
2.3 Modifying The DOM Tree
2.4 Printing XML
3. Differences From Regular XML Parsers
3.1 Lifetime Of Source Text
3.2 Ownership Of Strings
3.3 Destructive Vs Non-Destructive Mode
4. Performance
4.1 Comparison With Other Parsers
5. Reference

1. What is RapidXml?

RapidXml is an attempt to create the fastest XML DOM parser possible, while retaining useability, portability and reasonable W3C compatibility. It is an in-situ parser written in C++, with parsing speed approaching that of strlen() function executed on the same data.

+ Entire parser is contained in a single header file, so no building or linking is neccesary. To use it you just need to copy rapidxml.hpp file to a convenient place (such as your project directory), and include it where needed. You may also want to use printing functions contained in header rapidxml_print.hpp.

1.1 Dependencies And Compatibility

RapidXml has no dependencies other than a very small subset of standard C++ library (<cassert>, <cstdlib>, <new> and <exception>, unless exceptions are disabled). It should compile on any reasonably conformant compiler, and was tested on Visual C++ 2003, Visual C++ 2005, Visual C++ 2008, gcc 3, gcc 4, and Comeau 4.3.3. Care was taken that no warnings are produced on these compilers, even with highest warning levels enabled.

1.2 Character Types And Encodings

RapidXml is character type agnostic, and can work both with narrow and wide characters. Current version does not fully support UTF-16 or UTF-32, so use of wide characters is somewhat incapacitated. However, it should succesfully parse wchar_t strings containing UTF-16 or UTF-32 if endianness of the data matches that of the machine. UTF-8 is fully supported, including all numeric character references, which are expanded into appropriate UTF-8 byte sequences (unless you enable parse_no_utf8 flag).

+ Note that RapidXml performs no decoding - strings returned by name() and value() functions will contain text encoded using the same encoding as source file. Rapidxml understands and expands the following character references: &apos; &amp; &quot; &lt; &gt; &#...; Other character references are not expanded.

1.3 Error Handling

By default, RapidXml uses C++ exceptions to report errors. If this behaviour is undesirable, RAPIDXML_NO_EXCEPTIONS can be defined to suppress exception code. See parse_error class and parse_error_handler() function for more information.

1.4 Memory Allocation

RapidXml uses a special memory pool object to allocate nodes and attributes, because direct allocation using new operator would be far too slow. Underlying memory allocations performed by the pool can be customized by use of memory_pool::set_allocator() function. See class memory_pool for more information.

1.5 W3C Compliance

RapidXml is not a W3C compliant parser, primarily because it ignores DOCTYPE declarations. There is a number of other, minor incompatibilities as well. Still, it can successfully parse and produce complete trees of all valid XML files in W3C conformance suite (over 1000 files specially designed to find flaws in XML processors). In destructive mode it performs whitespace normalization and character entity substitution for a small set of built-in entities.

1.6 API Design

RapidXml API is minimalistic, to reduce code size as much as possible, and facilitate use in embedded environments. Additional convenience functions are provided in separate headers: rapidxml_utils.hpp and rapidxml_print.hpp. Contents of these headers is not an essential part of the library, and is currently not documented (otherwise than with comments in code).

1.7 Reliability

RapidXml is very robust and comes with a large harness of unit tests. Special care has been taken to ensure stability of the parser no matter what source text is thrown at it. One of the unit tests produces 100,000 randomly corrupted variants of XML document, which (when uncorrupted) contains all constructs recognized by RapidXml. RapidXml passes this test when it correctly recognizes that errors have been introduced, and does not crash or loop indefinitely.

+ Another unit test puts RapidXml head-to-head with another, well estabilished XML parser, and verifies that their outputs match across a wide variety of small and large documents.

+ Yet another test feeds RapidXml with over 1000 test files from W3C compliance suite, and verifies that correct results are obtained. There are also additional tests that verify each API function separately, and test that various parsing modes work as expected.

1.8 Acknowledgements

I would like to thank Arseny Kapoulkine for his work on pugixml, which was an inspiration for this project. Additional thanks go to Kristen Wegner for creating pugxml, from which pugixml was derived. Janusz Wohlfeil kindly ran RapidXml speed tests on hardware that I did not have access to, allowing me to expand performance comparison table.

2. Two Minute Tutorial

2.1 Parsing

The following code causes RapidXml to parse a zero-terminated string named text:
using namespace rapidxml;
+xml_document<> doc;    // character type defaults to char
+doc.parse<0>(text);    // 0 means default parse flags
+
doc object is now a root of DOM tree containing representation of the parsed XML. Because all RapidXml interface is contained inside namespace rapidxml, users must either bring contents of this namespace into scope, or fully qualify all the names. Class xml_document represents a root of the DOM hierarchy. By means of public inheritance, it is also an xml_node and a memory_pool. Template parameter of xml_document::parse() function is used to specify parsing flags, with which you can fine-tune behaviour of the parser. Note that flags must be a compile-time constant.

2.2 Accessing The DOM Tree

To access the DOM tree, use methods of xml_node and xml_attribute classes:
cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
+xml_node<> *node = doc.first_node("foobar");
+cout << "Node foobar has value " << node->value() << "\n";
+for (xml_attribute<> *attr = node->first_attribute();
+     attr; attr = attr->next_attribute())
+{
+    cout << "Node foobar has attribute " << attr->name() << " ";
+    cout << "with value " << attr->value() << "\n";
+}
+

2.3 Modifying The DOM Tree

DOM tree produced by the parser is fully modifiable. Nodes and attributes can be added/removed, and their contents changed. The below example creates a HTML document, whose sole contents is a link to google.com website:
xml_document<> doc;
+xml_node<> *node = doc.allocate_node(node_element, "a", "Google");
+doc.append_node(node);
+xml_attribute<> *attr = doc.allocate_attribute("href", "google.com");
+node->append_attribute(attr);
+
One quirk is that nodes and attributes do not own the text of their names and values. This is because normally they only store pointers to the source text. So, when assigning a new name or value to the node, care must be taken to ensure proper lifetime of the string. The easiest way to achieve it is to allocate the string from the xml_document memory pool. In the above example this is not necessary, because we are only assigning character constants. But the code below uses memory_pool::allocate_string() function to allocate node name (which will have the same lifetime as the document), and assigns it to a new node:
xml_document<> doc;
+char *node_name = doc.allocate_string(name);        // Allocate string and copy name into it
+xml_node<> *node = doc.allocate_node(node_element, node_name);  // Set node name to node_name
+
Check Reference section for description of the entire interface.

2.4 Printing XML

You can print xml_document and xml_node objects into an XML string. Use print() function or operator <<, which are defined in rapidxml_print.hpp header.
using namespace rapidxml;
+xml_document<> doc;    // character type defaults to char
+// ... some code to fill the document
+
+// Print to stream using operator <<
+std::cout << doc;   
+
+// Print to stream using print function, specifying printing flags
+print(std::cout, doc, 0);   // 0 means default printing flags
+
+// Print to string using output iterator
+std::string s;
+print(std::back_inserter(s), doc, 0);
+
+// Print to memory buffer using output iterator
+char buffer[4096];                      // You are responsible for making the buffer large enough!
+char *end = print(buffer, doc, 0);      // end contains pointer to character after last printed character
+*end = 0;                               // Add string terminator after XML
+

3. Differences From Regular XML Parsers

RapidXml is an in-situ parser, which allows it to achieve very high parsing speed. In-situ means that parser does not make copies of strings. Instead, it places pointers to the source text in the DOM hierarchy.

3.1 Lifetime Of Source Text

In-situ parsing requires that source text lives at least as long as the document object. If source text is destroyed, names and values of nodes in DOM tree will become destroyed as well. Additionally, whitespace processing, character entity translation, and zero-termination of strings require that source text be modified during parsing (but see non-destructive mode). This makes the text useless for further processing once it was parsed by RapidXml.

+ In many cases however, these are not serious issues.

3.2 Ownership Of Strings

Nodes and attributes produced by RapidXml do not own their name and value strings. They merely hold the pointers to them. This means you have to be careful when setting these values manually, by using xml_base::name(const Ch *) or xml_base::value(const Ch *) functions. Care must be taken to ensure that lifetime of the string passed is at least as long as lifetime of the node/attribute. The easiest way to achieve it is to allocate the string from memory_pool owned by the document. Use memory_pool::allocate_string() function for this purpose.

3.3 Destructive Vs Non-Destructive Mode

By default, the parser modifies source text during the parsing process. This is required to achieve character entity translation, whitespace normalization, and zero-termination of strings.

+ In some cases this behaviour may be undesirable, for example if source text resides in read only memory, or is mapped to memory directly from file. By using appropriate parser flags (parse_non_destructive), source text modifications can be disabled. However, because RapidXml does in-situ parsing, it obviously has the following side-effects:

4. Performance

RapidXml achieves its speed through use of several techniques:
  • In-situ parsing. When building DOM tree, RapidXml does not make copies of string data, such as node names and values. Instead, it stores pointers to interior of the source text.
  • Use of template metaprogramming techniques. This allows it to move much of the work to compile time. Through magic of the templates, C++ compiler generates a separate copy of parsing code for any combination of parser flags you use. In each copy, all possible decisions are made at compile time and all unused code is omitted.
  • Extensive use of lookup tables for parsing.
  • Hand-tuned C++ with profiling done on several most popular CPUs.
This results in a very small and fast code: a parser which is custom tailored to exact needs with each invocation.

4.1 Comparison With Other Parsers

The table below compares speed of RapidXml to some other parsers, and to strlen() function executed on the same data. On a modern CPU (as of 2007), you can expect parsing throughput to be close to 1 GB/s. As a rule of thumb, parsing speed is about 50-100x faster than Xerces DOM, 30-60x faster than TinyXml, 3-12x faster than pugxml, and about 5% - 30% faster than pugixml, the fastest XML parser I know of.
  • The test file is a real-world, 50kB large, moderately dense XML file.
  • All timing is done by using RDTSC instruction present in Pentium-compatible CPUs.
  • No profile-guided optimizations are used.
  • All parsers are running in their fastest modes.
  • The results are given in CPU cycles per character, so frequency of CPUs is irrelevant.
  • The results are minimum values from a large number of runs, to minimize effects of operating system activity, task switching, interrupt handling etc.
  • A single parse of the test file takes about 1/10th of a millisecond, so with large number of runs there is a good chance of hitting at least one no-interrupt streak, and obtaining undisturbed results.
Platform
Compiler
strlen() RapidXml pugixml 0.3 pugxml TinyXml
Pentium 4
MSVC 8.0
2.5
5.4
7.0
61.7
298.8
Pentium 4
gcc 4.1.1
0.8
6.1
9.5
67.0
413.2
Core 2
MSVC 8.0
1.0
4.5
5.0
24.6
154.8
Core 2
gcc 4.1.1
0.6
4.6
5.4
28.3
229.3
Athlon XP
MSVC 8.0
3.1
7.7
8.0
25.5
182.6
Athlon XP
gcc 4.1.1
0.9
8.2
9.2
33.7
265.2
Pentium 3
MSVC 8.0
2.0
6.3
7.0
30.9
211.9
Pentium 3
gcc 4.1.1
1.0
6.7
8.9
35.3
316.0
(*) All results are in CPU cycles per character of source text

5. Reference

This section lists all classes, functions, constants etc. and describes them in detail.
class + template + rapidxml::memory_pool
+ constructor + memory_pool()
+ destructor + ~memory_pool()
function allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
function allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
function allocate_string(const Ch *source=0, std::size_t size=0)
function clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0)
function clear()
function set_allocator(alloc_func *af, free_func *ff)

class rapidxml::parse_error
+ constructor + parse_error(const char *what, void *where)
function what() const
function where() const

class + template + rapidxml::xml_attribute
+ constructor + xml_attribute()
function document() const
function previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const

class + template + rapidxml::xml_base
+ constructor + xml_base()
function name() const
function name_size() const
function value() const
function value_size() const
function name(const Ch *name, std::size_t size)
function name(const Ch *name)
function value(const Ch *value, std::size_t size)
function value(const Ch *value)
function parent() const

class + template + rapidxml::xml_document
+ constructor + xml_document()
function parse(Ch *text)
function clear()

class + template + rapidxml::xml_node
+ constructor + xml_node(node_type type)
function type() const
function document() const
function first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function type(node_type type)
function prepend_node(xml_node< Ch > *child)
function append_node(xml_node< Ch > *child)
function insert_node(xml_node< Ch > *where, xml_node< Ch > *child)
function remove_first_node()
function remove_last_node()
function remove_node(xml_node< Ch > *where)
function remove_all_nodes()
function prepend_attribute(xml_attribute< Ch > *attribute)
function append_attribute(xml_attribute< Ch > *attribute)
function insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute)
function remove_first_attribute()
function remove_last_attribute()
function remove_attribute(xml_attribute< Ch > *where)
function remove_all_attributes()

namespace rapidxml
enum node_type
function parse_error_handler(const char *what, void *where)
function print(OutIt out, const xml_node< Ch > &node, int flags=0)
function print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0)
function operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node)
+ constant + parse_no_data_nodes
+ constant + parse_no_element_values
+ constant + parse_no_string_terminators
+ constant + parse_no_entity_translation
+ constant + parse_no_utf8
+ constant + parse_declaration_node
+ constant + parse_comment_nodes
+ constant + parse_doctype_node
+ constant + parse_pi_nodes
+ constant + parse_validate_closing_tags
+ constant + parse_trim_whitespace
+ constant + parse_normalize_whitespace
+ constant + parse_default
+ constant + parse_non_destructive
+ constant + parse_fastest
+ constant + parse_full
+ constant + print_no_indenting


class + template + rapidxml::memory_pool

+ + Defined in rapidxml.hpp
+ Base class for + xml_document

Description

This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. In most cases, you will not need to use this class directly. However, if you need to create nodes manually or modify names/values of nodes, you are encouraged to use memory_pool of relevant xml_document to allocate the memory. Not only is this faster than allocating them by using new operator, but also their lifetime will be tied to the lifetime of document, possibly simplyfing memory management.

+ Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. You can also call allocate_string() function to allocate strings. Such strings can then be used as names or values of nodes without worrying about their lifetime. Note that there is no free() function -- all allocations are freed at once when clear() function is called, or when the pool is destroyed.

+ It is also possible to create a standalone memory_pool, and use it to allocate nodes, whose lifetime will not be tied to any document.

+ Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. Until static memory is exhausted, no dynamic memory allocations are done. When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, by using global new[] and delete[] operators. This behaviour can be changed by setting custom allocation routines. Use set_allocator() function to set them.

+ Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. This value defaults to the size of pointer on target architecture.

+ To obtain absolutely top performance from the parser, it is important that all nodes are allocated from a single, contiguous block of memory. Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT to obtain best wasted memory to performance compromise. To do it, define their values before rapidxml.hpp file is included.

Parameters

Ch
Character type of created nodes.

+ constructor + memory_pool::memory_pool

Synopsis

memory_pool(); +

Description

Constructs empty pool with default allocator functions.

+ destructor + memory_pool::~memory_pool

Synopsis

~memory_pool(); +

Description

Destroys pool and frees all the memory. This causes memory occupied by nodes allocated by the pool to be freed. Nodes allocated from the pool are no longer valid.

function memory_pool::allocate_node

Synopsis

xml_node<Ch>* allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); +

Description

Allocates a new node from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

Parameters

type
Type of node to create.
name
Name to assign to the node, or 0 to assign no name.
value
Value to assign to the node, or 0 to assign no value.
name_size
Size of name to assign, or 0 to automatically calculate size from name string.
value_size
Size of value to assign, or 0 to automatically calculate size from value string.

Returns

Pointer to allocated node. This pointer will never be NULL.

function memory_pool::allocate_attribute

Synopsis

xml_attribute<Ch>* allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); +

Description

Allocates a new attribute from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

Parameters

name
Name to assign to the attribute, or 0 to assign no name.
value
Value to assign to the attribute, or 0 to assign no value.
name_size
Size of name to assign, or 0 to automatically calculate size from name string.
value_size
Size of value to assign, or 0 to automatically calculate size from value string.

Returns

Pointer to allocated attribute. This pointer will never be NULL.

function memory_pool::allocate_string

Synopsis

Ch* allocate_string(const Ch *source=0, std::size_t size=0); +

Description

Allocates a char array of given size from the pool, and optionally copies a given string to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

Parameters

source
String to initialize the allocated memory with, or 0 to not initialize it.
size
Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.

Returns

Pointer to allocated char array. This pointer will never be NULL.

function memory_pool::clone_node

Synopsis

xml_node<Ch>* clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0); +

Description

Clones an xml_node and its hierarchy of child nodes and attributes. Nodes and attributes are allocated from this memory pool. Names and values are not cloned, they are shared between the clone and the source. Result node can be optionally specified as a second parameter, in which case its contents will be replaced with cloned source node. This is useful when you want to clone entire document.

Parameters

source
Node to clone.
result
Node to put results in, or 0 to automatically allocate result node

Returns

Pointer to cloned node. This pointer will never be NULL.

function memory_pool::clear

Synopsis

void clear(); +

Description

Clears the pool. This causes memory occupied by nodes allocated by the pool to be freed. Any nodes or strings allocated from the pool will no longer be valid.

function memory_pool::set_allocator

Synopsis

void set_allocator(alloc_func *af, free_func *ff); +

Description

Sets or resets the user-defined memory allocation functions for the pool. This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. Allocation function must not return invalid pointer on failure. It should either throw, stop the program, or use longjmp() function to pass control to other place of program. If it returns invalid pointer, results are undefined.

+ User defined allocation functions must have the following forms:

+void *allocate(std::size_t size);
+void free(void *pointer);

Parameters

af
Allocation function, or 0 to restore default function
ff
Free function, or 0 to restore default function

class rapidxml::parse_error

+ + Defined in rapidxml.hpp

Description

Parse error exception. This exception is thrown by the parser when an error occurs. Use what() function to get human-readable error message. Use where() function to get a pointer to position within source text where error was detected.

+ If throwing exceptions by the parser is undesirable, it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. This function must be defined by the user.

+ This class derives from std::exception class.

+ constructor + parse_error::parse_error

Synopsis

parse_error(const char *what, void *where); +

Description

Constructs parse error.

function parse_error::what

Synopsis

virtual const char* what() const; +

Description

Gets human readable description of error.

Returns

Pointer to null terminated description of the error.

function parse_error::where

Synopsis

Ch* where() const; +

Description

Gets pointer to character data where error happened. Ch should be the same as char type of xml_document that produced the error.

Returns

Pointer to location within the parsed string where error occured.

class + template + rapidxml::xml_attribute

+ + Defined in rapidxml.hpp
+ Inherits from + xml_base

Description

Class representing attribute node of XML document. Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). Note that after parse, both name and value of attribute will point to interior of source text used for parsing. Thus, this text must persist in memory for the lifetime of attribute.

Parameters

Ch
Character type to use.

+ constructor + xml_attribute::xml_attribute

Synopsis

xml_attribute(); +

Description

Constructs an empty attribute with the specified type. Consider using memory_pool of appropriate xml_document if allocating attributes manually.

function xml_attribute::document

Synopsis

xml_document<Ch>* document() const; +

Description

Gets document of which attribute is a child.

Returns

Pointer to document that contains this attribute, or 0 if there is no parent document.

function xml_attribute::previous_attribute

Synopsis

xml_attribute<Ch>* previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets previous attribute, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

function xml_attribute::next_attribute

Synopsis

xml_attribute<Ch>* next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets next attribute, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

class + template + rapidxml::xml_base

+ + Defined in rapidxml.hpp
+ Base class for + xml_attribute xml_node

Description

Base class for xml_node and xml_attribute implementing common functions: name(), name_size(), value(), value_size() and parent().

Parameters

Ch
Character type to use

+ constructor + xml_base::xml_base

Synopsis

xml_base(); +

function xml_base::name

Synopsis

Ch* name() const; +

Description

Gets name of the node. Interpretation of name depends on type of node. Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

+ Use name_size() function to determine length of the name.

Returns

Name of node, or empty string if node has no name.

function xml_base::name_size

Synopsis

std::size_t name_size() const; +

Description

Gets size of node name, not including terminator character. This function works correctly irrespective of whether name is or is not zero terminated.

Returns

Size of node name, in characters.

function xml_base::value

Synopsis

Ch* value() const; +

Description

Gets value of node. Interpretation of value depends on type of node. Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

+ Use value_size() function to determine length of the value.

Returns

Value of node, or empty string if node has no value.

function xml_base::value_size

Synopsis

std::size_t value_size() const; +

Description

Gets size of node value, not including terminator character. This function works correctly irrespective of whether value is or is not zero terminated.

Returns

Size of node value, in characters.

function xml_base::name

Synopsis

void name(const Ch *name, std::size_t size); +

Description

Sets name of node to a non zero-terminated string. See Ownership Of Strings .

+ Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

+ Size of name must be specified separately, because name does not have to be zero terminated. Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).

Parameters

name
Name of node to set. Does not have to be zero terminated.
size
Size of name, in characters. This does not include zero terminator, if one is present.

function xml_base::name

Synopsis

void name(const Ch *name); +

Description

Sets name of node to a zero-terminated string. See also Ownership Of Strings and xml_node::name(const Ch *, std::size_t).

Parameters

name
Name of node to set. Must be zero terminated.

function xml_base::value

Synopsis

void value(const Ch *value, std::size_t size); +

Description

Sets value of node to a non zero-terminated string. See Ownership Of Strings .

+ Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

+ Size of value must be specified separately, because it does not have to be zero terminated. Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).

+ If an element has a child node of type node_data, it will take precedence over element value when printing. If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.

Parameters

value
value of node to set. Does not have to be zero terminated.
size
Size of value, in characters. This does not include zero terminator, if one is present.

function xml_base::value

Synopsis

void value(const Ch *value); +

Description

Sets value of node to a zero-terminated string. See also Ownership Of Strings and xml_node::value(const Ch *, std::size_t).

Parameters

value
Vame of node to set. Must be zero terminated.

function xml_base::parent

Synopsis

xml_node<Ch>* parent() const; +

Description

Gets node parent.

Returns

Pointer to parent node, or 0 if there is no parent.

class + template + rapidxml::xml_document

+ + Defined in rapidxml.hpp
+ Inherits from + xml_node memory_pool

Description

This class represents root of the DOM hierarchy. It is also an xml_node and a memory_pool through public inheritance. Use parse() function to build a DOM tree from a zero-terminated XML text string. parse() function allocates memory for nodes and attributes by using functions of xml_document, which are inherited from memory_pool. To access root node of the document, use the document itself, as if it was an xml_node.

Parameters

Ch
Character type to use.

+ constructor + xml_document::xml_document

Synopsis

xml_document(); +

Description

Constructs empty XML document.

function xml_document::parse

Synopsis

void parse(Ch *text); +

Description

Parses zero-terminated XML string according to given flags. Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. The string must persist for the lifetime of the document. In case of error, rapidxml::parse_error exception will be thrown.

+ If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. Make sure that data is zero-terminated.

+ Document can be parsed into multiple times. Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.

Parameters

text
XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.

function xml_document::clear

Synopsis

void clear(); +

Description

Clears the document by deleting all nodes and clearing the memory pool. All nodes owned by document pool are destroyed.

class + template + rapidxml::xml_node

+ + Defined in rapidxml.hpp
+ Inherits from + xml_base
+ Base class for + xml_document

Description

Class representing a node of XML document. Each node may have associated name and value strings, which are available through name() and value() functions. Interpretation of name and value depends on type of the node. Type of node can be determined by using type() function.

+ Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. Thus, this text must persist in the memory for the lifetime of node.

Parameters

Ch
Character type to use.

+ constructor + xml_node::xml_node

Synopsis

xml_node(node_type type); +

Description

Constructs an empty node with the specified type. Consider using memory_pool of appropriate document to allocate nodes manually.

Parameters

type
Type of node to construct.

function xml_node::type

Synopsis

node_type type() const; +

Description

Gets type of node.

Returns

Type of node.

function xml_node::document

Synopsis

xml_document<Ch>* document() const; +

Description

Gets document of which node is a child.

Returns

Pointer to document that contains this node, or 0 if there is no parent document.

function xml_node::first_node

Synopsis

xml_node<Ch>* first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets first child node, optionally matching node name.

Parameters

name
Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found child, or 0 if not found.

function xml_node::last_node

Synopsis

xml_node<Ch>* last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets last child node, optionally matching node name. Behaviour is undefined if node has no children. Use first_node() to test if node has children.

Parameters

name
Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found child, or 0 if not found.

function xml_node::previous_sibling

Synopsis

xml_node<Ch>* previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets previous sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

Parameters

name
Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found sibling, or 0 if not found.

function xml_node::next_sibling

Synopsis

xml_node<Ch>* next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets next sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

Parameters

name
Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found sibling, or 0 if not found.

function xml_node::first_attribute

Synopsis

xml_attribute<Ch>* first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets first attribute of node, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

function xml_node::last_attribute

Synopsis

xml_attribute<Ch>* last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

Description

Gets last attribute of node, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

function xml_node::type

Synopsis

void type(node_type type); +

Description

Sets type of node.

Parameters

type
Type of node to set.

function xml_node::prepend_node

Synopsis

void prepend_node(xml_node< Ch > *child); +

Description

Prepends a new child node. The prepended child becomes the first child, and all existing children are moved one position back.

Parameters

child
Node to prepend.

function xml_node::append_node

Synopsis

void append_node(xml_node< Ch > *child); +

Description

Appends a new child node. The appended child becomes the last child.

Parameters

child
Node to append.

function xml_node::insert_node

Synopsis

void insert_node(xml_node< Ch > *where, xml_node< Ch > *child); +

Description

Inserts a new child node at specified place inside the node. All children after and including the specified node are moved one position back.

Parameters

where
Place where to insert the child, or 0 to insert at the back.
child
Node to insert.

function xml_node::remove_first_node

Synopsis

void remove_first_node(); +

Description

Removes first child node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

function xml_node::remove_last_node

Synopsis

void remove_last_node(); +

Description

Removes last child of the node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

function xml_node::remove_node

Synopsis

void remove_node(xml_node< Ch > *where); +

Description

Removes specified child from the node.

function xml_node::remove_all_nodes

Synopsis

void remove_all_nodes(); +

Description

Removes all child nodes (but not attributes).

function xml_node::prepend_attribute

Synopsis

void prepend_attribute(xml_attribute< Ch > *attribute); +

Description

Prepends a new attribute to the node.

Parameters

attribute
Attribute to prepend.

function xml_node::append_attribute

Synopsis

void append_attribute(xml_attribute< Ch > *attribute); +

Description

Appends a new attribute to the node.

Parameters

attribute
Attribute to append.

function xml_node::insert_attribute

Synopsis

void insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute); +

Description

Inserts a new attribute at specified place inside the node. All attributes after and including the specified attribute are moved one position back.

Parameters

where
Place where to insert the attribute, or 0 to insert at the back.
attribute
Attribute to insert.

function xml_node::remove_first_attribute

Synopsis

void remove_first_attribute(); +

Description

Removes first attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

function xml_node::remove_last_attribute

Synopsis

void remove_last_attribute(); +

Description

Removes last attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

function xml_node::remove_attribute

Synopsis

void remove_attribute(xml_attribute< Ch > *where); +

Description

Removes specified attribute from node.

Parameters

where
Pointer to attribute to be removed.

function xml_node::remove_all_attributes

Synopsis

void remove_all_attributes(); +

Description

Removes all attributes of node.

enum node_type

Description

Enumeration listing all node types produced by the parser. Use xml_node::type() function to query node type.

Values

node_document
A document node. Name and value are empty.
node_element
An element node. Name contains element name. Value contains text of first data node.
node_data
A data node. Name is empty. Value contains data text.
node_cdata
A CDATA node. Name is empty. Value contains data text.
node_comment
A comment node. Name is empty. Value contains comment text.
node_declaration
A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
node_doctype
A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
node_pi
A PI node. Name contains target. Value contains instructions.

function parse_error_handler

Synopsis

void rapidxml::parse_error_handler(const char *what, void *where); +

Description

When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function is called to notify user about the error. It must be defined by the user.

+ This function cannot return. If it does, the results are undefined.

+ A very simple definition might look like that: + void rapidxml::parse_error_handler(const char *what, void *where) + { + std::cout << "Parse error: " << what << "\n"; + std::abort(); + } +

Parameters

what
Human readable description of the error.
where
Pointer to character data where error was detected.

function print

Synopsis

OutIt rapidxml::print(OutIt out, const xml_node< Ch > &node, int flags=0); +

Description

Prints XML to given output iterator.

Parameters

out
Output iterator to print to.
node
Node to be printed. Pass xml_document to print entire document.
flags
Flags controlling how XML is printed.

Returns

Output iterator pointing to position immediately after last character of printed text.

function print

Synopsis

std::basic_ostream<Ch>& rapidxml::print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0); +

Description

Prints XML to given output stream.

Parameters

out
Output stream to print to.
node
Node to be printed. Pass xml_document to print entire document.
flags
Flags controlling how XML is printed.

Returns

Output stream.

function operator<<

Synopsis

std::basic_ostream<Ch>& rapidxml::operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node); +

Description

Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.

Parameters

out
Output stream to print to.
node
Node to be printed.

Returns

Output stream.

+ constant + parse_no_data_nodes

Synopsis

const int parse_no_data_nodes + = 0x1; +

Description

Parse flag instructing the parser to not create data nodes. Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_no_element_values

Synopsis

const int parse_no_element_values + = 0x2; +

Description

Parse flag instructing the parser to not use text of first data node as a value of parent element. Can be combined with other flags by use of | operator. Note that child data nodes of element node take precendence over its value when printing. That is, if element has one or more child data nodes and a value, the value will be ignored. Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.

+ See xml_document::parse() function.

+ constant + parse_no_string_terminators

Synopsis

const int parse_no_string_terminators + = 0x4; +

Description

Parse flag instructing the parser to not place zero terminators after strings in the source text. By default zero terminators are placed, modifying source text. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_no_entity_translation

Synopsis

const int parse_no_entity_translation + = 0x8; +

Description

Parse flag instructing the parser to not translate entities in the source text. By default entities are translated, modifying source text. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_no_utf8

Synopsis

const int parse_no_utf8 + = 0x10; +

Description

Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. By default, UTF-8 handling is enabled. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_declaration_node

Synopsis

const int parse_declaration_node + = 0x20; +

Description

Parse flag instructing the parser to create XML declaration node. By default, declaration node is not created. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_comment_nodes

Synopsis

const int parse_comment_nodes + = 0x40; +

Description

Parse flag instructing the parser to create comments nodes. By default, comment nodes are not created. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_doctype_node

Synopsis

const int parse_doctype_node + = 0x80; +

Description

Parse flag instructing the parser to create DOCTYPE node. By default, doctype node is not created. Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_pi_nodes

Synopsis

const int parse_pi_nodes + = 0x100; +

Description

Parse flag instructing the parser to create PI nodes. By default, PI nodes are not created. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_validate_closing_tags

Synopsis

const int parse_validate_closing_tags + = 0x200; +

Description

Parse flag instructing the parser to validate closing tag names. If not set, name inside closing tag is irrelevant to the parser. By default, closing tags are not validated. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_trim_whitespace

Synopsis

const int parse_trim_whitespace + = 0x400; +

Description

Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. By default, whitespace is not trimmed. This flag does not cause the parser to modify source text. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_normalize_whitespace

Synopsis

const int parse_normalize_whitespace + = 0x800; +

Description

Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. By default, whitespace is not normalized. If this flag is specified, source text will be modified. Can be combined with other flags by use of | operator.

+ See xml_document::parse() function.

+ constant + parse_default

Synopsis

const int parse_default + = 0; +

Description

Parse flags which represent default behaviour of the parser. This is always equal to 0, so that all other flags can be simply ored together. Normally there is no need to inconveniently disable flags by anding with their negated (~) values. This also means that meaning of each flag is a negation of the default setting. For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, and using the flag will disable it.

+ See xml_document::parse() function.

+ constant + parse_non_destructive

Synopsis

const int parse_non_destructive + = parse_no_string_terminators | parse_no_entity_translation; +

Description

A combination of parse flags that forbids any modifications of the source text. This also results in faster parsing. However, note that the following will occur:
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • entities will not be translated
  • whitespace will not be normalized
+See xml_document::parse() function.

+ constant + parse_fastest

Synopsis

const int parse_fastest + = parse_non_destructive | parse_no_data_nodes; +

Description

A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.

+ See xml_document::parse() function.

+ constant + parse_full

Synopsis

const int parse_full + = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; +

Description

A combination of parse flags resulting in largest amount of data being extracted. This usually results in slowest parsing.

+ See xml_document::parse() function.

+ constant + print_no_indenting

Synopsis

const int print_no_indenting + = 0x1; +

Description

Printer flag instructing the printer to suppress indenting of XML. See print() function.

\ No newline at end of file diff --git a/modules/skybrowser/rapidxmlparser/rapidxml.hpp b/modules/skybrowser/rapidxmlparser/rapidxml.hpp new file mode 100644 index 0000000000..ae91e081d0 --- /dev/null +++ b/modules/skybrowser/rapidxmlparser/rapidxml.hpp @@ -0,0 +1,2596 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

+ //! This function cannot return. If it does, the results are undefined. + //!

+ //! A very simple definition might look like that: + //!

+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! 
+ //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

+ //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

+ //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

+ //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

+ //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
    + //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • + //!
  • entities will not be translated
  • + //!
  • whitespace will not be normalized
  • + //!
+ //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

+ //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

+ //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

+ //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

+ //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

+ //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

+ //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

+ //! User defined allocation functions must have the following forms: + //!
+ //!
void *allocate(std::size_t size); + //!
void free(void *pointer); + //!

+ //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

+ //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

+ //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp b/modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp new file mode 100644 index 0000000000..52ebc298aa --- /dev/null +++ b/modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml +{ + + //! Iterator of child nodes of xml_node + template + class node_iterator + { + + public: + + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node *node) + : m_node(node->first_node()) + { + } + + reference operator *() const + { + assert(m_node); + return *m_node; + } + + pointer operator->() const + { + assert(m_node); + return m_node; + } + + node_iterator& operator++() + { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator& operator--() + { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const node_iterator &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node *m_node; + + }; + + //! Iterator of child attributes of xml_node + template + class attribute_iterator + { + + public: + + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node *node) + : m_attribute(node->first_attribute()) + { + } + + reference operator *() const + { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const + { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator& operator++() + { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator& operator--() + { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const attribute_iterator &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute *m_attribute; + + }; + +} + +#endif diff --git a/modules/skybrowser/rapidxmlparser/rapidxml_print.hpp b/modules/skybrowser/rapidxmlparser/rapidxml_print.hpp new file mode 100644 index 0000000000..0ae2b14faa --- /dev/null +++ b/modules/skybrowser/rapidxmlparser/rapidxml_print.hpp @@ -0,0 +1,421 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include + #include +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + // Print node + template + inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + + // Print children of the node + template + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) + { + for (xml_node *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) + { + for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template + inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template + inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template + inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template + inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template + inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template + inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template + inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template + inline OutIt print(OutIt out, const xml_node &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template + inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) + { + print(std::ostream_iterator(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template + inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp b/modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp new file mode 100644 index 0000000000..37c29535f4 --- /dev/null +++ b/modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif From ec138b6897695872a014b32c31071fea006e6fab Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 30 Mar 2021 08:28:32 +0200 Subject: [PATCH 050/251] Add function to save URL to file, parse to XML tree and insert into vector as images --- modules/skybrowser/CMakeLists.txt | 1 + modules/skybrowser/skybrowsermodule.cpp | 76 ++++++++++++++++++++- modules/skybrowser/skybrowsermodule.h | 15 +++- modules/skybrowser/skybrowsermodule_lua.inl | 6 ++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index ae29dbfdfc..0e6cfd1fa1 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -29,6 +29,7 @@ set(HEADER_FILES skybrowsermodule.h include/screenspaceskybrowser.h include/screenspaceskytarget.h + rapidxmlparser/rapidxml.hpp ) source_group("Header Files" FILES ${HEADER_FILES}) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1d703edc65..8d14fc08e7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -23,6 +23,9 @@ ****************************************************************************************/ #include +#include // For parsing xml +#include // For parsing xml +#include // For parsing xml //#include //#include @@ -41,8 +44,11 @@ #include #include #include // For atan2 -#include +#include // For printing glm data #include +#include // For downloading files from url +#include + namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -284,6 +290,74 @@ ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } +void SkyBrowserModule::loadImages(std::string url, std::string fileDestination) { + // Get the webpage and save to file + HttpRequest::RequestOptions opt{0}; + SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes); + wtml_root.download(opt); + // Parse XML document + using namespace rapidxml; + rapidxml::file<> xmlFile(fileDestination.c_str()); // Default template is char + rapidxml::xml_document<> doc; + doc.parse<0>(xmlFile.data()); + + // Get child of node until we find the "Place" node + xml_node<>* place = getChildNode(doc.first_node(), "Place"); + + // Iterate through all the places and load as images + while (place) { + loadImage(place); + place = place->next_sibling(); + } + LINFO(images[55].thumbnailUrl); +} + +int SkyBrowserModule::loadImage(rapidxml::xml_node<>* imgNode) { + ImageData image; + using namespace rapidxml; + // Get all attributes for the + for (xml_attribute<>* attr = imgNode->first_attribute(); attr; attr = attr->next_attribute()) + { + if (attr->name() == "RA") { + image.celestCoords.x = std::stof(attr->value()); + } + else if (attr->name() == "DEC") { + image.celestCoords.y = std::stof(attr->value()); + } + else if (attr->name() == "Classification") { + image.name = attr->value(); + } + } + xml_node<>* imageSet = getChildNode(imgNode, "ImageSet"); + if (!imageSet) return -1; + // Get all attributes for the + for (xml_attribute<>* attr = imageSet->first_attribute(); attr; attr = attr->next_attribute()) { + if (attr->name() == "Name") { + image.name = attr->value(); + break; + } + } + // The thumbnail is the last node so traverse backwards for speed + xml_node<>* imageSetChild = imageSet->last_node(); + while (imageSetChild) { + if (std::string(imageSetChild->name()) == "ThumbnailUrl") { + image.thumbnailUrl = imageSetChild->value(); + break; + } + imageSetChild = imageSetChild->previous_sibling(); + } + + images.push_back(image); + // Return index of image in vector + return images.size(); +} + +rapidxml::xml_node<>* SkyBrowserModule::getChildNode(rapidxml::xml_node<>* node, std::string name) { + while (node && std::string(node->name()) != name) { + node = node->first_node(); + } + return node; +} /* std::vector SkyBrowserModule::documentations() const { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index aa26181e56..1da3242818 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -27,7 +27,7 @@ #include - +#include // For parsing xml #include #include #include @@ -40,6 +40,14 @@ class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; class ScreenSpaceRenderable; +struct ImageData { + std::string name; + std::string thumbnailUrl; + glm::vec2 celestCoords; + std::string classification; + float zoom; +}; + class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; @@ -48,6 +56,7 @@ public: virtual ~SkyBrowserModule() = default; glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); + void loadImages(std::string url, std::string fileDestination); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -55,6 +64,8 @@ public: protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; + int loadImage(rapidxml::xml_node<>* imgNode); + rapidxml::xml_node<>* getChildNode(rapidxml::xml_node<>* node, std::string name); // Using snake case on these casting functions to make them similar to eg std::to_string ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr); ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr); @@ -75,6 +86,8 @@ protected: // Current interaction status bool currentlyResizingBrowser; bool currentlyDraggingObject; + + std::vector images; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4d45bbe0f7..5ee5d65616 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -45,6 +45,12 @@ namespace openspace::skybrowser::luascriptfunctions { int followCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); + + SkyBrowserModule* module = global::moduleEngine->module(); + std::string url = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=vampfeeds"; + url = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=wise"; + std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/wise.aspx"); + module->loadImages(url, fileDestination); return 1; } From d4e944f73fea54836a7cf75f10f441a1bea09c81 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 30 Mar 2021 08:29:57 +0200 Subject: [PATCH 051/251] Add webgui to cmake include dependencies --- modules/skybrowser/include.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/skybrowser/include.cmake b/modules/skybrowser/include.cmake index 9f1c8e7b85..499ac872db 100644 --- a/modules/skybrowser/include.cmake +++ b/modules/skybrowser/include.cmake @@ -1,3 +1,4 @@ set(OPENSPACE_DEPENDENCIES webbrowser + webgui ) From b95d6e5b940edc1679101fb40f9cc21ae6e4d35c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 31 Mar 2021 16:41:25 +0200 Subject: [PATCH 052/251] Change rapidxmlparser to tinyxml2 and add more extensive xml parsing and image loading --- modules/skybrowser/CMakeLists.txt | 3 +- modules/skybrowser/rapidxmlparser/license.txt | 52 - modules/skybrowser/rapidxmlparser/manual.html | 406 --- .../skybrowser/rapidxmlparser/rapidxml.hpp | 2596 -------------- .../rapidxmlparser/rapidxml_iterators.hpp | 174 - .../rapidxmlparser/rapidxml_print.hpp | 421 --- .../rapidxmlparser/rapidxml_utils.hpp | 122 - modules/skybrowser/skybrowsermodule.cpp | 231 +- modules/skybrowser/skybrowsermodule.h | 24 +- modules/skybrowser/skybrowsermodule_lua.inl | 15 +- modules/skybrowser/tinyxml2/tinyxml2.cpp | 2986 +++++++++++++++++ modules/skybrowser/tinyxml2/tinyxml2.h | 2380 +++++++++++++ 12 files changed, 5571 insertions(+), 3839 deletions(-) delete mode 100644 modules/skybrowser/rapidxmlparser/license.txt delete mode 100644 modules/skybrowser/rapidxmlparser/manual.html delete mode 100644 modules/skybrowser/rapidxmlparser/rapidxml.hpp delete mode 100644 modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp delete mode 100644 modules/skybrowser/rapidxmlparser/rapidxml_print.hpp delete mode 100644 modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp create mode 100644 modules/skybrowser/tinyxml2/tinyxml2.cpp create mode 100644 modules/skybrowser/tinyxml2/tinyxml2.h diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 0e6cfd1fa1..53db470fff 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -29,7 +29,7 @@ set(HEADER_FILES skybrowsermodule.h include/screenspaceskybrowser.h include/screenspaceskytarget.h - rapidxmlparser/rapidxml.hpp + tinyxml2/tinyxml2.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -40,6 +40,7 @@ set(SOURCE_FILES skybrowsermodule_lua.inl src/screenspaceskybrowser.cpp src/screenspaceskytarget.cpp + tinyxml2/tinyxml2.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/rapidxmlparser/license.txt b/modules/skybrowser/rapidxmlparser/license.txt deleted file mode 100644 index 140983180b..0000000000 --- a/modules/skybrowser/rapidxmlparser/license.txt +++ /dev/null @@ -1,52 +0,0 @@ -Use of this software is granted under one of the following two licenses, -to be chosen freely by the user. - -1. Boost Software License - Version 1.0 - August 17th, 2003 -=============================================================================== - -Copyright (c) 2006, 2007 Marcin Kalicinski - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -2. The MIT License -=============================================================================== - -Copyright (c) 2006, 2007 Marcin Kalicinski - -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. diff --git a/modules/skybrowser/rapidxmlparser/manual.html b/modules/skybrowser/rapidxmlparser/manual.html deleted file mode 100644 index 2c422703f4..0000000000 --- a/modules/skybrowser/rapidxmlparser/manual.html +++ /dev/null @@ -1,406 +0,0 @@ -

RAPIDXML Manual

Version 1.13

Copyright (C) 2006, 2009 Marcin Kalicinski
See accompanying file license.txt for license information.

Table of Contents

1. What is RapidXml?
1.1 Dependencies And Compatibility
1.2 Character Types And Encodings
1.3 Error Handling
1.4 Memory Allocation
1.5 W3C Compliance
1.6 API Design
1.7 Reliability
1.8 Acknowledgements
2. Two Minute Tutorial
2.1 Parsing
2.2 Accessing The DOM Tree
2.3 Modifying The DOM Tree
2.4 Printing XML
3. Differences From Regular XML Parsers
3.1 Lifetime Of Source Text
3.2 Ownership Of Strings
3.3 Destructive Vs Non-Destructive Mode
4. Performance
4.1 Comparison With Other Parsers
5. Reference

1. What is RapidXml?

RapidXml is an attempt to create the fastest XML DOM parser possible, while retaining useability, portability and reasonable W3C compatibility. It is an in-situ parser written in C++, with parsing speed approaching that of strlen() function executed on the same data.

- Entire parser is contained in a single header file, so no building or linking is neccesary. To use it you just need to copy rapidxml.hpp file to a convenient place (such as your project directory), and include it where needed. You may also want to use printing functions contained in header rapidxml_print.hpp.

1.1 Dependencies And Compatibility

RapidXml has no dependencies other than a very small subset of standard C++ library (<cassert>, <cstdlib>, <new> and <exception>, unless exceptions are disabled). It should compile on any reasonably conformant compiler, and was tested on Visual C++ 2003, Visual C++ 2005, Visual C++ 2008, gcc 3, gcc 4, and Comeau 4.3.3. Care was taken that no warnings are produced on these compilers, even with highest warning levels enabled.

1.2 Character Types And Encodings

RapidXml is character type agnostic, and can work both with narrow and wide characters. Current version does not fully support UTF-16 or UTF-32, so use of wide characters is somewhat incapacitated. However, it should succesfully parse wchar_t strings containing UTF-16 or UTF-32 if endianness of the data matches that of the machine. UTF-8 is fully supported, including all numeric character references, which are expanded into appropriate UTF-8 byte sequences (unless you enable parse_no_utf8 flag).

- Note that RapidXml performs no decoding - strings returned by name() and value() functions will contain text encoded using the same encoding as source file. Rapidxml understands and expands the following character references: &apos; &amp; &quot; &lt; &gt; &#...; Other character references are not expanded.

1.3 Error Handling

By default, RapidXml uses C++ exceptions to report errors. If this behaviour is undesirable, RAPIDXML_NO_EXCEPTIONS can be defined to suppress exception code. See parse_error class and parse_error_handler() function for more information.

1.4 Memory Allocation

RapidXml uses a special memory pool object to allocate nodes and attributes, because direct allocation using new operator would be far too slow. Underlying memory allocations performed by the pool can be customized by use of memory_pool::set_allocator() function. See class memory_pool for more information.

1.5 W3C Compliance

RapidXml is not a W3C compliant parser, primarily because it ignores DOCTYPE declarations. There is a number of other, minor incompatibilities as well. Still, it can successfully parse and produce complete trees of all valid XML files in W3C conformance suite (over 1000 files specially designed to find flaws in XML processors). In destructive mode it performs whitespace normalization and character entity substitution for a small set of built-in entities.

1.6 API Design

RapidXml API is minimalistic, to reduce code size as much as possible, and facilitate use in embedded environments. Additional convenience functions are provided in separate headers: rapidxml_utils.hpp and rapidxml_print.hpp. Contents of these headers is not an essential part of the library, and is currently not documented (otherwise than with comments in code).

1.7 Reliability

RapidXml is very robust and comes with a large harness of unit tests. Special care has been taken to ensure stability of the parser no matter what source text is thrown at it. One of the unit tests produces 100,000 randomly corrupted variants of XML document, which (when uncorrupted) contains all constructs recognized by RapidXml. RapidXml passes this test when it correctly recognizes that errors have been introduced, and does not crash or loop indefinitely.

- Another unit test puts RapidXml head-to-head with another, well estabilished XML parser, and verifies that their outputs match across a wide variety of small and large documents.

- Yet another test feeds RapidXml with over 1000 test files from W3C compliance suite, and verifies that correct results are obtained. There are also additional tests that verify each API function separately, and test that various parsing modes work as expected.

1.8 Acknowledgements

I would like to thank Arseny Kapoulkine for his work on pugixml, which was an inspiration for this project. Additional thanks go to Kristen Wegner for creating pugxml, from which pugixml was derived. Janusz Wohlfeil kindly ran RapidXml speed tests on hardware that I did not have access to, allowing me to expand performance comparison table.

2. Two Minute Tutorial

2.1 Parsing

The following code causes RapidXml to parse a zero-terminated string named text:
using namespace rapidxml;
-xml_document<> doc;    // character type defaults to char
-doc.parse<0>(text);    // 0 means default parse flags
-
doc object is now a root of DOM tree containing representation of the parsed XML. Because all RapidXml interface is contained inside namespace rapidxml, users must either bring contents of this namespace into scope, or fully qualify all the names. Class xml_document represents a root of the DOM hierarchy. By means of public inheritance, it is also an xml_node and a memory_pool. Template parameter of xml_document::parse() function is used to specify parsing flags, with which you can fine-tune behaviour of the parser. Note that flags must be a compile-time constant.

2.2 Accessing The DOM Tree

To access the DOM tree, use methods of xml_node and xml_attribute classes:
cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
-xml_node<> *node = doc.first_node("foobar");
-cout << "Node foobar has value " << node->value() << "\n";
-for (xml_attribute<> *attr = node->first_attribute();
-     attr; attr = attr->next_attribute())
-{
-    cout << "Node foobar has attribute " << attr->name() << " ";
-    cout << "with value " << attr->value() << "\n";
-}
-

2.3 Modifying The DOM Tree

DOM tree produced by the parser is fully modifiable. Nodes and attributes can be added/removed, and their contents changed. The below example creates a HTML document, whose sole contents is a link to google.com website:
xml_document<> doc;
-xml_node<> *node = doc.allocate_node(node_element, "a", "Google");
-doc.append_node(node);
-xml_attribute<> *attr = doc.allocate_attribute("href", "google.com");
-node->append_attribute(attr);
-
One quirk is that nodes and attributes do not own the text of their names and values. This is because normally they only store pointers to the source text. So, when assigning a new name or value to the node, care must be taken to ensure proper lifetime of the string. The easiest way to achieve it is to allocate the string from the xml_document memory pool. In the above example this is not necessary, because we are only assigning character constants. But the code below uses memory_pool::allocate_string() function to allocate node name (which will have the same lifetime as the document), and assigns it to a new node:
xml_document<> doc;
-char *node_name = doc.allocate_string(name);        // Allocate string and copy name into it
-xml_node<> *node = doc.allocate_node(node_element, node_name);  // Set node name to node_name
-
Check Reference section for description of the entire interface.

2.4 Printing XML

You can print xml_document and xml_node objects into an XML string. Use print() function or operator <<, which are defined in rapidxml_print.hpp header.
using namespace rapidxml;
-xml_document<> doc;    // character type defaults to char
-// ... some code to fill the document
-
-// Print to stream using operator <<
-std::cout << doc;   
-
-// Print to stream using print function, specifying printing flags
-print(std::cout, doc, 0);   // 0 means default printing flags
-
-// Print to string using output iterator
-std::string s;
-print(std::back_inserter(s), doc, 0);
-
-// Print to memory buffer using output iterator
-char buffer[4096];                      // You are responsible for making the buffer large enough!
-char *end = print(buffer, doc, 0);      // end contains pointer to character after last printed character
-*end = 0;                               // Add string terminator after XML
-

3. Differences From Regular XML Parsers

RapidXml is an in-situ parser, which allows it to achieve very high parsing speed. In-situ means that parser does not make copies of strings. Instead, it places pointers to the source text in the DOM hierarchy.

3.1 Lifetime Of Source Text

In-situ parsing requires that source text lives at least as long as the document object. If source text is destroyed, names and values of nodes in DOM tree will become destroyed as well. Additionally, whitespace processing, character entity translation, and zero-termination of strings require that source text be modified during parsing (but see non-destructive mode). This makes the text useless for further processing once it was parsed by RapidXml.

- In many cases however, these are not serious issues.

3.2 Ownership Of Strings

Nodes and attributes produced by RapidXml do not own their name and value strings. They merely hold the pointers to them. This means you have to be careful when setting these values manually, by using xml_base::name(const Ch *) or xml_base::value(const Ch *) functions. Care must be taken to ensure that lifetime of the string passed is at least as long as lifetime of the node/attribute. The easiest way to achieve it is to allocate the string from memory_pool owned by the document. Use memory_pool::allocate_string() function for this purpose.

3.3 Destructive Vs Non-Destructive Mode

By default, the parser modifies source text during the parsing process. This is required to achieve character entity translation, whitespace normalization, and zero-termination of strings.

- In some cases this behaviour may be undesirable, for example if source text resides in read only memory, or is mapped to memory directly from file. By using appropriate parser flags (parse_non_destructive), source text modifications can be disabled. However, because RapidXml does in-situ parsing, it obviously has the following side-effects:

4. Performance

RapidXml achieves its speed through use of several techniques:
  • In-situ parsing. When building DOM tree, RapidXml does not make copies of string data, such as node names and values. Instead, it stores pointers to interior of the source text.
  • Use of template metaprogramming techniques. This allows it to move much of the work to compile time. Through magic of the templates, C++ compiler generates a separate copy of parsing code for any combination of parser flags you use. In each copy, all possible decisions are made at compile time and all unused code is omitted.
  • Extensive use of lookup tables for parsing.
  • Hand-tuned C++ with profiling done on several most popular CPUs.
This results in a very small and fast code: a parser which is custom tailored to exact needs with each invocation.

4.1 Comparison With Other Parsers

The table below compares speed of RapidXml to some other parsers, and to strlen() function executed on the same data. On a modern CPU (as of 2007), you can expect parsing throughput to be close to 1 GB/s. As a rule of thumb, parsing speed is about 50-100x faster than Xerces DOM, 30-60x faster than TinyXml, 3-12x faster than pugxml, and about 5% - 30% faster than pugixml, the fastest XML parser I know of.
  • The test file is a real-world, 50kB large, moderately dense XML file.
  • All timing is done by using RDTSC instruction present in Pentium-compatible CPUs.
  • No profile-guided optimizations are used.
  • All parsers are running in their fastest modes.
  • The results are given in CPU cycles per character, so frequency of CPUs is irrelevant.
  • The results are minimum values from a large number of runs, to minimize effects of operating system activity, task switching, interrupt handling etc.
  • A single parse of the test file takes about 1/10th of a millisecond, so with large number of runs there is a good chance of hitting at least one no-interrupt streak, and obtaining undisturbed results.
Platform
Compiler
strlen() RapidXml pugixml 0.3 pugxml TinyXml
Pentium 4
MSVC 8.0
2.5
5.4
7.0
61.7
298.8
Pentium 4
gcc 4.1.1
0.8
6.1
9.5
67.0
413.2
Core 2
MSVC 8.0
1.0
4.5
5.0
24.6
154.8
Core 2
gcc 4.1.1
0.6
4.6
5.4
28.3
229.3
Athlon XP
MSVC 8.0
3.1
7.7
8.0
25.5
182.6
Athlon XP
gcc 4.1.1
0.9
8.2
9.2
33.7
265.2
Pentium 3
MSVC 8.0
2.0
6.3
7.0
30.9
211.9
Pentium 3
gcc 4.1.1
1.0
6.7
8.9
35.3
316.0
(*) All results are in CPU cycles per character of source text

5. Reference

This section lists all classes, functions, constants etc. and describes them in detail.
class - template - rapidxml::memory_pool
- constructor - memory_pool()
- destructor - ~memory_pool()
function allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
function allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
function allocate_string(const Ch *source=0, std::size_t size=0)
function clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0)
function clear()
function set_allocator(alloc_func *af, free_func *ff)

class rapidxml::parse_error
- constructor - parse_error(const char *what, void *where)
function what() const
function where() const

class - template - rapidxml::xml_attribute
- constructor - xml_attribute()
function document() const
function previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const

class - template - rapidxml::xml_base
- constructor - xml_base()
function name() const
function name_size() const
function value() const
function value_size() const
function name(const Ch *name, std::size_t size)
function name(const Ch *name)
function value(const Ch *value, std::size_t size)
function value(const Ch *value)
function parent() const

class - template - rapidxml::xml_document
- constructor - xml_document()
function parse(Ch *text)
function clear()

class - template - rapidxml::xml_node
- constructor - xml_node(node_type type)
function type() const
function document() const
function first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
function type(node_type type)
function prepend_node(xml_node< Ch > *child)
function append_node(xml_node< Ch > *child)
function insert_node(xml_node< Ch > *where, xml_node< Ch > *child)
function remove_first_node()
function remove_last_node()
function remove_node(xml_node< Ch > *where)
function remove_all_nodes()
function prepend_attribute(xml_attribute< Ch > *attribute)
function append_attribute(xml_attribute< Ch > *attribute)
function insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute)
function remove_first_attribute()
function remove_last_attribute()
function remove_attribute(xml_attribute< Ch > *where)
function remove_all_attributes()

namespace rapidxml
enum node_type
function parse_error_handler(const char *what, void *where)
function print(OutIt out, const xml_node< Ch > &node, int flags=0)
function print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0)
function operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node)
- constant - parse_no_data_nodes
- constant - parse_no_element_values
- constant - parse_no_string_terminators
- constant - parse_no_entity_translation
- constant - parse_no_utf8
- constant - parse_declaration_node
- constant - parse_comment_nodes
- constant - parse_doctype_node
- constant - parse_pi_nodes
- constant - parse_validate_closing_tags
- constant - parse_trim_whitespace
- constant - parse_normalize_whitespace
- constant - parse_default
- constant - parse_non_destructive
- constant - parse_fastest
- constant - parse_full
- constant - print_no_indenting


class - template - rapidxml::memory_pool

- - Defined in rapidxml.hpp
- Base class for - xml_document

Description

This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. In most cases, you will not need to use this class directly. However, if you need to create nodes manually or modify names/values of nodes, you are encouraged to use memory_pool of relevant xml_document to allocate the memory. Not only is this faster than allocating them by using new operator, but also their lifetime will be tied to the lifetime of document, possibly simplyfing memory management.

- Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. You can also call allocate_string() function to allocate strings. Such strings can then be used as names or values of nodes without worrying about their lifetime. Note that there is no free() function -- all allocations are freed at once when clear() function is called, or when the pool is destroyed.

- It is also possible to create a standalone memory_pool, and use it to allocate nodes, whose lifetime will not be tied to any document.

- Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. Until static memory is exhausted, no dynamic memory allocations are done. When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, by using global new[] and delete[] operators. This behaviour can be changed by setting custom allocation routines. Use set_allocator() function to set them.

- Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. This value defaults to the size of pointer on target architecture.

- To obtain absolutely top performance from the parser, it is important that all nodes are allocated from a single, contiguous block of memory. Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT to obtain best wasted memory to performance compromise. To do it, define their values before rapidxml.hpp file is included.

Parameters

Ch
Character type of created nodes.

- constructor - memory_pool::memory_pool

Synopsis

memory_pool(); -

Description

Constructs empty pool with default allocator functions.

- destructor - memory_pool::~memory_pool

Synopsis

~memory_pool(); -

Description

Destroys pool and frees all the memory. This causes memory occupied by nodes allocated by the pool to be freed. Nodes allocated from the pool are no longer valid.

function memory_pool::allocate_node

Synopsis

xml_node<Ch>* allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); -

Description

Allocates a new node from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

Parameters

type
Type of node to create.
name
Name to assign to the node, or 0 to assign no name.
value
Value to assign to the node, or 0 to assign no value.
name_size
Size of name to assign, or 0 to automatically calculate size from name string.
value_size
Size of value to assign, or 0 to automatically calculate size from value string.

Returns

Pointer to allocated node. This pointer will never be NULL.

function memory_pool::allocate_attribute

Synopsis

xml_attribute<Ch>* allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); -

Description

Allocates a new attribute from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

Parameters

name
Name to assign to the attribute, or 0 to assign no name.
value
Value to assign to the attribute, or 0 to assign no value.
name_size
Size of name to assign, or 0 to automatically calculate size from name string.
value_size
Size of value to assign, or 0 to automatically calculate size from value string.

Returns

Pointer to allocated attribute. This pointer will never be NULL.

function memory_pool::allocate_string

Synopsis

Ch* allocate_string(const Ch *source=0, std::size_t size=0); -

Description

Allocates a char array of given size from the pool, and optionally copies a given string to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

Parameters

source
String to initialize the allocated memory with, or 0 to not initialize it.
size
Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.

Returns

Pointer to allocated char array. This pointer will never be NULL.

function memory_pool::clone_node

Synopsis

xml_node<Ch>* clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0); -

Description

Clones an xml_node and its hierarchy of child nodes and attributes. Nodes and attributes are allocated from this memory pool. Names and values are not cloned, they are shared between the clone and the source. Result node can be optionally specified as a second parameter, in which case its contents will be replaced with cloned source node. This is useful when you want to clone entire document.

Parameters

source
Node to clone.
result
Node to put results in, or 0 to automatically allocate result node

Returns

Pointer to cloned node. This pointer will never be NULL.

function memory_pool::clear

Synopsis

void clear(); -

Description

Clears the pool. This causes memory occupied by nodes allocated by the pool to be freed. Any nodes or strings allocated from the pool will no longer be valid.

function memory_pool::set_allocator

Synopsis

void set_allocator(alloc_func *af, free_func *ff); -

Description

Sets or resets the user-defined memory allocation functions for the pool. This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. Allocation function must not return invalid pointer on failure. It should either throw, stop the program, or use longjmp() function to pass control to other place of program. If it returns invalid pointer, results are undefined.

- User defined allocation functions must have the following forms:

-void *allocate(std::size_t size);
-void free(void *pointer);

Parameters

af
Allocation function, or 0 to restore default function
ff
Free function, or 0 to restore default function

class rapidxml::parse_error

- - Defined in rapidxml.hpp

Description

Parse error exception. This exception is thrown by the parser when an error occurs. Use what() function to get human-readable error message. Use where() function to get a pointer to position within source text where error was detected.

- If throwing exceptions by the parser is undesirable, it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. This function must be defined by the user.

- This class derives from std::exception class.

- constructor - parse_error::parse_error

Synopsis

parse_error(const char *what, void *where); -

Description

Constructs parse error.

function parse_error::what

Synopsis

virtual const char* what() const; -

Description

Gets human readable description of error.

Returns

Pointer to null terminated description of the error.

function parse_error::where

Synopsis

Ch* where() const; -

Description

Gets pointer to character data where error happened. Ch should be the same as char type of xml_document that produced the error.

Returns

Pointer to location within the parsed string where error occured.

class - template - rapidxml::xml_attribute

- - Defined in rapidxml.hpp
- Inherits from - xml_base

Description

Class representing attribute node of XML document. Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). Note that after parse, both name and value of attribute will point to interior of source text used for parsing. Thus, this text must persist in memory for the lifetime of attribute.

Parameters

Ch
Character type to use.

- constructor - xml_attribute::xml_attribute

Synopsis

xml_attribute(); -

Description

Constructs an empty attribute with the specified type. Consider using memory_pool of appropriate xml_document if allocating attributes manually.

function xml_attribute::document

Synopsis

xml_document<Ch>* document() const; -

Description

Gets document of which attribute is a child.

Returns

Pointer to document that contains this attribute, or 0 if there is no parent document.

function xml_attribute::previous_attribute

Synopsis

xml_attribute<Ch>* previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets previous attribute, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

function xml_attribute::next_attribute

Synopsis

xml_attribute<Ch>* next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets next attribute, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

class - template - rapidxml::xml_base

- - Defined in rapidxml.hpp
- Base class for - xml_attribute xml_node

Description

Base class for xml_node and xml_attribute implementing common functions: name(), name_size(), value(), value_size() and parent().

Parameters

Ch
Character type to use

- constructor - xml_base::xml_base

Synopsis

xml_base(); -

function xml_base::name

Synopsis

Ch* name() const; -

Description

Gets name of the node. Interpretation of name depends on type of node. Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

- Use name_size() function to determine length of the name.

Returns

Name of node, or empty string if node has no name.

function xml_base::name_size

Synopsis

std::size_t name_size() const; -

Description

Gets size of node name, not including terminator character. This function works correctly irrespective of whether name is or is not zero terminated.

Returns

Size of node name, in characters.

function xml_base::value

Synopsis

Ch* value() const; -

Description

Gets value of node. Interpretation of value depends on type of node. Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

- Use value_size() function to determine length of the value.

Returns

Value of node, or empty string if node has no value.

function xml_base::value_size

Synopsis

std::size_t value_size() const; -

Description

Gets size of node value, not including terminator character. This function works correctly irrespective of whether value is or is not zero terminated.

Returns

Size of node value, in characters.

function xml_base::name

Synopsis

void name(const Ch *name, std::size_t size); -

Description

Sets name of node to a non zero-terminated string. See Ownership Of Strings .

- Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

- Size of name must be specified separately, because name does not have to be zero terminated. Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).

Parameters

name
Name of node to set. Does not have to be zero terminated.
size
Size of name, in characters. This does not include zero terminator, if one is present.

function xml_base::name

Synopsis

void name(const Ch *name); -

Description

Sets name of node to a zero-terminated string. See also Ownership Of Strings and xml_node::name(const Ch *, std::size_t).

Parameters

name
Name of node to set. Must be zero terminated.

function xml_base::value

Synopsis

void value(const Ch *value, std::size_t size); -

Description

Sets value of node to a non zero-terminated string. See Ownership Of Strings .

- Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

- Size of value must be specified separately, because it does not have to be zero terminated. Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).

- If an element has a child node of type node_data, it will take precedence over element value when printing. If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.

Parameters

value
value of node to set. Does not have to be zero terminated.
size
Size of value, in characters. This does not include zero terminator, if one is present.

function xml_base::value

Synopsis

void value(const Ch *value); -

Description

Sets value of node to a zero-terminated string. See also Ownership Of Strings and xml_node::value(const Ch *, std::size_t).

Parameters

value
Vame of node to set. Must be zero terminated.

function xml_base::parent

Synopsis

xml_node<Ch>* parent() const; -

Description

Gets node parent.

Returns

Pointer to parent node, or 0 if there is no parent.

class - template - rapidxml::xml_document

- - Defined in rapidxml.hpp
- Inherits from - xml_node memory_pool

Description

This class represents root of the DOM hierarchy. It is also an xml_node and a memory_pool through public inheritance. Use parse() function to build a DOM tree from a zero-terminated XML text string. parse() function allocates memory for nodes and attributes by using functions of xml_document, which are inherited from memory_pool. To access root node of the document, use the document itself, as if it was an xml_node.

Parameters

Ch
Character type to use.

- constructor - xml_document::xml_document

Synopsis

xml_document(); -

Description

Constructs empty XML document.

function xml_document::parse

Synopsis

void parse(Ch *text); -

Description

Parses zero-terminated XML string according to given flags. Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. The string must persist for the lifetime of the document. In case of error, rapidxml::parse_error exception will be thrown.

- If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. Make sure that data is zero-terminated.

- Document can be parsed into multiple times. Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.

Parameters

text
XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.

function xml_document::clear

Synopsis

void clear(); -

Description

Clears the document by deleting all nodes and clearing the memory pool. All nodes owned by document pool are destroyed.

class - template - rapidxml::xml_node

- - Defined in rapidxml.hpp
- Inherits from - xml_base
- Base class for - xml_document

Description

Class representing a node of XML document. Each node may have associated name and value strings, which are available through name() and value() functions. Interpretation of name and value depends on type of the node. Type of node can be determined by using type() function.

- Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. Thus, this text must persist in the memory for the lifetime of node.

Parameters

Ch
Character type to use.

- constructor - xml_node::xml_node

Synopsis

xml_node(node_type type); -

Description

Constructs an empty node with the specified type. Consider using memory_pool of appropriate document to allocate nodes manually.

Parameters

type
Type of node to construct.

function xml_node::type

Synopsis

node_type type() const; -

Description

Gets type of node.

Returns

Type of node.

function xml_node::document

Synopsis

xml_document<Ch>* document() const; -

Description

Gets document of which node is a child.

Returns

Pointer to document that contains this node, or 0 if there is no parent document.

function xml_node::first_node

Synopsis

xml_node<Ch>* first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets first child node, optionally matching node name.

Parameters

name
Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found child, or 0 if not found.

function xml_node::last_node

Synopsis

xml_node<Ch>* last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets last child node, optionally matching node name. Behaviour is undefined if node has no children. Use first_node() to test if node has children.

Parameters

name
Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found child, or 0 if not found.

function xml_node::previous_sibling

Synopsis

xml_node<Ch>* previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets previous sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

Parameters

name
Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found sibling, or 0 if not found.

function xml_node::next_sibling

Synopsis

xml_node<Ch>* next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets next sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

Parameters

name
Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found sibling, or 0 if not found.

function xml_node::first_attribute

Synopsis

xml_attribute<Ch>* first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets first attribute of node, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

function xml_node::last_attribute

Synopsis

xml_attribute<Ch>* last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; -

Description

Gets last attribute of node, optionally matching attribute name.

Parameters

name
Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
name_size
Size of name, in characters, or 0 to have size calculated automatically from string
case_sensitive
Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

Returns

Pointer to found attribute, or 0 if not found.

function xml_node::type

Synopsis

void type(node_type type); -

Description

Sets type of node.

Parameters

type
Type of node to set.

function xml_node::prepend_node

Synopsis

void prepend_node(xml_node< Ch > *child); -

Description

Prepends a new child node. The prepended child becomes the first child, and all existing children are moved one position back.

Parameters

child
Node to prepend.

function xml_node::append_node

Synopsis

void append_node(xml_node< Ch > *child); -

Description

Appends a new child node. The appended child becomes the last child.

Parameters

child
Node to append.

function xml_node::insert_node

Synopsis

void insert_node(xml_node< Ch > *where, xml_node< Ch > *child); -

Description

Inserts a new child node at specified place inside the node. All children after and including the specified node are moved one position back.

Parameters

where
Place where to insert the child, or 0 to insert at the back.
child
Node to insert.

function xml_node::remove_first_node

Synopsis

void remove_first_node(); -

Description

Removes first child node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

function xml_node::remove_last_node

Synopsis

void remove_last_node(); -

Description

Removes last child of the node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

function xml_node::remove_node

Synopsis

void remove_node(xml_node< Ch > *where); -

Description

Removes specified child from the node.

function xml_node::remove_all_nodes

Synopsis

void remove_all_nodes(); -

Description

Removes all child nodes (but not attributes).

function xml_node::prepend_attribute

Synopsis

void prepend_attribute(xml_attribute< Ch > *attribute); -

Description

Prepends a new attribute to the node.

Parameters

attribute
Attribute to prepend.

function xml_node::append_attribute

Synopsis

void append_attribute(xml_attribute< Ch > *attribute); -

Description

Appends a new attribute to the node.

Parameters

attribute
Attribute to append.

function xml_node::insert_attribute

Synopsis

void insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute); -

Description

Inserts a new attribute at specified place inside the node. All attributes after and including the specified attribute are moved one position back.

Parameters

where
Place where to insert the attribute, or 0 to insert at the back.
attribute
Attribute to insert.

function xml_node::remove_first_attribute

Synopsis

void remove_first_attribute(); -

Description

Removes first attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

function xml_node::remove_last_attribute

Synopsis

void remove_last_attribute(); -

Description

Removes last attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

function xml_node::remove_attribute

Synopsis

void remove_attribute(xml_attribute< Ch > *where); -

Description

Removes specified attribute from node.

Parameters

where
Pointer to attribute to be removed.

function xml_node::remove_all_attributes

Synopsis

void remove_all_attributes(); -

Description

Removes all attributes of node.

enum node_type

Description

Enumeration listing all node types produced by the parser. Use xml_node::type() function to query node type.

Values

node_document
A document node. Name and value are empty.
node_element
An element node. Name contains element name. Value contains text of first data node.
node_data
A data node. Name is empty. Value contains data text.
node_cdata
A CDATA node. Name is empty. Value contains data text.
node_comment
A comment node. Name is empty. Value contains comment text.
node_declaration
A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
node_doctype
A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
node_pi
A PI node. Name contains target. Value contains instructions.

function parse_error_handler

Synopsis

void rapidxml::parse_error_handler(const char *what, void *where); -

Description

When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function is called to notify user about the error. It must be defined by the user.

- This function cannot return. If it does, the results are undefined.

- A very simple definition might look like that: - void rapidxml::parse_error_handler(const char *what, void *where) - { - std::cout << "Parse error: " << what << "\n"; - std::abort(); - } -

Parameters

what
Human readable description of the error.
where
Pointer to character data where error was detected.

function print

Synopsis

OutIt rapidxml::print(OutIt out, const xml_node< Ch > &node, int flags=0); -

Description

Prints XML to given output iterator.

Parameters

out
Output iterator to print to.
node
Node to be printed. Pass xml_document to print entire document.
flags
Flags controlling how XML is printed.

Returns

Output iterator pointing to position immediately after last character of printed text.

function print

Synopsis

std::basic_ostream<Ch>& rapidxml::print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0); -

Description

Prints XML to given output stream.

Parameters

out
Output stream to print to.
node
Node to be printed. Pass xml_document to print entire document.
flags
Flags controlling how XML is printed.

Returns

Output stream.

function operator<<

Synopsis

std::basic_ostream<Ch>& rapidxml::operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node); -

Description

Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.

Parameters

out
Output stream to print to.
node
Node to be printed.

Returns

Output stream.

- constant - parse_no_data_nodes

Synopsis

const int parse_no_data_nodes - = 0x1; -

Description

Parse flag instructing the parser to not create data nodes. Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_no_element_values

Synopsis

const int parse_no_element_values - = 0x2; -

Description

Parse flag instructing the parser to not use text of first data node as a value of parent element. Can be combined with other flags by use of | operator. Note that child data nodes of element node take precendence over its value when printing. That is, if element has one or more child data nodes and a value, the value will be ignored. Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.

- See xml_document::parse() function.

- constant - parse_no_string_terminators

Synopsis

const int parse_no_string_terminators - = 0x4; -

Description

Parse flag instructing the parser to not place zero terminators after strings in the source text. By default zero terminators are placed, modifying source text. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_no_entity_translation

Synopsis

const int parse_no_entity_translation - = 0x8; -

Description

Parse flag instructing the parser to not translate entities in the source text. By default entities are translated, modifying source text. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_no_utf8

Synopsis

const int parse_no_utf8 - = 0x10; -

Description

Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. By default, UTF-8 handling is enabled. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_declaration_node

Synopsis

const int parse_declaration_node - = 0x20; -

Description

Parse flag instructing the parser to create XML declaration node. By default, declaration node is not created. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_comment_nodes

Synopsis

const int parse_comment_nodes - = 0x40; -

Description

Parse flag instructing the parser to create comments nodes. By default, comment nodes are not created. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_doctype_node

Synopsis

const int parse_doctype_node - = 0x80; -

Description

Parse flag instructing the parser to create DOCTYPE node. By default, doctype node is not created. Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_pi_nodes

Synopsis

const int parse_pi_nodes - = 0x100; -

Description

Parse flag instructing the parser to create PI nodes. By default, PI nodes are not created. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_validate_closing_tags

Synopsis

const int parse_validate_closing_tags - = 0x200; -

Description

Parse flag instructing the parser to validate closing tag names. If not set, name inside closing tag is irrelevant to the parser. By default, closing tags are not validated. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_trim_whitespace

Synopsis

const int parse_trim_whitespace - = 0x400; -

Description

Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. By default, whitespace is not trimmed. This flag does not cause the parser to modify source text. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_normalize_whitespace

Synopsis

const int parse_normalize_whitespace - = 0x800; -

Description

Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. By default, whitespace is not normalized. If this flag is specified, source text will be modified. Can be combined with other flags by use of | operator.

- See xml_document::parse() function.

- constant - parse_default

Synopsis

const int parse_default - = 0; -

Description

Parse flags which represent default behaviour of the parser. This is always equal to 0, so that all other flags can be simply ored together. Normally there is no need to inconveniently disable flags by anding with their negated (~) values. This also means that meaning of each flag is a negation of the default setting. For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, and using the flag will disable it.

- See xml_document::parse() function.

- constant - parse_non_destructive

Synopsis

const int parse_non_destructive - = parse_no_string_terminators | parse_no_entity_translation; -

Description

A combination of parse flags that forbids any modifications of the source text. This also results in faster parsing. However, note that the following will occur:
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • entities will not be translated
  • whitespace will not be normalized
-See xml_document::parse() function.

- constant - parse_fastest

Synopsis

const int parse_fastest - = parse_non_destructive | parse_no_data_nodes; -

Description

A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.

- See xml_document::parse() function.

- constant - parse_full

Synopsis

const int parse_full - = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; -

Description

A combination of parse flags resulting in largest amount of data being extracted. This usually results in slowest parsing.

- See xml_document::parse() function.

- constant - print_no_indenting

Synopsis

const int print_no_indenting - = 0x1; -

Description

Printer flag instructing the printer to suppress indenting of XML. See print() function.

\ No newline at end of file diff --git a/modules/skybrowser/rapidxmlparser/rapidxml.hpp b/modules/skybrowser/rapidxmlparser/rapidxml.hpp deleted file mode 100644 index ae91e081d0..0000000000 --- a/modules/skybrowser/rapidxmlparser/rapidxml.hpp +++ /dev/null @@ -1,2596 +0,0 @@ -#ifndef RAPIDXML_HPP_INCLUDED -#define RAPIDXML_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation - -// If standard library is disabled, user must provide implementations of required functions and typedefs -#if !defined(RAPIDXML_NO_STDLIB) - #include // For std::size_t - #include // For assert - #include // For placement new -#endif - -// On MSVC, disable "conditional expression is constant" warning (level 4). -// This warning is almost impossible to avoid with certain types of templated code -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4127) // Conditional expression is constant -#endif - -/////////////////////////////////////////////////////////////////////////// -// RAPIDXML_PARSE_ERROR - -#if defined(RAPIDXML_NO_EXCEPTIONS) - -#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } - -namespace rapidxml -{ - //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, - //! this function is called to notify user about the error. - //! It must be defined by the user. - //!

- //! This function cannot return. If it does, the results are undefined. - //!

- //! A very simple definition might look like that: - //!

-    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
-    //! {
-    //!     std::cout << "Parse error: " << what << "\n";
-    //!     std::abort();
-    //! }
-    //! 
- //! \param what Human readable description of the error. - //! \param where Pointer to character data where error was detected. - void parse_error_handler(const char *what, void *where); -} - -#else - -#include // For std::exception - -#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) - -namespace rapidxml -{ - - //! Parse error exception. - //! This exception is thrown by the parser when an error occurs. - //! Use what() function to get human-readable error message. - //! Use where() function to get a pointer to position within source text where error was detected. - //!

- //! If throwing exceptions by the parser is undesirable, - //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. - //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. - //! This function must be defined by the user. - //!

- //! This class derives from std::exception class. - class parse_error: public std::exception - { - - public: - - //! Constructs parse error - parse_error(const char *what, void *where) - : m_what(what) - , m_where(where) - { - } - - //! Gets human readable description of error. - //! \return Pointer to null terminated description of the error. - virtual const char *what() const throw() - { - return m_what; - } - - //! Gets pointer to character data where error happened. - //! Ch should be the same as char type of xml_document that produced the error. - //! \return Pointer to location within the parsed string where error occured. - template - Ch *where() const - { - return reinterpret_cast(m_where); - } - - private: - - const char *m_what; - void *m_where; - - }; -} - -#endif - -/////////////////////////////////////////////////////////////////////////// -// Pool sizes - -#ifndef RAPIDXML_STATIC_POOL_SIZE - // Size of static memory block of memory_pool. - // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. - // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. - #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) -#endif - -#ifndef RAPIDXML_DYNAMIC_POOL_SIZE - // Size of dynamic memory block of memory_pool. - // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. - // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. - #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) -#endif - -#ifndef RAPIDXML_ALIGNMENT - // Memory allocation alignment. - // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. - // All memory allocations for nodes, attributes and strings will be aligned to this value. - // This must be a power of 2 and at least 1, otherwise memory_pool will not work. - #define RAPIDXML_ALIGNMENT sizeof(void *) -#endif - -namespace rapidxml -{ - // Forward declarations - template class xml_node; - template class xml_attribute; - template class xml_document; - - //! Enumeration listing all node types produced by the parser. - //! Use xml_node::type() function to query node type. - enum node_type - { - node_document, //!< A document node. Name and value are empty. - node_element, //!< An element node. Name contains element name. Value contains text of first data node. - node_data, //!< A data node. Name is empty. Value contains data text. - node_cdata, //!< A CDATA node. Name is empty. Value contains data text. - node_comment, //!< A comment node. Name is empty. Value contains comment text. - node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. - node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. - node_pi //!< A PI node. Name contains target. Value contains instructions. - }; - - /////////////////////////////////////////////////////////////////////// - // Parsing flags - - //! Parse flag instructing the parser to not create data nodes. - //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_data_nodes = 0x1; - - //! Parse flag instructing the parser to not use text of first data node as a value of parent element. - //! Can be combined with other flags by use of | operator. - //! Note that child data nodes of element node take precendence over its value when printing. - //! That is, if element has one or more child data nodes and a value, the value will be ignored. - //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. - //!

- //! See xml_document::parse() function. - const int parse_no_element_values = 0x2; - - //! Parse flag instructing the parser to not place zero terminators after strings in the source text. - //! By default zero terminators are placed, modifying source text. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_string_terminators = 0x4; - - //! Parse flag instructing the parser to not translate entities in the source text. - //! By default entities are translated, modifying source text. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_entity_translation = 0x8; - - //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. - //! By default, UTF-8 handling is enabled. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_utf8 = 0x10; - - //! Parse flag instructing the parser to create XML declaration node. - //! By default, declaration node is not created. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_declaration_node = 0x20; - - //! Parse flag instructing the parser to create comments nodes. - //! By default, comment nodes are not created. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_comment_nodes = 0x40; - - //! Parse flag instructing the parser to create DOCTYPE node. - //! By default, doctype node is not created. - //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_doctype_node = 0x80; - - //! Parse flag instructing the parser to create PI nodes. - //! By default, PI nodes are not created. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_pi_nodes = 0x100; - - //! Parse flag instructing the parser to validate closing tag names. - //! If not set, name inside closing tag is irrelevant to the parser. - //! By default, closing tags are not validated. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_validate_closing_tags = 0x200; - - //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. - //! By default, whitespace is not trimmed. - //! This flag does not cause the parser to modify source text. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_trim_whitespace = 0x400; - - //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. - //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. - //! By default, whitespace is not normalized. - //! If this flag is specified, source text will be modified. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_normalize_whitespace = 0x800; - - // Compound flags - - //! Parse flags which represent default behaviour of the parser. - //! This is always equal to 0, so that all other flags can be simply ored together. - //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. - //! This also means that meaning of each flag is a negation of the default setting. - //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, - //! and using the flag will disable it. - //!

- //! See xml_document::parse() function. - const int parse_default = 0; - - //! A combination of parse flags that forbids any modifications of the source text. - //! This also results in faster parsing. However, note that the following will occur: - //!
    - //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • - //!
  • entities will not be translated
  • - //!
  • whitespace will not be normalized
  • - //!
- //! See xml_document::parse() function. - const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; - - //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. - //!

- //! See xml_document::parse() function. - const int parse_fastest = parse_non_destructive | parse_no_data_nodes; - - //! A combination of parse flags resulting in largest amount of data being extracted. - //! This usually results in slowest parsing. - //!

- //! See xml_document::parse() function. - const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; - - /////////////////////////////////////////////////////////////////////// - // Internals - - //! \cond internal - namespace internal - { - - // Struct that contains lookup tables for the parser - // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). - template - struct lookup_tables - { - static const unsigned char lookup_whitespace[256]; // Whitespace table - static const unsigned char lookup_node_name[256]; // Node name table - static const unsigned char lookup_text[256]; // Text table - static const unsigned char lookup_text_pure_no_ws[256]; // Text table - static const unsigned char lookup_text_pure_with_ws[256]; // Text table - static const unsigned char lookup_attribute_name[256]; // Attribute name table - static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote - static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote - static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes - static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes - static const unsigned char lookup_digits[256]; // Digits - static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters - }; - - // Find length of the string - template - inline std::size_t measure(const Ch *p) - { - const Ch *tmp = p; - while (*tmp) - ++tmp; - return tmp - p; - } - - // Compare strings for equality - template - inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) - { - if (size1 != size2) - return false; - if (case_sensitive) - { - for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) - if (*p1 != *p2) - return false; - } - else - { - for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) - if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) - return false; - } - return true; - } - } - //! \endcond - - /////////////////////////////////////////////////////////////////////// - // Memory pool - - //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. - //! In most cases, you will not need to use this class directly. - //! However, if you need to create nodes manually or modify names/values of nodes, - //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. - //! Not only is this faster than allocating them by using new operator, - //! but also their lifetime will be tied to the lifetime of document, - //! possibly simplyfing memory management. - //!

- //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. - //! You can also call allocate_string() function to allocate strings. - //! Such strings can then be used as names or values of nodes without worrying about their lifetime. - //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, - //! or when the pool is destroyed. - //!

- //! It is also possible to create a standalone memory_pool, and use it - //! to allocate nodes, whose lifetime will not be tied to any document. - //!

- //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. - //! Until static memory is exhausted, no dynamic memory allocations are done. - //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, - //! by using global new[] and delete[] operators. - //! This behaviour can be changed by setting custom allocation routines. - //! Use set_allocator() function to set them. - //!

- //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. - //! This value defaults to the size of pointer on target architecture. - //!

- //! To obtain absolutely top performance from the parser, - //! it is important that all nodes are allocated from a single, contiguous block of memory. - //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. - //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT - //! to obtain best wasted memory to performance compromise. - //! To do it, define their values before rapidxml.hpp file is included. - //! \param Ch Character type of created nodes. - template - class memory_pool - { - - public: - - //! \cond internal - typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory - typedef void (free_func)(void *); // Type of user-defined function used to free memory - //! \endcond - - //! Constructs empty pool with default allocator functions. - memory_pool() - : m_alloc_func(0) - , m_free_func(0) - { - init(); - } - - //! Destroys pool and frees all the memory. - //! This causes memory occupied by nodes allocated by the pool to be freed. - //! Nodes allocated from the pool are no longer valid. - ~memory_pool() - { - clear(); - } - - //! Allocates a new node from the pool, and optionally assigns name and value to it. - //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. - //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function - //! will call rapidxml::parse_error_handler() function. - //! \param type Type of node to create. - //! \param name Name to assign to the node, or 0 to assign no name. - //! \param value Value to assign to the node, or 0 to assign no value. - //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. - //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. - //! \return Pointer to allocated node. This pointer will never be NULL. - xml_node *allocate_node(node_type type, - const Ch *name = 0, const Ch *value = 0, - std::size_t name_size = 0, std::size_t value_size = 0) - { - void *memory = allocate_aligned(sizeof(xml_node)); - xml_node *node = new(memory) xml_node(type); - if (name) - { - if (name_size > 0) - node->name(name, name_size); - else - node->name(name); - } - if (value) - { - if (value_size > 0) - node->value(value, value_size); - else - node->value(value); - } - return node; - } - - //! Allocates a new attribute from the pool, and optionally assigns name and value to it. - //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. - //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function - //! will call rapidxml::parse_error_handler() function. - //! \param name Name to assign to the attribute, or 0 to assign no name. - //! \param value Value to assign to the attribute, or 0 to assign no value. - //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. - //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. - //! \return Pointer to allocated attribute. This pointer will never be NULL. - xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, - std::size_t name_size = 0, std::size_t value_size = 0) - { - void *memory = allocate_aligned(sizeof(xml_attribute)); - xml_attribute *attribute = new(memory) xml_attribute; - if (name) - { - if (name_size > 0) - attribute->name(name, name_size); - else - attribute->name(name); - } - if (value) - { - if (value_size > 0) - attribute->value(value, value_size); - else - attribute->value(value); - } - return attribute; - } - - //! Allocates a char array of given size from the pool, and optionally copies a given string to it. - //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. - //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function - //! will call rapidxml::parse_error_handler() function. - //! \param source String to initialize the allocated memory with, or 0 to not initialize it. - //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. - //! \return Pointer to allocated char array. This pointer will never be NULL. - Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) - { - assert(source || size); // Either source or size (or both) must be specified - if (size == 0) - size = internal::measure(source) + 1; - Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); - if (source) - for (std::size_t i = 0; i < size; ++i) - result[i] = source[i]; - return result; - } - - //! Clones an xml_node and its hierarchy of child nodes and attributes. - //! Nodes and attributes are allocated from this memory pool. - //! Names and values are not cloned, they are shared between the clone and the source. - //! Result node can be optionally specified as a second parameter, - //! in which case its contents will be replaced with cloned source node. - //! This is useful when you want to clone entire document. - //! \param source Node to clone. - //! \param result Node to put results in, or 0 to automatically allocate result node - //! \return Pointer to cloned node. This pointer will never be NULL. - xml_node *clone_node(const xml_node *source, xml_node *result = 0) - { - // Prepare result node - if (result) - { - result->remove_all_attributes(); - result->remove_all_nodes(); - result->type(source->type()); - } - else - result = allocate_node(source->type()); - - // Clone name and value - result->name(source->name(), source->name_size()); - result->value(source->value(), source->value_size()); - - // Clone child nodes and attributes - for (xml_node *child = source->first_node(); child; child = child->next_sibling()) - result->append_node(clone_node(child)); - for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) - result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); - - return result; - } - - //! Clears the pool. - //! This causes memory occupied by nodes allocated by the pool to be freed. - //! Any nodes or strings allocated from the pool will no longer be valid. - void clear() - { - while (m_begin != m_static_memory) - { - char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; - if (m_free_func) - m_free_func(m_begin); - else - delete[] m_begin; - m_begin = previous_begin; - } - init(); - } - - //! Sets or resets the user-defined memory allocation functions for the pool. - //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. - //! Allocation function must not return invalid pointer on failure. It should either throw, - //! stop the program, or use longjmp() function to pass control to other place of program. - //! If it returns invalid pointer, results are undefined. - //!

- //! User defined allocation functions must have the following forms: - //!
- //!
void *allocate(std::size_t size); - //!
void free(void *pointer); - //!

- //! \param af Allocation function, or 0 to restore default function - //! \param ff Free function, or 0 to restore default function - void set_allocator(alloc_func *af, free_func *ff) - { - assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet - m_alloc_func = af; - m_free_func = ff; - } - - private: - - struct header - { - char *previous_begin; - }; - - void init() - { - m_begin = m_static_memory; - m_ptr = align(m_begin); - m_end = m_static_memory + sizeof(m_static_memory); - } - - char *align(char *ptr) - { - std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); - return ptr + alignment; - } - - char *allocate_raw(std::size_t size) - { - // Allocate - void *memory; - if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] - { - memory = m_alloc_func(size); - assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp - } - else - { - memory = new char[size]; -#ifdef RAPIDXML_NO_EXCEPTIONS - if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc - RAPIDXML_PARSE_ERROR("out of memory", 0); -#endif - } - return static_cast(memory); - } - - void *allocate_aligned(std::size_t size) - { - // Calculate aligned pointer - char *result = align(m_ptr); - - // If not enough memory left in current pool, allocate a new pool - if (result + size > m_end) - { - // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) - std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; - if (pool_size < size) - pool_size = size; - - // Allocate - std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation - char *raw_memory = allocate_raw(alloc_size); - - // Setup new pool in allocated memory - char *pool = align(raw_memory); - header *new_header = reinterpret_cast
(pool); - new_header->previous_begin = m_begin; - m_begin = raw_memory; - m_ptr = pool + sizeof(header); - m_end = raw_memory + alloc_size; - - // Calculate aligned pointer again using new pool - result = align(m_ptr); - } - - // Update pool and return aligned pointer - m_ptr = result + size; - return result; - } - - char *m_begin; // Start of raw memory making up current pool - char *m_ptr; // First free byte in current pool - char *m_end; // One past last available byte in current pool - char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory - alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used - free_func *m_free_func; // Free function, or 0 if default is to be used - }; - - /////////////////////////////////////////////////////////////////////////// - // XML base - - //! Base class for xml_node and xml_attribute implementing common functions: - //! name(), name_size(), value(), value_size() and parent(). - //! \param Ch Character type to use - template - class xml_base - { - - public: - - /////////////////////////////////////////////////////////////////////////// - // Construction & destruction - - // Construct a base with empty name, value and parent - xml_base() - : m_name(0) - , m_value(0) - , m_parent(0) - { - } - - /////////////////////////////////////////////////////////////////////////// - // Node data access - - //! Gets name of the node. - //! Interpretation of name depends on type of node. - //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. - //!

- //! Use name_size() function to determine length of the name. - //! \return Name of node, or empty string if node has no name. - Ch *name() const - { - return m_name ? m_name : nullstr(); - } - - //! Gets size of node name, not including terminator character. - //! This function works correctly irrespective of whether name is or is not zero terminated. - //! \return Size of node name, in characters. - std::size_t name_size() const - { - return m_name ? m_name_size : 0; - } - - //! Gets value of node. - //! Interpretation of value depends on type of node. - //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. - //!

- //! Use value_size() function to determine length of the value. - //! \return Value of node, or empty string if node has no value. - Ch *value() const - { - return m_value ? m_value : nullstr(); - } - - //! Gets size of node value, not including terminator character. - //! This function works correctly irrespective of whether value is or is not zero terminated. - //! \return Size of node value, in characters. - std::size_t value_size() const - { - return m_value ? m_value_size : 0; - } - - /////////////////////////////////////////////////////////////////////////// - // Node modification - - //! Sets name of node to a non zero-terminated string. - //! See \ref ownership_of_strings. - //!

- //! Note that node does not own its name or value, it only stores a pointer to it. - //! It will not delete or otherwise free the pointer on destruction. - //! It is reponsibility of the user to properly manage lifetime of the string. - //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - - //! on destruction of the document the string will be automatically freed. - //!

- //! Size of name must be specified separately, because name does not have to be zero terminated. - //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). - //! \param name Name of node to set. Does not have to be zero terminated. - //! \param size Size of name, in characters. This does not include zero terminator, if one is present. - void name(const Ch *name, std::size_t size) - { - m_name = const_cast(name); - m_name_size = size; - } - - //! Sets name of node to a zero-terminated string. - //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). - //! \param name Name of node to set. Must be zero terminated. - void name(const Ch *name) - { - this->name(name, internal::measure(name)); - } - - //! Sets value of node to a non zero-terminated string. - //! See \ref ownership_of_strings. - //!

- //! Note that node does not own its name or value, it only stores a pointer to it. - //! It will not delete or otherwise free the pointer on destruction. - //! It is reponsibility of the user to properly manage lifetime of the string. - //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - - //! on destruction of the document the string will be automatically freed. - //!

- //! Size of value must be specified separately, because it does not have to be zero terminated. - //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). - //!

- //! If an element has a child node of type node_data, it will take precedence over element value when printing. - //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. - //! \param value value of node to set. Does not have to be zero terminated. - //! \param size Size of value, in characters. This does not include zero terminator, if one is present. - void value(const Ch *value, std::size_t size) - { - m_value = const_cast(value); - m_value_size = size; - } - - //! Sets value of node to a zero-terminated string. - //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). - //! \param value Vame of node to set. Must be zero terminated. - void value(const Ch *value) - { - this->value(value, internal::measure(value)); - } - - /////////////////////////////////////////////////////////////////////////// - // Related nodes access - - //! Gets node parent. - //! \return Pointer to parent node, or 0 if there is no parent. - xml_node *parent() const - { - return m_parent; - } - - protected: - - // Return empty string - static Ch *nullstr() - { - static Ch zero = Ch('\0'); - return &zero; - } - - Ch *m_name; // Name of node, or 0 if no name - Ch *m_value; // Value of node, or 0 if no value - std::size_t m_name_size; // Length of node name, or undefined of no name - std::size_t m_value_size; // Length of node value, or undefined if no value - xml_node *m_parent; // Pointer to parent node, or 0 if none - - }; - - //! Class representing attribute node of XML document. - //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). - //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. - //! Thus, this text must persist in memory for the lifetime of attribute. - //! \param Ch Character type to use. - template - class xml_attribute: public xml_base - { - - friend class xml_node; - - public: - - /////////////////////////////////////////////////////////////////////////// - // Construction & destruction - - //! Constructs an empty attribute with the specified type. - //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. - xml_attribute() - { - } - - /////////////////////////////////////////////////////////////////////////// - // Related nodes access - - //! Gets document of which attribute is a child. - //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. - xml_document *document() const - { - if (xml_node *node = this->parent()) - { - while (node->parent()) - node = node->parent(); - return node->type() == node_document ? static_cast *>(node) : 0; - } - else - return 0; - } - - //! Gets previous attribute, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return this->m_parent ? m_prev_attribute : 0; - } - - //! Gets next attribute, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return this->m_parent ? m_next_attribute : 0; - } - - private: - - xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero - xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero - - }; - - /////////////////////////////////////////////////////////////////////////// - // XML node - - //! Class representing a node of XML document. - //! Each node may have associated name and value strings, which are available through name() and value() functions. - //! Interpretation of name and value depends on type of the node. - //! Type of node can be determined by using type() function. - //!

- //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. - //! Thus, this text must persist in the memory for the lifetime of node. - //! \param Ch Character type to use. - template - class xml_node: public xml_base - { - - public: - - /////////////////////////////////////////////////////////////////////////// - // Construction & destruction - - //! Constructs an empty node with the specified type. - //! Consider using memory_pool of appropriate document to allocate nodes manually. - //! \param type Type of node to construct. - xml_node(node_type type) - : m_type(type) - , m_first_node(0) - , m_first_attribute(0) - { - } - - /////////////////////////////////////////////////////////////////////////// - // Node data access - - //! Gets type of node. - //! \return Type of node. - node_type type() const - { - return m_type; - } - - /////////////////////////////////////////////////////////////////////////// - // Related nodes access - - //! Gets document of which node is a child. - //! \return Pointer to document that contains this node, or 0 if there is no parent document. - xml_document *document() const - { - xml_node *node = const_cast *>(this); - while (node->parent()) - node = node->parent(); - return node->type() == node_document ? static_cast *>(node) : 0; - } - - //! Gets first child node, optionally matching node name. - //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found child, or 0 if not found. - xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *child = m_first_node; child; child = child->next_sibling()) - if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) - return child; - return 0; - } - else - return m_first_node; - } - - //! Gets last child node, optionally matching node name. - //! Behaviour is undefined if node has no children. - //! Use first_node() to test if node has children. - //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found child, or 0 if not found. - xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - assert(m_first_node); // Cannot query for last child if node has no children - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *child = m_last_node; child; child = child->previous_sibling()) - if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) - return child; - return 0; - } - else - return m_last_node; - } - - //! Gets previous sibling node, optionally matching node name. - //! Behaviour is undefined if node has no parent. - //! Use parent() to test if node has a parent. - //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found sibling, or 0 if not found. - xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - assert(this->m_parent); // Cannot query for siblings if node has no parent - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) - if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) - return sibling; - return 0; - } - else - return m_prev_sibling; - } - - //! Gets next sibling node, optionally matching node name. - //! Behaviour is undefined if node has no parent. - //! Use parent() to test if node has a parent. - //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found sibling, or 0 if not found. - xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - assert(this->m_parent); // Cannot query for siblings if node has no parent - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) - if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) - return sibling; - return 0; - } - else - return m_next_sibling; - } - - //! Gets first attribute of node, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return m_first_attribute; - } - - //! Gets last attribute of node, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return m_first_attribute ? m_last_attribute : 0; - } - - /////////////////////////////////////////////////////////////////////////// - // Node modification - - //! Sets type of node. - //! \param type Type of node to set. - void type(node_type type) - { - m_type = type; - } - - /////////////////////////////////////////////////////////////////////////// - // Node manipulation - - //! Prepends a new child node. - //! The prepended child becomes the first child, and all existing children are moved one position back. - //! \param child Node to prepend. - void prepend_node(xml_node *child) - { - assert(child && !child->parent() && child->type() != node_document); - if (first_node()) - { - child->m_next_sibling = m_first_node; - m_first_node->m_prev_sibling = child; - } - else - { - child->m_next_sibling = 0; - m_last_node = child; - } - m_first_node = child; - child->m_parent = this; - child->m_prev_sibling = 0; - } - - //! Appends a new child node. - //! The appended child becomes the last child. - //! \param child Node to append. - void append_node(xml_node *child) - { - assert(child && !child->parent() && child->type() != node_document); - if (first_node()) - { - child->m_prev_sibling = m_last_node; - m_last_node->m_next_sibling = child; - } - else - { - child->m_prev_sibling = 0; - m_first_node = child; - } - m_last_node = child; - child->m_parent = this; - child->m_next_sibling = 0; - } - - //! Inserts a new child node at specified place inside the node. - //! All children after and including the specified node are moved one position back. - //! \param where Place where to insert the child, or 0 to insert at the back. - //! \param child Node to insert. - void insert_node(xml_node *where, xml_node *child) - { - assert(!where || where->parent() == this); - assert(child && !child->parent() && child->type() != node_document); - if (where == m_first_node) - prepend_node(child); - else if (where == 0) - append_node(child); - else - { - child->m_prev_sibling = where->m_prev_sibling; - child->m_next_sibling = where; - where->m_prev_sibling->m_next_sibling = child; - where->m_prev_sibling = child; - child->m_parent = this; - } - } - - //! Removes first child node. - //! If node has no children, behaviour is undefined. - //! Use first_node() to test if node has children. - void remove_first_node() - { - assert(first_node()); - xml_node *child = m_first_node; - m_first_node = child->m_next_sibling; - if (child->m_next_sibling) - child->m_next_sibling->m_prev_sibling = 0; - else - m_last_node = 0; - child->m_parent = 0; - } - - //! Removes last child of the node. - //! If node has no children, behaviour is undefined. - //! Use first_node() to test if node has children. - void remove_last_node() - { - assert(first_node()); - xml_node *child = m_last_node; - if (child->m_prev_sibling) - { - m_last_node = child->m_prev_sibling; - child->m_prev_sibling->m_next_sibling = 0; - } - else - m_first_node = 0; - child->m_parent = 0; - } - - //! Removes specified child from the node - // \param where Pointer to child to be removed. - void remove_node(xml_node *where) - { - assert(where && where->parent() == this); - assert(first_node()); - if (where == m_first_node) - remove_first_node(); - else if (where == m_last_node) - remove_last_node(); - else - { - where->m_prev_sibling->m_next_sibling = where->m_next_sibling; - where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; - where->m_parent = 0; - } - } - - //! Removes all child nodes (but not attributes). - void remove_all_nodes() - { - for (xml_node *node = first_node(); node; node = node->m_next_sibling) - node->m_parent = 0; - m_first_node = 0; - } - - //! Prepends a new attribute to the node. - //! \param attribute Attribute to prepend. - void prepend_attribute(xml_attribute *attribute) - { - assert(attribute && !attribute->parent()); - if (first_attribute()) - { - attribute->m_next_attribute = m_first_attribute; - m_first_attribute->m_prev_attribute = attribute; - } - else - { - attribute->m_next_attribute = 0; - m_last_attribute = attribute; - } - m_first_attribute = attribute; - attribute->m_parent = this; - attribute->m_prev_attribute = 0; - } - - //! Appends a new attribute to the node. - //! \param attribute Attribute to append. - void append_attribute(xml_attribute *attribute) - { - assert(attribute && !attribute->parent()); - if (first_attribute()) - { - attribute->m_prev_attribute = m_last_attribute; - m_last_attribute->m_next_attribute = attribute; - } - else - { - attribute->m_prev_attribute = 0; - m_first_attribute = attribute; - } - m_last_attribute = attribute; - attribute->m_parent = this; - attribute->m_next_attribute = 0; - } - - //! Inserts a new attribute at specified place inside the node. - //! All attributes after and including the specified attribute are moved one position back. - //! \param where Place where to insert the attribute, or 0 to insert at the back. - //! \param attribute Attribute to insert. - void insert_attribute(xml_attribute *where, xml_attribute *attribute) - { - assert(!where || where->parent() == this); - assert(attribute && !attribute->parent()); - if (where == m_first_attribute) - prepend_attribute(attribute); - else if (where == 0) - append_attribute(attribute); - else - { - attribute->m_prev_attribute = where->m_prev_attribute; - attribute->m_next_attribute = where; - where->m_prev_attribute->m_next_attribute = attribute; - where->m_prev_attribute = attribute; - attribute->m_parent = this; - } - } - - //! Removes first attribute of the node. - //! If node has no attributes, behaviour is undefined. - //! Use first_attribute() to test if node has attributes. - void remove_first_attribute() - { - assert(first_attribute()); - xml_attribute *attribute = m_first_attribute; - if (attribute->m_next_attribute) - { - attribute->m_next_attribute->m_prev_attribute = 0; - } - else - m_last_attribute = 0; - attribute->m_parent = 0; - m_first_attribute = attribute->m_next_attribute; - } - - //! Removes last attribute of the node. - //! If node has no attributes, behaviour is undefined. - //! Use first_attribute() to test if node has attributes. - void remove_last_attribute() - { - assert(first_attribute()); - xml_attribute *attribute = m_last_attribute; - if (attribute->m_prev_attribute) - { - attribute->m_prev_attribute->m_next_attribute = 0; - m_last_attribute = attribute->m_prev_attribute; - } - else - m_first_attribute = 0; - attribute->m_parent = 0; - } - - //! Removes specified attribute from node. - //! \param where Pointer to attribute to be removed. - void remove_attribute(xml_attribute *where) - { - assert(first_attribute() && where->parent() == this); - if (where == m_first_attribute) - remove_first_attribute(); - else if (where == m_last_attribute) - remove_last_attribute(); - else - { - where->m_prev_attribute->m_next_attribute = where->m_next_attribute; - where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; - where->m_parent = 0; - } - } - - //! Removes all attributes of node. - void remove_all_attributes() - { - for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) - attribute->m_parent = 0; - m_first_attribute = 0; - } - - private: - - /////////////////////////////////////////////////////////////////////////// - // Restrictions - - // No copying - xml_node(const xml_node &); - void operator =(const xml_node &); - - /////////////////////////////////////////////////////////////////////////// - // Data members - - // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. - // This is required for maximum performance, as it allows the parser to omit initialization of - // unneded/redundant values. - // - // The rules are as follows: - // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively - // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage - // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage - - node_type m_type; // Type of node; always valid - xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid - xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero - xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid - xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero - xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero - xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero - - }; - - /////////////////////////////////////////////////////////////////////////// - // XML document - - //! This class represents root of the DOM hierarchy. - //! It is also an xml_node and a memory_pool through public inheritance. - //! Use parse() function to build a DOM tree from a zero-terminated XML text string. - //! parse() function allocates memory for nodes and attributes by using functions of xml_document, - //! which are inherited from memory_pool. - //! To access root node of the document, use the document itself, as if it was an xml_node. - //! \param Ch Character type to use. - template - class xml_document: public xml_node, public memory_pool - { - - public: - - //! Constructs empty XML document - xml_document() - : xml_node(node_document) - { - } - - //! Parses zero-terminated XML string according to given flags. - //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. - //! The string must persist for the lifetime of the document. - //! In case of error, rapidxml::parse_error exception will be thrown. - //!

- //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. - //! Make sure that data is zero-terminated. - //!

- //! Document can be parsed into multiple times. - //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. - //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. - template - void parse(Ch *text) - { - assert(text); - - // Remove current contents - this->remove_all_nodes(); - this->remove_all_attributes(); - - // Parse BOM, if any - parse_bom(text); - - // Parse children - while (1) - { - // Skip whitespace before node - skip(text); - if (*text == 0) - break; - - // Parse and append new child - if (*text == Ch('<')) - { - ++text; // Skip '<' - if (xml_node *node = parse_node(text)) - this->append_node(node); - } - else - RAPIDXML_PARSE_ERROR("expected <", text); - } - - } - - //! Clears the document by deleting all nodes and clearing the memory pool. - //! All nodes owned by document pool are destroyed. - void clear() - { - this->remove_all_nodes(); - this->remove_all_attributes(); - memory_pool::clear(); - } - - private: - - /////////////////////////////////////////////////////////////////////// - // Internal character utility functions - - // Detect whitespace character - struct whitespace_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; - } - }; - - // Detect node name character - struct node_name_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; - } - }; - - // Detect attribute name character - struct attribute_name_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; - } - }; - - // Detect text character (PCDATA) - struct text_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; - } - }; - - // Detect text character (PCDATA) that does not require processing - struct text_pure_no_ws_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; - } - }; - - // Detect text character (PCDATA) that does not require processing - struct text_pure_with_ws_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; - } - }; - - // Detect attribute value character - template - struct attribute_value_pred - { - static unsigned char test(Ch ch) - { - if (Quote == Ch('\'')) - return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; - if (Quote == Ch('\"')) - return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; - return 0; // Should never be executed, to avoid warnings on Comeau - } - }; - - // Detect attribute value character - template - struct attribute_value_pure_pred - { - static unsigned char test(Ch ch) - { - if (Quote == Ch('\'')) - return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; - if (Quote == Ch('\"')) - return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; - return 0; // Should never be executed, to avoid warnings on Comeau - } - }; - - // Insert coded character, using UTF8 or 8-bit ASCII - template - static void insert_coded_character(Ch *&text, unsigned long code) - { - if (Flags & parse_no_utf8) - { - // Insert 8-bit ASCII character - // Todo: possibly verify that code is less than 256 and use replacement char otherwise? - text[0] = static_cast(code); - text += 1; - } - else - { - // Insert UTF8 sequence - if (code < 0x80) // 1 byte sequence - { - text[0] = static_cast(code); - text += 1; - } - else if (code < 0x800) // 2 byte sequence - { - text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[0] = static_cast(code | 0xC0); - text += 2; - } - else if (code < 0x10000) // 3 byte sequence - { - text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[0] = static_cast(code | 0xE0); - text += 3; - } - else if (code < 0x110000) // 4 byte sequence - { - text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[0] = static_cast(code | 0xF0); - text += 4; - } - else // Invalid, only codes up to 0x10FFFF are allowed in Unicode - { - RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); - } - } - } - - // Skip characters until predicate evaluates to true - template - static void skip(Ch *&text) - { - Ch *tmp = text; - while (StopPred::test(*tmp)) - ++tmp; - text = tmp; - } - - // Skip characters until predicate evaluates to true while doing the following: - // - replacing XML character entity references with proper characters (' & " < > &#...;) - // - condensing whitespace sequences to single space character - template - static Ch *skip_and_expand_character_refs(Ch *&text) - { - // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip - if (Flags & parse_no_entity_translation && - !(Flags & parse_normalize_whitespace) && - !(Flags & parse_trim_whitespace)) - { - skip(text); - return text; - } - - // Use simple skip until first modification is detected - skip(text); - - // Use translation skip - Ch *src = text; - Ch *dest = src; - while (StopPred::test(*src)) - { - // If entity translation is enabled - if (!(Flags & parse_no_entity_translation)) - { - // Test if replacement is needed - if (src[0] == Ch('&')) - { - switch (src[1]) - { - - // & ' - case Ch('a'): - if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) - { - *dest = Ch('&'); - ++dest; - src += 5; - continue; - } - if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) - { - *dest = Ch('\''); - ++dest; - src += 6; - continue; - } - break; - - // " - case Ch('q'): - if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) - { - *dest = Ch('"'); - ++dest; - src += 6; - continue; - } - break; - - // > - case Ch('g'): - if (src[2] == Ch('t') && src[3] == Ch(';')) - { - *dest = Ch('>'); - ++dest; - src += 4; - continue; - } - break; - - // < - case Ch('l'): - if (src[2] == Ch('t') && src[3] == Ch(';')) - { - *dest = Ch('<'); - ++dest; - src += 4; - continue; - } - break; - - // &#...; - assumes ASCII - case Ch('#'): - if (src[2] == Ch('x')) - { - unsigned long code = 0; - src += 3; // Skip &#x - while (1) - { - unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; - if (digit == 0xFF) - break; - code = code * 16 + digit; - ++src; - } - insert_coded_character(dest, code); // Put character in output - } - else - { - unsigned long code = 0; - src += 2; // Skip &# - while (1) - { - unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; - if (digit == 0xFF) - break; - code = code * 10 + digit; - ++src; - } - insert_coded_character(dest, code); // Put character in output - } - if (*src == Ch(';')) - ++src; - else - RAPIDXML_PARSE_ERROR("expected ;", src); - continue; - - // Something else - default: - // Ignore, just copy '&' verbatim - break; - - } - } - } - - // If whitespace condensing is enabled - if (Flags & parse_normalize_whitespace) - { - // Test if condensing is needed - if (whitespace_pred::test(*src)) - { - *dest = Ch(' '); ++dest; // Put single space in dest - ++src; // Skip first whitespace char - // Skip remaining whitespace chars - while (whitespace_pred::test(*src)) - ++src; - continue; - } - } - - // No replacement, only copy character - *dest++ = *src++; - - } - - // Return new end - text = src; - return dest; - - } - - /////////////////////////////////////////////////////////////////////// - // Internal parsing functions - - // Parse BOM, if any - template - void parse_bom(Ch *&text) - { - // UTF-8? - if (static_cast(text[0]) == 0xEF && - static_cast(text[1]) == 0xBB && - static_cast(text[2]) == 0xBF) - { - text += 3; // Skup utf-8 bom - } - } - - // Parse XML declaration ( - xml_node *parse_xml_declaration(Ch *&text) - { - // If parsing of declaration is disabled - if (!(Flags & parse_declaration_node)) - { - // Skip until end of declaration - while (text[0] != Ch('?') || text[1] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - text += 2; // Skip '?>' - return 0; - } - - // Create declaration - xml_node *declaration = this->allocate_node(node_declaration); - - // Skip whitespace before attributes or ?> - skip(text); - - // Parse declaration attributes - parse_node_attributes(text, declaration); - - // Skip ?> - if (text[0] != Ch('?') || text[1] != Ch('>')) - RAPIDXML_PARSE_ERROR("expected ?>", text); - text += 2; - - return declaration; - } - - // Parse XML comment (' - return 0; // Do not produce comment node - } - - // Remember value start - Ch *value = text; - - // Skip until end of comment - while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - - // Create comment node - xml_node *comment = this->allocate_node(node_comment); - comment->value(value, text - value); - - // Place zero terminator after comment value - if (!(Flags & parse_no_string_terminators)) - *text = Ch('\0'); - - text += 3; // Skip '-->' - return comment; - } - - // Parse DOCTYPE - template - xml_node *parse_doctype(Ch *&text) - { - // Remember value start - Ch *value = text; - - // Skip to > - while (*text != Ch('>')) - { - // Determine character type - switch (*text) - { - - // If '[' encountered, scan for matching ending ']' using naive algorithm with depth - // This works for all W3C test files except for 2 most wicked - case Ch('['): - { - ++text; // Skip '[' - int depth = 1; - while (depth > 0) - { - switch (*text) - { - case Ch('['): ++depth; break; - case Ch(']'): --depth; break; - case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); - } - ++text; - } - break; - } - - // Error on end of text - case Ch('\0'): - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - - // Other character, skip it - default: - ++text; - - } - } - - // If DOCTYPE nodes enabled - if (Flags & parse_doctype_node) - { - // Create a new doctype node - xml_node *doctype = this->allocate_node(node_doctype); - doctype->value(value, text - value); - - // Place zero terminator after value - if (!(Flags & parse_no_string_terminators)) - *text = Ch('\0'); - - text += 1; // skip '>' - return doctype; - } - else - { - text += 1; // skip '>' - return 0; - } - - } - - // Parse PI - template - xml_node *parse_pi(Ch *&text) - { - // If creation of PI nodes is enabled - if (Flags & parse_pi_nodes) - { - // Create pi node - xml_node *pi = this->allocate_node(node_pi); - - // Extract PI target name - Ch *name = text; - skip(text); - if (text == name) - RAPIDXML_PARSE_ERROR("expected PI target", text); - pi->name(name, text - name); - - // Skip whitespace between pi target and pi - skip(text); - - // Remember start of pi - Ch *value = text; - - // Skip to '?>' - while (text[0] != Ch('?') || text[1] != Ch('>')) - { - if (*text == Ch('\0')) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - - // Set pi value (verbatim, no entity expansion or whitespace normalization) - pi->value(value, text - value); - - // Place zero terminator after name and value - if (!(Flags & parse_no_string_terminators)) - { - pi->name()[pi->name_size()] = Ch('\0'); - pi->value()[pi->value_size()] = Ch('\0'); - } - - text += 2; // Skip '?>' - return pi; - } - else - { - // Skip to '?>' - while (text[0] != Ch('?') || text[1] != Ch('>')) - { - if (*text == Ch('\0')) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - text += 2; // Skip '?>' - return 0; - } - } - - // Parse and append data - // Return character that ends data. - // This is necessary because this character might have been overwritten by a terminating 0 - template - Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) - { - // Backup to contents start if whitespace trimming is disabled - if (!(Flags & parse_trim_whitespace)) - text = contents_start; - - // Skip until end of data - Ch *value = text, *end; - if (Flags & parse_normalize_whitespace) - end = skip_and_expand_character_refs(text); - else - end = skip_and_expand_character_refs(text); - - // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > - if (Flags & parse_trim_whitespace) - { - if (Flags & parse_normalize_whitespace) - { - // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end - if (*(end - 1) == Ch(' ')) - --end; - } - else - { - // Backup until non-whitespace character is found - while (whitespace_pred::test(*(end - 1))) - --end; - } - } - - // If characters are still left between end and value (this test is only necessary if normalization is enabled) - // Create new data node - if (!(Flags & parse_no_data_nodes)) - { - xml_node *data = this->allocate_node(node_data); - data->value(value, end - value); - node->append_node(data); - } - - // Add data to parent node if no data exists yet - if (!(Flags & parse_no_element_values)) - if (*node->value() == Ch('\0')) - node->value(value, end - value); - - // Place zero terminator after value - if (!(Flags & parse_no_string_terminators)) - { - Ch ch = *text; - *end = Ch('\0'); - return ch; // Return character that ends data; this is required because zero terminator overwritten it - } - - // Return character that ends data - return *text; - } - - // Parse CDATA - template - xml_node *parse_cdata(Ch *&text) - { - // If CDATA is disabled - if (Flags & parse_no_data_nodes) - { - // Skip until end of cdata - while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - text += 3; // Skip ]]> - return 0; // Do not produce CDATA node - } - - // Skip until end of cdata - Ch *value = text; - while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - - // Create new cdata node - xml_node *cdata = this->allocate_node(node_cdata); - cdata->value(value, text - value); - - // Place zero terminator after value - if (!(Flags & parse_no_string_terminators)) - *text = Ch('\0'); - - text += 3; // Skip ]]> - return cdata; - } - - // Parse element node - template - xml_node *parse_element(Ch *&text) - { - // Create element node - xml_node *element = this->allocate_node(node_element); - - // Extract element name - Ch *name = text; - skip(text); - if (text == name) - RAPIDXML_PARSE_ERROR("expected element name", text); - element->name(name, text - name); - - // Skip whitespace between element name and attributes or > - skip(text); - - // Parse attributes, if any - parse_node_attributes(text, element); - - // Determine ending type - if (*text == Ch('>')) - { - ++text; - parse_node_contents(text, element); - } - else if (*text == Ch('/')) - { - ++text; - if (*text != Ch('>')) - RAPIDXML_PARSE_ERROR("expected >", text); - ++text; - } - else - RAPIDXML_PARSE_ERROR("expected >", text); - - // Place zero terminator after name - if (!(Flags & parse_no_string_terminators)) - element->name()[element->name_size()] = Ch('\0'); - - // Return parsed element - return element; - } - - // Determine node type, and parse it - template - xml_node *parse_node(Ch *&text) - { - // Parse proper node type - switch (text[0]) - { - - // <... - default: - // Parse and append element node - return parse_element(text); - - // (text); - } - else - { - // Parse PI - return parse_pi(text); - } - - // (text); - } - break; - - // (text); - } - break; - - // (text); - } - - } // switch - - // Attempt to skip other, unrecognized node types starting with ')) - { - if (*text == 0) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - ++text; // Skip '>' - return 0; // No node recognized - - } - } - - // Parse contents of the node - children, data etc. - template - void parse_node_contents(Ch *&text, xml_node *node) - { - // For all children and text - while (1) - { - // Skip whitespace between > and node contents - Ch *contents_start = text; // Store start of node contents before whitespace is skipped - skip(text); - Ch next_char = *text; - - // After data nodes, instead of continuing the loop, control jumps here. - // This is because zero termination inside parse_and_append_data() function - // would wreak havoc with the above code. - // Also, skipping whitespace after data nodes is unnecessary. - after_data_node: - - // Determine what comes next: node closing, child node, data node, or 0? - switch (next_char) - { - - // Node closing or child node - case Ch('<'): - if (text[1] == Ch('/')) - { - // Node closing - text += 2; // Skip '(text); - if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) - RAPIDXML_PARSE_ERROR("invalid closing tag name", text); - } - else - { - // No validation, just skip name - skip(text); - } - // Skip remaining whitespace after node name - skip(text); - if (*text != Ch('>')) - RAPIDXML_PARSE_ERROR("expected >", text); - ++text; // Skip '>' - return; // Node closed, finished parsing contents - } - else - { - // Child node - ++text; // Skip '<' - if (xml_node *child = parse_node(text)) - node->append_node(child); - } - break; - - // End of data - error - case Ch('\0'): - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - - // Data node - default: - next_char = parse_and_append_data(node, text, contents_start); - goto after_data_node; // Bypass regular processing after data nodes - - } - } - } - - // Parse XML attributes of the node - template - void parse_node_attributes(Ch *&text, xml_node *node) - { - // For all attributes - while (attribute_name_pred::test(*text)) - { - // Extract attribute name - Ch *name = text; - ++text; // Skip first character of attribute name - skip(text); - if (text == name) - RAPIDXML_PARSE_ERROR("expected attribute name", name); - - // Create new attribute - xml_attribute *attribute = this->allocate_attribute(); - attribute->name(name, text - name); - node->append_attribute(attribute); - - // Skip whitespace after attribute name - skip(text); - - // Skip = - if (*text != Ch('=')) - RAPIDXML_PARSE_ERROR("expected =", text); - ++text; - - // Add terminating zero after name - if (!(Flags & parse_no_string_terminators)) - attribute->name()[attribute->name_size()] = 0; - - // Skip whitespace after = - skip(text); - - // Skip quote and remember if it was ' or " - Ch quote = *text; - if (quote != Ch('\'') && quote != Ch('"')) - RAPIDXML_PARSE_ERROR("expected ' or \"", text); - ++text; - - // Extract attribute value and expand char refs in it - Ch *value = text, *end; - const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes - if (quote == Ch('\'')) - end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); - else - end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); - - // Set attribute value - attribute->value(value, end - value); - - // Make sure that end quote is present - if (*text != quote) - RAPIDXML_PARSE_ERROR("expected ' or \"", text); - ++text; // Skip quote - - // Add terminating zero after value - if (!(Flags & parse_no_string_terminators)) - attribute->value()[attribute->value_size()] = 0; - - // Skip whitespace after attribute value - skip(text); - } - } - - }; - - //! \cond internal - namespace internal - { - - // Whitespace (space \n \r \t) - template - const unsigned char lookup_tables::lookup_whitespace[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F - }; - - // Node name (anything but space \n \r \t / > ? \0) - template - const unsigned char lookup_tables::lookup_node_name[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Text (i.e. PCDATA) (anything but < \0) - template - const unsigned char lookup_tables::lookup_text[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled - // (anything but < \0 &) - template - const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled - // (anything but < \0 & space \n \r \t) - template - const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute name (anything but space \n \r \t / < > = ? ! \0) - template - const unsigned char lookup_tables::lookup_attribute_name[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with single quote (anything but ' \0) - template - const unsigned char lookup_tables::lookup_attribute_data_1[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with single quote that does not require processing (anything but ' \0 &) - template - const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with double quote (anything but " \0) - template - const unsigned char lookup_tables::lookup_attribute_data_2[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with double quote that does not require processing (anything but " \0 &) - template - const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Digits (dec and hex, 255 denotes end of numeric character reference) - template - const unsigned char lookup_tables::lookup_digits[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 - 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 - 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F - }; - - // Upper case conversion - template - const unsigned char lookup_tables::lookup_upcase[256] = - { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 - 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F - }; - } - //! \endcond - -} - -// Undefine internal macros -#undef RAPIDXML_PARSE_ERROR - -// On MSVC, restore warnings state -#ifdef _MSC_VER - #pragma warning(pop) -#endif - -#endif diff --git a/modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp b/modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp deleted file mode 100644 index 52ebc298aa..0000000000 --- a/modules/skybrowser/rapidxmlparser/rapidxml_iterators.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED -#define RAPIDXML_ITERATORS_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml_iterators.hpp This file contains rapidxml iterators - -#include "rapidxml.hpp" - -namespace rapidxml -{ - - //! Iterator of child nodes of xml_node - template - class node_iterator - { - - public: - - typedef typename xml_node value_type; - typedef typename xml_node &reference; - typedef typename xml_node *pointer; - typedef std::ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - node_iterator() - : m_node(0) - { - } - - node_iterator(xml_node *node) - : m_node(node->first_node()) - { - } - - reference operator *() const - { - assert(m_node); - return *m_node; - } - - pointer operator->() const - { - assert(m_node); - return m_node; - } - - node_iterator& operator++() - { - assert(m_node); - m_node = m_node->next_sibling(); - return *this; - } - - node_iterator operator++(int) - { - node_iterator tmp = *this; - ++this; - return tmp; - } - - node_iterator& operator--() - { - assert(m_node && m_node->previous_sibling()); - m_node = m_node->previous_sibling(); - return *this; - } - - node_iterator operator--(int) - { - node_iterator tmp = *this; - ++this; - return tmp; - } - - bool operator ==(const node_iterator &rhs) - { - return m_node == rhs.m_node; - } - - bool operator !=(const node_iterator &rhs) - { - return m_node != rhs.m_node; - } - - private: - - xml_node *m_node; - - }; - - //! Iterator of child attributes of xml_node - template - class attribute_iterator - { - - public: - - typedef typename xml_attribute value_type; - typedef typename xml_attribute &reference; - typedef typename xml_attribute *pointer; - typedef std::ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - attribute_iterator() - : m_attribute(0) - { - } - - attribute_iterator(xml_node *node) - : m_attribute(node->first_attribute()) - { - } - - reference operator *() const - { - assert(m_attribute); - return *m_attribute; - } - - pointer operator->() const - { - assert(m_attribute); - return m_attribute; - } - - attribute_iterator& operator++() - { - assert(m_attribute); - m_attribute = m_attribute->next_attribute(); - return *this; - } - - attribute_iterator operator++(int) - { - attribute_iterator tmp = *this; - ++this; - return tmp; - } - - attribute_iterator& operator--() - { - assert(m_attribute && m_attribute->previous_attribute()); - m_attribute = m_attribute->previous_attribute(); - return *this; - } - - attribute_iterator operator--(int) - { - attribute_iterator tmp = *this; - ++this; - return tmp; - } - - bool operator ==(const attribute_iterator &rhs) - { - return m_attribute == rhs.m_attribute; - } - - bool operator !=(const attribute_iterator &rhs) - { - return m_attribute != rhs.m_attribute; - } - - private: - - xml_attribute *m_attribute; - - }; - -} - -#endif diff --git a/modules/skybrowser/rapidxmlparser/rapidxml_print.hpp b/modules/skybrowser/rapidxmlparser/rapidxml_print.hpp deleted file mode 100644 index 0ae2b14faa..0000000000 --- a/modules/skybrowser/rapidxmlparser/rapidxml_print.hpp +++ /dev/null @@ -1,421 +0,0 @@ -#ifndef RAPIDXML_PRINT_HPP_INCLUDED -#define RAPIDXML_PRINT_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml_print.hpp This file contains rapidxml printer implementation - -#include "rapidxml.hpp" - -// Only include streams if not disabled -#ifndef RAPIDXML_NO_STREAMS - #include - #include -#endif - -namespace rapidxml -{ - - /////////////////////////////////////////////////////////////////////// - // Printing flags - - const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. - - /////////////////////////////////////////////////////////////////////// - // Internal - - //! \cond internal - namespace internal - { - - /////////////////////////////////////////////////////////////////////////// - // Internal character operations - - // Copy characters from given range to given output iterator - template - inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) - { - while (begin != end) - *out++ = *begin++; - return out; - } - - // Copy characters from given range to given output iterator and expand - // characters into references (< > ' " &) - template - inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) - { - while (begin != end) - { - if (*begin == noexpand) - { - *out++ = *begin; // No expansion, copy character - } - else - { - switch (*begin) - { - case Ch('<'): - *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); - break; - case Ch('>'): - *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); - break; - case Ch('\''): - *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); - break; - case Ch('"'): - *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); - break; - case Ch('&'): - *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); - break; - default: - *out++ = *begin; // No expansion, copy character - } - } - ++begin; // Step to next character - } - return out; - } - - // Fill given output iterator with repetitions of the same character - template - inline OutIt fill_chars(OutIt out, int n, Ch ch) - { - for (int i = 0; i < n; ++i) - *out++ = ch; - return out; - } - - // Find character - template - inline bool find_char(const Ch *begin, const Ch *end) - { - while (begin != end) - if (*begin++ == ch) - return true; - return false; - } - - /////////////////////////////////////////////////////////////////////////// - // Internal printing operations - - // Print node - template - inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) - { - // Print proper node type - switch (node->type()) - { - - // Document - case node_document: - out = print_children(out, node, flags, indent); - break; - - // Element - case node_element: - out = print_element_node(out, node, flags, indent); - break; - - // Data - case node_data: - out = print_data_node(out, node, flags, indent); - break; - - // CDATA - case node_cdata: - out = print_cdata_node(out, node, flags, indent); - break; - - // Declaration - case node_declaration: - out = print_declaration_node(out, node, flags, indent); - break; - - // Comment - case node_comment: - out = print_comment_node(out, node, flags, indent); - break; - - // Doctype - case node_doctype: - out = print_doctype_node(out, node, flags, indent); - break; - - // Pi - case node_pi: - out = print_pi_node(out, node, flags, indent); - break; - - // Unknown - default: - assert(0); - break; - } - - // If indenting not disabled, add line break after node - if (!(flags & print_no_indenting)) - *out = Ch('\n'), ++out; - - // Return modified iterator - return out; - } - - // Print children of the node - template - inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) - { - for (xml_node *child = node->first_node(); child; child = child->next_sibling()) - out = print_node(out, child, flags, indent); - return out; - } - - // Print attributes of the node - template - inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) - { - for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) - { - if (attribute->name() && attribute->value()) - { - // Print attribute name - *out = Ch(' '), ++out; - out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); - *out = Ch('='), ++out; - // Print attribute value using appropriate quote type - if (find_char(attribute->value(), attribute->value() + attribute->value_size())) - { - *out = Ch('\''), ++out; - out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); - *out = Ch('\''), ++out; - } - else - { - *out = Ch('"'), ++out; - out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); - *out = Ch('"'), ++out; - } - } - } - return out; - } - - // Print data node - template - inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_data); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); - return out; - } - - // Print data node - template - inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_cdata); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'); ++out; - *out = Ch('!'); ++out; - *out = Ch('['); ++out; - *out = Ch('C'); ++out; - *out = Ch('D'); ++out; - *out = Ch('A'); ++out; - *out = Ch('T'); ++out; - *out = Ch('A'); ++out; - *out = Ch('['); ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch(']'); ++out; - *out = Ch(']'); ++out; - *out = Ch('>'); ++out; - return out; - } - - // Print element node - template - inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_element); - - // Print element name and attributes, if any - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - out = copy_chars(node->name(), node->name() + node->name_size(), out); - out = print_attributes(out, node, flags); - - // If node is childless - if (node->value_size() == 0 && !node->first_node()) - { - // Print childless node tag ending - *out = Ch('/'), ++out; - *out = Ch('>'), ++out; - } - else - { - // Print normal node tag ending - *out = Ch('>'), ++out; - - // Test if node contains a single data node only (and no other nodes) - xml_node *child = node->first_node(); - if (!child) - { - // If node has no children, only print its value without indenting - out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); - } - else if (child->next_sibling() == 0 && child->type() == node_data) - { - // If node has a sole data child, only print its value without indenting - out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); - } - else - { - // Print all children with full indenting - if (!(flags & print_no_indenting)) - *out = Ch('\n'), ++out; - out = print_children(out, node, flags, indent + 1); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - } - - // Print node end - *out = Ch('<'), ++out; - *out = Ch('/'), ++out; - out = copy_chars(node->name(), node->name() + node->name_size(), out); - *out = Ch('>'), ++out; - } - return out; - } - - // Print declaration node - template - inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) - { - // Print declaration start - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('?'), ++out; - *out = Ch('x'), ++out; - *out = Ch('m'), ++out; - *out = Ch('l'), ++out; - - // Print attributes - out = print_attributes(out, node, flags); - - // Print declaration end - *out = Ch('?'), ++out; - *out = Ch('>'), ++out; - - return out; - } - - // Print comment node - template - inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_comment); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('!'), ++out; - *out = Ch('-'), ++out; - *out = Ch('-'), ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch('-'), ++out; - *out = Ch('-'), ++out; - *out = Ch('>'), ++out; - return out; - } - - // Print doctype node - template - inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_doctype); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('!'), ++out; - *out = Ch('D'), ++out; - *out = Ch('O'), ++out; - *out = Ch('C'), ++out; - *out = Ch('T'), ++out; - *out = Ch('Y'), ++out; - *out = Ch('P'), ++out; - *out = Ch('E'), ++out; - *out = Ch(' '), ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch('>'), ++out; - return out; - } - - // Print pi node - template - inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_pi); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('?'), ++out; - out = copy_chars(node->name(), node->name() + node->name_size(), out); - *out = Ch(' '), ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch('?'), ++out; - *out = Ch('>'), ++out; - return out; - } - - } - //! \endcond - - /////////////////////////////////////////////////////////////////////////// - // Printing - - //! Prints XML to given output iterator. - //! \param out Output iterator to print to. - //! \param node Node to be printed. Pass xml_document to print entire document. - //! \param flags Flags controlling how XML is printed. - //! \return Output iterator pointing to position immediately after last character of printed text. - template - inline OutIt print(OutIt out, const xml_node &node, int flags = 0) - { - return internal::print_node(out, &node, flags, 0); - } - -#ifndef RAPIDXML_NO_STREAMS - - //! Prints XML to given output stream. - //! \param out Output stream to print to. - //! \param node Node to be printed. Pass xml_document to print entire document. - //! \param flags Flags controlling how XML is printed. - //! \return Output stream. - template - inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) - { - print(std::ostream_iterator(out), node, flags); - return out; - } - - //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. - //! \param out Output stream to print to. - //! \param node Node to be printed. - //! \return Output stream. - template - inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) - { - return print(out, node); - } - -#endif - -} - -#endif diff --git a/modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp b/modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp deleted file mode 100644 index 37c29535f4..0000000000 --- a/modules/skybrowser/rapidxmlparser/rapidxml_utils.hpp +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef RAPIDXML_UTILS_HPP_INCLUDED -#define RAPIDXML_UTILS_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful -//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. - -#include "rapidxml.hpp" -#include -#include -#include -#include - -namespace rapidxml -{ - - //! Represents data loaded from a file - template - class file - { - - public: - - //! Loads file into the memory. Data will be automatically destroyed by the destructor. - //! \param filename Filename to load. - file(const char *filename) - { - using namespace std; - - // Open stream - basic_ifstream stream(filename, ios::binary); - if (!stream) - throw runtime_error(string("cannot open file ") + filename); - stream.unsetf(ios::skipws); - - // Determine stream size - stream.seekg(0, ios::end); - size_t size = stream.tellg(); - stream.seekg(0); - - // Load data and add terminating 0 - m_data.resize(size + 1); - stream.read(&m_data.front(), static_cast(size)); - m_data[size] = 0; - } - - //! Loads file into the memory. Data will be automatically destroyed by the destructor - //! \param stream Stream to load from - file(std::basic_istream &stream) - { - using namespace std; - - // Load data and add terminating 0 - stream.unsetf(ios::skipws); - m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); - if (stream.fail() || stream.bad()) - throw runtime_error("error reading stream"); - m_data.push_back(0); - } - - //! Gets file data. - //! \return Pointer to data of file. - Ch *data() - { - return &m_data.front(); - } - - //! Gets file data. - //! \return Pointer to data of file. - const Ch *data() const - { - return &m_data.front(); - } - - //! Gets file data size. - //! \return Size of file data, in characters. - std::size_t size() const - { - return m_data.size(); - } - - private: - - std::vector m_data; // File data - - }; - - //! Counts children of node. Time complexity is O(n). - //! \return Number of children of node - template - inline std::size_t count_children(xml_node *node) - { - xml_node *child = node->first_node(); - std::size_t count = 0; - while (child) - { - ++count; - child = child->next_sibling(); - } - return count; - } - - //! Counts attributes of node. Time complexity is O(n). - //! \return Number of attributes of node - template - inline std::size_t count_attributes(xml_node *node) - { - xml_attribute *attr = node->first_attribute(); - std::size_t count = 0; - while (attr) - { - ++count; - attr = attr->next_attribute(); - } - return count; - } - -} - -#endif diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 8d14fc08e7..11a6af6ea1 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -23,9 +23,7 @@ ****************************************************************************************/ #include -#include // For parsing xml -#include // For parsing xml -#include // For parsing xml +#include //#include //#include @@ -48,7 +46,7 @@ #include #include // For downloading files from url #include - +#include // To iterate through files in directory namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -245,9 +243,13 @@ SkyBrowserModule::SkyBrowserModule() } ); } +SkyBrowserModule::~SkyBrowserModule() { + // Call destructor of all allocated xmls + xmls.clear(); +} void SkyBrowserModule::internalDeinitialize() { - + } @@ -290,75 +292,196 @@ ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } -void SkyBrowserModule::loadImages(std::string url, std::string fileDestination) { +bool SkyBrowserModule::downloadFile(std::string& url, std::string& fileDestination) { // Get the webpage and save to file - HttpRequest::RequestOptions opt{0}; + HttpRequest::RequestOptions opt{ 5 }; SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes); wtml_root.download(opt); - // Parse XML document - using namespace rapidxml; - rapidxml::file<> xmlFile(fileDestination.c_str()); // Default template is char - rapidxml::xml_document<> doc; - doc.parse<0>(xmlFile.data()); - - // Get child of node until we find the "Place" node - xml_node<>* place = getChildNode(doc.first_node(), "Place"); - - // Iterate through all the places and load as images - while (place) { - loadImage(place); - place = place->next_sibling(); - } - LINFO(images[55].thumbnailUrl); + return wtml_root.hasSucceeded(); } -int SkyBrowserModule::loadImage(rapidxml::xml_node<>* imgNode) { - ImageData image; - using namespace rapidxml; - // Get all attributes for the - for (xml_attribute<>* attr = imgNode->first_attribute(); attr; attr = attr->next_attribute()) - { - if (attr->name() == "RA") { - image.celestCoords.x = std::stof(attr->value()); +void SkyBrowserModule::loadWTMLCollectionsFromURL(std::string url, std::string fileName) { + // Get file + std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/") + fileName + ".aspx"; + if (!downloadFile(url, fileDestination)) { + LINFO("Couldn't download file " + url); + return; + } + // Parse to XML + using namespace tinyxml2; + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + doc->LoadFile(fileDestination.c_str()); + + XMLElement* root = doc->RootElement(); + XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); + // If there are no folders, or there are folder but without urls, stop recursion + if (!element || (element && !element->FindAttribute("Url"))) { + + imageUrls.push_back(url); + xmls.push_back(doc); + LINFO("Saving " + url); + + return; + } + // Iterate through all the folders + while (element && std::string(element->Value()) == "Folder") { + // Get all attributes for the + std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : ""; + std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : ""; + if (subUrl != "" && subName != "") { + loadWTMLCollectionsFromURL(subUrl, subName); } - else if (attr->name() == "DEC") { - image.celestCoords.y = std::stof(attr->value()); - } - else if (attr->name() == "Classification") { - image.name = attr->value(); + element = element->NextSiblingElement(); + } +} + +void SkyBrowserModule::loadWTMLCollectionsFromDirectory(std::string directory) { + + for (const auto& entry : std::filesystem::directory_iterator(directory)) { + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + std::cout << entry.path().u8string().c_str() << std::endl; + if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) { + xmls.push_back(doc); } } - xml_node<>* imageSet = getChildNode(imgNode, "ImageSet"); - if (!imageSet) return -1; - // Get all attributes for the - for (xml_attribute<>* attr = imageSet->first_attribute(); attr; attr = attr->next_attribute()) { - if (attr->name() == "Name") { - image.name = attr->value(); - break; - } +} + +std::ostream& operator<<(std::ostream& os, const ImageData& img) { + os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl; + os << "Thumbnail: " << img.thumbnailUrl << std::endl; + os << "Collection: " << img.collection << std::endl << std::endl; + return os; +} + + +int SkyBrowserModule::loadAllImagesFromXMLs() { + for(tinyxml2::XMLDocument* doc : xmls) { + tinyxml2::XMLElement* root = doc->FirstChildElement(); + std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; + loadImagesFromXML(root, collectionName); } - // The thumbnail is the last node so traverse backwards for speed - xml_node<>* imageSetChild = imageSet->last_node(); - while (imageSetChild) { - if (std::string(imageSetChild->name()) == "ThumbnailUrl") { - image.thumbnailUrl = imageSetChild->value(); - break; - } - imageSetChild = imageSetChild->previous_sibling(); + + for (ImageData img : images) { + std::cout << img; } + return images.size(); +} + +void SkyBrowserModule::printAllUrls() { + for (auto it = imageUrls.begin(); it != imageUrls.end(); it++) { + LINFO(*it); + } +} + +void SkyBrowserModule::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) { + // Get direct child of node called "Place" + using namespace tinyxml2; + XMLElement* folder = getChildNode(node->FirstChildElement(), "Folder"); + // Terminate recursion if no folders + if (!folder) { + // When we are at leaf folder + // Iterate through all the places and load as images + // Prefer places over Image Sets as they contain same info + XMLElement* place = getChildNode(node->FirstChildElement(), "Place"); + // No place found - look for images instead + if (!place) { + XMLElement* imageSet = getChildNode(node->FirstChildElement(), "ImageSet"); + while (imageSet) { + loadImageSet(imageSet, collectionName); + imageSet = imageSet->NextSiblingElement(); + } + } + // Place found - look through places + while (place) { + loadPlace(place, collectionName); + place = place->NextSiblingElement(); + } + } + else { + // Open all folders at same level + while (folder) { + std::string newCollectionName = collectionName + "/"; + if (folder->FindAttribute("Name")) { + newCollectionName += std::string(folder->FindAttribute("Name")->Value()); + } + loadImagesFromXML(folder, newCollectionName); + folder = folder->NextSiblingElement(); + } + } +} + +int SkyBrowserModule::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) { + // Only load "Sky" type images + if (std::string(place->FindAttribute("DataSetType")->Value()) != "Sky") + return - 1; + + std::string url = ""; + // If the place doesn't have a thumbnail url data attribute, + // Load the containing image set instead + if (!place->FindAttribute("Thumbnail")) { + // Traverse the children and look at all their first child to find ImageSet + tinyxml2::XMLElement* child = place->FirstChildElement(); + tinyxml2::XMLElement* imageSet = nullptr; + while (child) { + imageSet = getChildNode(child, "ImageSet"); + if (imageSet) break; + child = child->NextSiblingElement(); + } + // If the place doesn't contain an image, nothing to add + if (!imageSet) return -1; + + // Collect thumbnail url from ImageSet + url = getURLFromImageSet(imageSet); + if (url == "") return -1; + } + ImageData image; + // Get attributes for the image + image.name = place->FindAttribute("Name") ? place->FindAttribute("Name")->Value() : ""; + image.celestCoords.x = place->FindAttribute("RA") ? std::stof(place->FindAttribute("RA")->Value()) : 0.f; + image.celestCoords.y = place->FindAttribute("Dec") ? std::stof(place->FindAttribute("Dec")->Value()) : 0.f; + image.thumbnailUrl = url == "" ? place->FindAttribute("Thumbnail")->Value() : url; + image.collection = collectionName; + + images.push_back(image); + // Return index of image in vector + return images.size(); +} +int SkyBrowserModule::loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName) { + std::string type = imageSet->FindAttribute("DataSetType") ? imageSet->FindAttribute("DataSetType")->Value() : ""; + // Only load "Sky" type images + if (type != "Sky") + return - 1; + + ImageData image; + + // Get attributes for the image + image.name = imageSet->FindAttribute("Name") ? imageSet->FindAttribute("Name")->Value() : ""; + image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f; + image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f; + image.thumbnailUrl = getURLFromImageSet(imageSet); + image.collection = collectionName; + images.push_back(image); // Return index of image in vector return images.size(); } -rapidxml::xml_node<>* SkyBrowserModule::getChildNode(rapidxml::xml_node<>* node, std::string name) { - while (node && std::string(node->name()) != name) { - node = node->first_node(); +std::string SkyBrowserModule::getURLFromImageSet(tinyxml2::XMLElement* imageSet) { + // FInd the thumbnail image url + // The thumbnail is the last node so traverse backwards for speed + tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement("ThumbnailUrl"); + return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; +} + +tinyxml2::XMLElement* SkyBrowserModule::getChildNode(tinyxml2::XMLElement* node, std::string name) { + while (node && std::string(node->Name()) != name) { + node = node->FirstChildElement(); } return node; } + /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 1da3242818..ee7b79a138 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -25,9 +25,8 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ - #include -#include // For parsing xml +#include #include #include #include @@ -44,8 +43,7 @@ struct ImageData { std::string name; std::string thumbnailUrl; glm::vec2 celestCoords; - std::string classification; - float zoom; + std::string collection; }; class SkyBrowserModule : public OpenSpaceModule { @@ -53,10 +51,16 @@ public: constexpr static const char* Name = "SkyBrowser"; SkyBrowserModule(); - virtual ~SkyBrowserModule() = default; + virtual ~SkyBrowserModule(); glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); - void loadImages(std::string url, std::string fileDestination); + // Image downloading and xml parsing + bool downloadFile(std::string& url, std::string& fileDestination); + void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); + void loadWTMLCollectionsFromURL(std::string url, std::string fileName); + void loadWTMLCollectionsFromDirectory(std::string directory); + int loadAllImagesFromXMLs(); + void printAllUrls(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -64,8 +68,10 @@ public: protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; - int loadImage(rapidxml::xml_node<>* imgNode); - rapidxml::xml_node<>* getChildNode(rapidxml::xml_node<>* node, std::string name); + int loadPlace(tinyxml2::XMLElement* place, std::string collectionName); + int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName); + std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet); + tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); // Using snake case on these casting functions to make them similar to eg std::to_string ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr); ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr); @@ -88,6 +94,8 @@ protected: bool currentlyDraggingObject; std::vector images; + std::vector imageUrls; + std::vector xmls; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 5ee5d65616..dc0b5c6243 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -47,16 +47,21 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkyBrowserModule* module = global::moduleEngine->module(); - std::string url = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=vampfeeds"; - url = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=wise"; - std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/wise.aspx"); - module->loadImages(url, fileDestination); - + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + + module->loadWTMLCollectionsFromURL(root, "root"); + module->printAllUrls(); + LINFO(std::to_string( module->loadAllImagesFromXMLs())); + return 1; } int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); + SkyBrowserModule* module = global::moduleEngine->module(); + module->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); + module->printAllUrls(); + LINFO(std::to_string(module->loadAllImagesFromXMLs())); return 1; } diff --git a/modules/skybrowser/tinyxml2/tinyxml2.cpp b/modules/skybrowser/tinyxml2/tinyxml2.cpp new file mode 100644 index 0000000000..925cffd28c --- /dev/null +++ b/modules/skybrowser/tinyxml2/tinyxml2.cpp @@ -0,0 +1,2986 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +#else +# include +# include +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + +#if defined(_WIN64) + #define TIXML_FSEEK _fseeki64 + #define TIXML_FTELL _ftelli64 +#elif defined(__APPLE__) || defined(__FreeBSD__) + #define TIXML_FSEEK fseeko + #define TIXML_FTELL ftello +#elif defined(__unix__) && defined(__x86_64__) + #define TIXML_FSEEK fseeko64 + #define TIXML_FTELL ftello64 +#else + #define TIXML_FSEEK fseek + #define TIXML_FTELL ftell +#endif + + +static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other != 0 ); + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( endTag && *endTag ); + TIXMLASSERT(curLineNumPtr); + + char* start = p; + const char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } else if (*p == '\n') { + ++(*curLineNumPtr); + } + ++p; + TIXMLASSERT( p ); + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start, 0 ); + + if ( *_start ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p, 0 ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + const char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::writeBoolTrue = "true"; +const char* XMLUtil::writeBoolFalse = "false"; + +void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) +{ + static const char* defTrue = "true"; + static const char* defFalse = "false"; + + writeBoolTrue = (writeTrue) ? writeTrue : defTrue; + writeBoolFalse = (writeFalse) ? writeFalse : defFalse; +} + + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs are annotated with carefully designed comments + // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc + switch (*length) { + case 4: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 3: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 2: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 1: + --output; + *output = static_cast(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit < 16 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit < 10 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) +{ + // horrible syntax trick to make the compiler happy about %lld + TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); +} + +void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) +{ + // horrible syntax trick to make the compiler happy about %llu + TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v); +} + +bool XMLUtil::ToInt(const char* str, int* value) +{ + if (IsPrefixHex(str)) { + unsigned v; + if (TIXML_SSCANF(str, "%x", &v) == 1) { + *value = static_cast(v); + return true; + } + } + else { + if (TIXML_SSCANF(str, "%d", value) == 1) { + return true; + } + } + return false; +} + +bool XMLUtil::ToUnsigned(const char* str, unsigned* value) +{ + if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; + static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; + + for (int i = 0; TRUE_VALS[i]; ++i) { + if (StringEqual(str, TRUE_VALS[i])) { + *value = true; + return true; + } + } + for (int i = 0; FALSE_VALS[i]; ++i) { + if (StringEqual(str, FALSE_VALS[i])) { + *value = false; + return true; + } + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToInt64(const char* str, int64_t* value) +{ + if (IsPrefixHex(str)) { + unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llx + if (TIXML_SSCANF(str, "%llx", &v) == 1) { + *value = static_cast(v); + return true; + } + } + else { + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = static_cast(v); + return true; + } + } + return false; +} + + +bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { + unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu + if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) { + *value = (uint64_t)v; + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + int const startLine = _parseCurLineNum; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + XMLText* text = CreateUnlinkedNode( _textPool ); + returnNode = text; + returnNode->_parseLineNum = _parseCurLineNum; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _elementPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } + else { + returnNode = CreateUnlinkedNode( _textPool ); + returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _value(), + _parseLineNum( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _userData( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Edge case: XMLDocuments don't have a Value. Return null. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + +XMLNode* XMLNode::DeepClone(XMLDocument* target) const +{ + XMLNode* clone = this->ShallowClone(target); + if (!clone) return 0; + + for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { + XMLNode* childClone = child->DeepClone(target); + TIXMLASSERT(childClone); + clone->InsertEndChild(childClone); + } + return clone; +} + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + DeleteChild( _firstChild ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_next = 0; + child->_prev = 0; + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + TIXMLASSERT(node->_prev == 0); + TIXMLASSERT(node->_next == 0); + TIXMLASSERT(node->_parent == 0); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + if ( afterThis == addThis ) { + // Current state: BeforeThis -> AddThis -> OneAfterAddThis + // Now AddThis must disappear from it's location and then + // reappear between BeforeThis and OneAfterAddThis. + // So just leave it where it is. + return addThis; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // + // + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + XMLDocument::DepthTracker tracker(_document); + if (_document->Error()) + return 0; + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + TIXMLASSERT( p ); + if ( node == 0 ) { + break; + } + + const int initialLineNum = node->_parseLineNum; + + StrPair endTag; + p = node->ParseDeep( p, &endTag, curLineNumPtr ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); + } + break; + } + + const XMLDeclaration* const decl = node->ToDeclaration(); + if ( decl ) { + // Declarations are only allowed at document level + // + // Multiple declarations are allowed but all declarations + // must occur before anything else. + // + // Optimized due to a security test case. If the first node is + // a declaration, and the last node is a declaration, then only + // declarations have so far been added. + bool wellLocated = false; + + if (ToDocument()) { + if (FirstChild()) { + wellLocated = + FirstChild() && + FirstChild()->ToDeclaration() && + LastChild() && + LastChild()->ToDeclaration(); + } + else { + wellLocated = true; + } + } + if ( !wellLocated ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); + DeleteNode( node ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEndTag ) { + ele->_value.TransferTo( parentEndTag ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +/*static*/ void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + TIXMLASSERT(node->_document); + if (!node->ToDocument()) { + node->_document->MarkInUse(node); + } + + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if (insertThis->_parent) { + insertThis->_parent->Unlink( insertThis ); + } + else { + insertThis->_document->MarkInUse(insertThis); + insertThis->_memPool->SetTracked(); + } +} + +const XMLElement* XMLNode::ToElementWithName( const char* name ) const +{ + const XMLElement* element = this->ToElement(); + if ( element == 0 ) { + return 0; + } + if ( name == 0 ) { + return element; + } + if ( XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + return 0; +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags, curLineNumPtr ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Comment parses as text. + p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Declaration parses as text. + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Unknown parses as text. + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + const char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryInt64Value(int64_t* value) const +{ + if (XMLUtil::ToInt64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const +{ + if(XMLUtil::ToUnsigned64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + +void XMLAttribute::SetAttribute(uint64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( OPEN ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + +int XMLElement::IntAttribute(const char* name, int defaultValue) const +{ + int i = defaultValue; + QueryIntAttribute(name, &i); + return i; +} + +unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedAttribute(name, &i); + return i; +} + +int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Attribute(name, &i); + return i; +} + +uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const +{ + uint64_t i = defaultValue; + QueryUnsigned64Attribute(name, &i); + return i; +} + +bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolAttribute(name, &b); + return b; +} + +double XMLElement::DoubleAttribute(const char* name, double defaultValue) const +{ + double d = defaultValue; + QueryDoubleAttribute(name, &d); + return d; +} + +float XMLElement::FloatAttribute(const char* name, float defaultValue) const +{ + float f = defaultValue; + QueryFloatAttribute(name, &f); + return f; +} + +const char* XMLElement::GetText() const +{ + /* skip comment node */ + const XMLNode* node = FirstChild(); + while (node) { + if (node->ToComment()) { + node = node->NextSibling(); + continue; + } + break; + } + + if ( node && node->ToText() ) { + return node->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + +void XMLElement::SetText(uint64_t v) { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryInt64Text(int64_t* ival) const +{ + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const +{ + if(FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if(XMLUtil::ToUnsigned64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + +int XMLElement::IntText(int defaultValue) const +{ + int i = defaultValue; + QueryIntText(&i); + return i; +} + +unsigned XMLElement::UnsignedText(unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedText(&i); + return i; +} + +int64_t XMLElement::Int64Text(int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Text(&i); + return i; +} + +uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const +{ + uint64_t i = defaultValue; + QueryUnsigned64Text(&i); + return i; +} + +bool XMLElement::BoolText(bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolText(&b); + return b; +} + +double XMLElement::DoubleText(double defaultValue) const +{ + double d = defaultValue; + QueryDoubleText(&d); + return d; +} + +float XMLElement::FloatText(float defaultValue) const +{ + float f = defaultValue; + QueryFloatText(&f); + return f; +} + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + if ( last ) { + TIXMLASSERT( last->_next == 0 ); + last->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + attrib->SetName( name ); + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) +{ + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { + XMLAttribute* attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + attrib->_parseLineNum = _document->_parseCurLineNum; + + const int attrLineNum = attrib->_parseLineNum; + + p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + TIXMLASSERT( prevAttribute->_next == 0 ); + prevAttribute->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +XMLAttribute* XMLElement::CreateAttribute() +{ + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + TIXMLASSERT( attrib ); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + return attrib; +} + + +XMLElement* XMLElement::InsertNewChildElement(const char* name) +{ + XMLElement* node = _document->NewElement(name); + return InsertEndChild(node) ? node : 0; +} + +XMLComment* XMLElement::InsertNewComment(const char* comment) +{ + XMLComment* node = _document->NewComment(comment); + return InsertEndChild(node) ? node : 0; +} + +XMLText* XMLElement::InsertNewText(const char* text) +{ + XMLText* node = _document->NewText(text); + return InsertEndChild(node) ? node : 0; +} + +XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) +{ + XMLDeclaration* node = _document->NewDeclaration(text); + return InsertEndChild(node) ? node : 0; +} + +XMLUnknown* XMLElement::InsertNewUnknown(const char* text) +{ + XMLUnknown* node = _document->NewUnknown(text); + return InsertEndChild(node) ? node : 0; +} + + + +// +// +// foobar +// +char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p, curLineNumPtr ); + if ( !p || !*p || _closingType != OPEN ) { + return p; + } + + p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE", + "XML_ELEMENT_DEPTH_EXCEEDED" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID(XML_SUCCESS), + _whitespaceMode( whitespaceMode ), + _errorStr(), + _errorLineNum( 0 ), + _charBuffer( 0 ), + _parseCurLineNum( 0 ), + _parsingDepth(0), + _unlinked(), + _elementPool(), + _attributePool(), + _textPool(), + _commentPool() +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::MarkInUse(const XMLNode* const node) +{ + TIXMLASSERT(node); + TIXMLASSERT(node->_parent == 0); + + for (int i = 0; i < _unlinked.Size(); ++i) { + if (node == _unlinked[i]) { + _unlinked.SwapRemove(i); + break; + } + } +} + +void XMLDocument::Clear() +{ + DeleteChildren(); + while( _unlinked.Size()) { + DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. + } + +#ifdef TINYXML2_DEBUG + const bool hadError = Error(); +#endif + ClearError(); + + delete [] _charBuffer; + _charBuffer = 0; + _parsingDepth = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef TINYXML2_DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +void XMLDocument::DeepCopy(XMLDocument* target) const +{ + TIXMLASSERT(target); + if (target == this) { + return; // technically success - a no-op. + } + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } +} + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + XMLElement* ele = CreateUnlinkedNode( _elementPool ); + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + XMLComment* comment = CreateUnlinkedNode( _commentPool ); + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + XMLText* text = CreateUnlinkedNode( _textPool ); + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + XMLDeclaration* dec = CreateUnlinkedNode( _commentPool ); + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + XMLUnknown* unk = CreateUnlinkedNode( _commentPool ); + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + const errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + TIXML_FSEEK( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + TIXML_FSEEK( fp, 0, SEEK_END ); + + unsigned long long filelength; + { + const long long fileLengthSigned = TIXML_FTELL( fp ); + TIXML_FSEEK( fp, 0, SEEK_SET ); + if ( fileLengthSigned == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( fileLengthSigned >= 0 ); + filelength = static_cast(fileLengthSigned); + } + + const size_t maxSizeT = static_cast(-1); + // We'll do the comparison as an unsigned long long, because that's guaranteed to be at + // least 8 bytes, even on a 32-bit platform. + if ( filelength >= static_cast(maxSizeT) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = static_cast(filelength); + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[size+1]; + const size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + ClearError(); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == static_cast(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::ClearError() { + _errorID = XML_SUCCESS; + _errorLineNum = 0; + _errorStr.Reset(); +} + + +void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorLineNum = lineNum; + _errorStr.Reset(); + + const size_t BUFFER_SIZE = 1000; + char* buffer = new char[BUFFER_SIZE]; + + TIXMLASSERT(sizeof(error) <= sizeof(int)); + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); + + if (format) { + size_t len = strlen(buffer); + TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); + len = strlen(buffer); + + va_list va; + va_start(va, format); + TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); + va_end(va); + } + _errorStr.SetStr(buffer); + delete[] buffer; +} + + +/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) +{ + TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +const char* XMLDocument::ErrorStr() const +{ + return _errorStr.Empty() ? "" : _errorStr.GetStr(); +} + + +void XMLDocument::PrintError() const +{ + printf("%s\n", ErrorStr()); +} + +const char* XMLDocument::ErrorName() const +{ + return ErrorIDToName(_errorID); +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + _parseCurLineNum = 1; + _parseLineNum = 1; + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0, &_parseCurLineNum ); +} + +void XMLDocument::PushDepth() +{ + _parsingDepth++; + if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { + SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); + } +} + +void XMLDocument::PopDepth() +{ + TIXMLASSERT(_parsingDepth > 0); + --_parsingDepth; +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _stack(), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ), + _buffer() +{ + for( int i=0; i(entityValue); + TIXMLASSERT( flagIndex < ENTITY_RANGE ); + _entityFlag[flagIndex] = true; + } + _restrictedEntityFlag[static_cast('&')] = true; + _restrictedEntityFlag[static_cast('<')] = true; + _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::Write( const char* data, size_t size ) +{ + if ( _fp ) { + fwrite ( data , sizeof(char), size, _fp); + } + else { + char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. + memcpy( p, data, size ); + p[size] = 0; + } +} + + +void XMLPrinter::Putc( char ch ) +{ + if ( _fp ) { + fputc ( ch, _fp); + } + else { + char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. + p[0] = ch; + p[1] = 0; + } +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[static_cast(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); + Write( p, toPrint ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i(delta); + Write( p, toPrint ); + } + } + else { + Write( p ); + } +} + + +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) +{ + if ( writeBOM ) { + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; + Write( reinterpret_cast< const char* >( bom ) ); + } + if ( writeDec ) { + PushDeclaration( "xml version=\"1.0\"" ); + } +} + +void XMLPrinter::PrepareForNewNode( bool compactMode ) +{ + SealElementIfJustOpened(); + + if ( compactMode ) { + return; + } + + if ( _firstElement ) { + PrintSpace (_depth); + } else if ( _textDepth < 0) { + Putc( '\n' ); + PrintSpace( _depth ); + } + + _firstElement = false; +} + +void XMLPrinter::OpenElement( const char* name, bool compactMode ) +{ + PrepareForNewNode( compactMode ); + _stack.Push( name ); + + Write ( "<" ); + Write ( name ); + + _elementJustOpened = true; + ++_depth; +} + + +void XMLPrinter::PushAttribute( const char* name, const char* value ) +{ + TIXMLASSERT( _elementJustOpened ); + Putc ( ' ' ); + Write( name ); + Write( "=\"" ); + PrintString( value, false ); + Putc ( '\"' ); +} + + +void XMLPrinter::PushAttribute( const char* name, int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute(const char* name, int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + +void XMLPrinter::PushAttribute(const char* name, uint64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + +void XMLPrinter::PushAttribute( const char* name, bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::CloseElement( bool compactMode ) +{ + --_depth; + const char* name = _stack.Pop(); + + if ( _elementJustOpened ) { + Write( "/>" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + Write ( "" ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Putc( '\n' ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Putc( '>' ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Write( "" ); + } + else { + PrintString( text, true ); + } +} + + +void XMLPrinter::PushText( int64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( uint64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); +} + + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + PrepareForNewNode( _compactMode ); + + Write( "" ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + PrepareForNewNode( _compactMode ); + + Write( "" ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + PrepareForNewNode( _compactMode ); + + Write( "' ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 diff --git a/modules/skybrowser/tinyxml2/tinyxml2.h b/modules/skybrowser/tinyxml2/tinyxml2.h new file mode 100644 index 0000000000..d257966c97 --- /dev/null +++ b/modules/skybrowser/tinyxml2/tinyxml2.h @@ -0,0 +1,2380 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +# if defined(__PS3__) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#include + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined (__DEBUG__) +# ifndef TINYXML2_DEBUG +# define TINYXML2_DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#elif __GNUC__ >= 4 +# define TINYXML2_LIB __attribute__((visibility("default"))) +#else +# define TINYXML2_LIB +#endif + + +#if !defined(TIXMLASSERT) +#if defined(TINYXML2_DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif +#endif + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 8; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 0; + +#define TINYXML2_MAJOR_VERSION 8 +#define TINYXML2_MINOR_VERSION 0 +#define TINYXML2_PATCH_VERSION 0 + +// A fixed element depth limit is problematic. There needs to be a +// limit to avoid a stack overflow. However, that limit varies per +// system, and the capacity of the stack. On the other hand, it's a trivial +// attack that can result from ill, malicious, or even correctly formed XML, +// so there needs to be a limit in place. +static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] + + Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 +*/ +class TINYXML2_LIB StrPair +{ +public: + enum Mode { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + TIXMLASSERT( start ); + TIXMLASSERT( end ); + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + void Reset(); + +private: + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( const StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class DynArray +{ +public: + DynArray() : + _mem( _pool ), + _allocated( INITIAL_SIZE ), + _size( 0 ) + { + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size] = t; + ++_size; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + --_size; + return _mem[_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + void SwapRemove(int i) { + TIXMLASSERT(i >= 0 && i < _size); + TIXMLASSERT(_size > 0); + _mem[i] = _mem[_size - 1]; + --_size; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + const int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + TIXMLASSERT( newAllocated >= _size ); + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int ITEM_SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + MemPoolT< ITEM_SIZE >::Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* lastBlock = _blockPtrs.Pop(); + delete lastBlock; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return ITEM_SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + Item* blockItems = block->items; + for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + blockItems[i].next = &(blockItems[i + 1]); + } + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; + } + Item* const result = _root; + TIXMLASSERT( result != 0 ); + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + ++_nAllocs; + ++_nUntracked; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Item* item = static_cast( mem ); +#ifdef TINYXML2_DEBUG + memset( item, 0xfe, sizeof( *item ) ); +#endif + item->next = _root; + _root = item; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, + ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + --_nUntracked; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK + // in private part if ITEMS_PER_BLOCK is private + enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Item { + Item* next; + char itemData[ITEM_SIZE]; + }; + struct Block { + Item items[ITEMS_PER_BLOCK]; + }; + DynArray< Block*, 10 > _blockPtrs; + Item* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + XML_ELEMENT_DEPTH_EXCEEDED, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class TINYXML2_LIB XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { + TIXMLASSERT( p ); + + while( IsWhiteSpace(*p) ) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { + return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool IsPrefixHex( const char* p) { + p = SkipWhiteSpace(p, 0); + return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + TIXMLASSERT( p ); + TIXMLASSERT( q ); + TIXMLASSERT( nChar >= 0 ); + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( const char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + static void ToStr(int64_t v, char* buffer, int bufferSize); + static void ToStr(uint64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); + static bool ToInt64(const char* str, int64_t* value); + static bool ToUnsigned64(const char* str, uint64_t* value); + // Changes what is serialized for a boolean value. + // Default to "true" and "false". Shouldn't be changed + // unless you have a special testing or compatibility need. + // Be careful: static, global, & not thread safe. + // Be sure to set static const memory as parameters. + static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); + +private: + static const char* writeBoolTrue; + static const char* writeBoolFalse; +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Gets the line number the node is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Make a copy of this node and all its children. + + If the 'target' is null, then the nodes will + be allocated in the current document. If 'target' + is specified, the memory will be allocated is the + specified XMLDocument. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* target ) const; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + +protected: + explicit XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + int _parseLineNum; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + const XMLElement* ToElementWithName( const char* name ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// Gets the line number the attribute is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + uint64_t Unsigned64Value() const { + uint64_t i = 0; + QueryUnsigned64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_SUCCESS on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryUnsigned64Value(uint64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute(uint64_t value); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); + + mutable StrPair _name; + mutable StrPair _value; + int _parseLineNum; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). + */ + int IntAttribute(const char* name, int defaultValue = 0) const; + /// See IntAttribute() + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; + /// See IntAttribute() + double DoubleAttribute(const char* name, double defaultValue = 0) const; + /// See IntAttribute() + float FloatAttribute(const char* name, float defaultValue = 0) const; + + /** Given an attribute name, QueryIntAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if(!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsigned64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryStringAttribute(const char* name, const char** value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + *value = a->Value(); + return XML_SUCCESS; + } + + + + /** Given an attribute name, QueryAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + XMLError QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + XMLError QueryAttribute(const char* name, uint64_t* value) const { + return QueryUnsigned64Attribute(name, value); + } + + XMLError QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + XMLError QueryAttribute(const char* name, const char** value) const { + return QueryStringAttribute(name, value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, uint64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(uint64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryUnsigned64Text(uint64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + int IntText(int defaultValue = 0) const; + + /// See QueryIntText() + unsigned UnsignedText(unsigned defaultValue = 0) const; + /// See QueryIntText() + int64_t Int64Text(int64_t defaultValue = 0) const; + /// See QueryIntText() + uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; + /// See QueryIntText() + bool BoolText(bool defaultValue = false) const; + /// See QueryIntText() + double DoubleText(double defaultValue = 0) const; + /// See QueryIntText() + float FloatText(float defaultValue = 0) const; + + /** + Convenience method to create a new XMLElement and add it as last (right) + child of this node. Returns the created and inserted element. + */ + XMLElement* InsertNewChildElement(const char* name); + /// See InsertNewChildElement() + XMLComment* InsertNewComment(const char* comment); + /// See InsertNewChildElement() + XMLText* InsertNewText(const char* text); + /// See InsertNewChildElement() + XMLDeclaration* InsertNewDeclaration(const char* text); + /// See InsertNewChildElement() + XMLUnknown* InsertNewUnknown(const char* text); + + + // internal: + enum ElementClosingType { + OPEN, // + CLOSED, // + CLOSING // + }; + ElementClosingType ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindOrCreateAttribute( const char* name ); + char* ParseAttributes( char* p, int* curLineNumPtr ); + static void DeleteAttribute( XMLAttribute* attribute ); + XMLAttribute* CreateAttribute(); + + enum { BUF_SIZE = 200 }; + ElementClosingType _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; + // Gives access to SetError and Push/PopDepth, but over-access for everything else. + // Wishing C++ had "internal" scope. + friend class XMLNode; + friend class XMLText; + friend class XMLComment; + friend class XMLDeclaration; + friend class XMLUnknown; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_SUCCESS (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=static_cast(-1) ); + + /** + Load an XML file from disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespaceMode; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + /// Clears the error flags. + void ClearError(); + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); + + /** Returns a "long form" error description. A hopefully helpful + diagnostic with location, line number, and/or additional info. + */ + const char* ErrorStr() const; + + /// A (trivial) utility function that prints the ErrorStr() to stdout. + void PrintError() const; + + /// Return the line where the error occurred, or zero if unknown. + int ErrorLineNum() const + { + return _errorLineNum; + } + + /// Clear the document, resetting it to the initial state. + void Clear(); + + /** + Copies this document to a target document. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see XMLNode::DeepClone(). + + NOTE: that the 'target' must be non-null. + */ + void DeepCopy(XMLDocument* target) const; + + // internal + char* Identify( char* p, XMLNode** node ); + + // internal + void MarkInUse(const XMLNode* const); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespaceMode; + mutable StrPair _errorStr; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; + int _parsingDepth; + // Memory tracking does add some overhead. + // However, the code assumes that you don't + // have a bunch of unlinked nodes around. + // Therefore it takes less memory to track + // in the document vs. a linked list in the XMLNode, + // and the performance is the same. + DynArray _unlinked; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); + + void SetError( XMLError error, int lineNum, const char* format, ... ); + + // Something of an obvious security hole, once it was discovered. + // Either an ill-formed XML or an excessively deep one can overflow + // the stack. Track stack depth, and error out if needed. + class DepthTracker { + public: + explicit DepthTracker(XMLDocument * document) { + this->_document = document; + document->PushDepth(); + } + ~DepthTracker() { + _document->PopDepth(); + } + private: + XMLDocument * _document; + }; + void PushDepth(); + void PopDepth(); + + template + NodeType* CreateUnlinkedNode( MemPoolT& pool ); +}; + +template +inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) +{ + TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); + TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); + NodeType* returnNode = new (pool.Alloc()) NodeType( this ); + TIXMLASSERT( returnNode ); + returnNode->_memPool = &pool; + + _unlinked.Push(returnNode); + return returnNode; +} + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + explicit XMLHandle( XMLNode* node ) : _node( node ) { + } + /// Create a handle from a node. + explicit XMLHandle( XMLNode& node ) : _node( &node ) { + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( _node ? _node->ToElement() : 0 ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( _node ? _node->ToText() : 0 ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( _node ? _node->ToUnknown() : 0 ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { + } + explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { + } + XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( _node ? _node->ToElement() : 0 ); + } + const XMLText* ToText() const { + return ( _node ? _node->ToText() : 0 ); + } + const XMLUnknown* ToUnknown() const { + return ( _node ? _node->ToUnknown() : 0 ); + } + const XMLDeclaration* ToDeclaration() const { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute( const char* name, int64_t value ); + void PushAttribute( const char* name, uint64_t value ); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from a signed 64bit integer. + void PushText( int64_t value ); + /// Add a text node from an unsigned 64bit integer. + void PushText( uint64_t value ); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer( bool resetToFirstElement = true ) { + _buffer.Clear(); + _buffer.Push(0); + _firstElement = resetToFirstElement; + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + virtual void Print( const char* format, ... ); + virtual void Write( const char* data, size_t size ); + virtual void Putc( char ch ); + + inline void Write(const char* data) { Write(data, strlen(data)); } + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + /** + Prepares to write a new node. This includes sealing an element that was + just opened, and writing any whitespace necessary if not in compact mode. + */ + void PrepareForNewNode( bool compactMode ); + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; + + // Prohibit cloning, intentionally not implemented + XMLPrinter( const XMLPrinter& ); + XMLPrinter& operator=( const XMLPrinter& ); +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED From f99f3e88a9275fbd18120b22212f65bc56cac3aa Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 31 Mar 2021 17:02:51 +0200 Subject: [PATCH 053/251] Move the WWT data handling to class WWTDataHandler and add pointer in module --- modules/skybrowser/CMakeLists.txt | 2 + modules/skybrowser/include/wwtdatahandler.h | 44 ++++ modules/skybrowser/skybrowsermodule.cpp | 205 +------------------ modules/skybrowser/skybrowsermodule.h | 30 +-- modules/skybrowser/skybrowsermodule_lua.inl | 12 +- modules/skybrowser/src/wwtdatahandler.cpp | 212 ++++++++++++++++++++ 6 files changed, 277 insertions(+), 228 deletions(-) create mode 100644 modules/skybrowser/include/wwtdatahandler.h create mode 100644 modules/skybrowser/src/wwtdatahandler.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 53db470fff..0241bd1178 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -29,6 +29,7 @@ set(HEADER_FILES skybrowsermodule.h include/screenspaceskybrowser.h include/screenspaceskytarget.h + include/wwtdatahandler.h tinyxml2/tinyxml2.h ) @@ -40,6 +41,7 @@ set(SOURCE_FILES skybrowsermodule_lua.inl src/screenspaceskybrowser.cpp src/screenspaceskytarget.cpp + src/wwtdatahandler.cpp tinyxml2/tinyxml2.cpp ) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h new file mode 100644 index 0000000000..8898327368 --- /dev/null +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -0,0 +1,44 @@ +#ifndef __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ + +#include +#include + +namespace openspace::documentation { struct Documentation; } + +namespace openspace { + + struct ImageData { + std::string name; + std::string thumbnailUrl; + glm::vec2 celestCoords; + std::string collection; + }; + + class WWTDataHandler { + + public: + WWTDataHandler() = default; + ~WWTDataHandler(); + // Image downloading and xml parsing + bool downloadFile(std::string& url, std::string& fileDestination); + void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); + void loadWTMLCollectionsFromURL(std::string url, std::string fileName); + void loadWTMLCollectionsFromDirectory(std::string directory); + int loadAllImagesFromXMLs(); + void printAllUrls(); + private: + int loadPlace(tinyxml2::XMLElement* place, std::string collectionName); + int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName); + std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet); + tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); + + std::vector images; + std::vector imageUrls; + std::vector xmls; + + }; +} + +#endif // __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ + diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 11a6af6ea1..69b2ace77c 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -23,8 +23,7 @@ ****************************************************************************************/ #include -#include - +#include //#include //#include #include @@ -43,10 +42,9 @@ #include #include // For atan2 #include // For printing glm data -#include -#include // For downloading files from url + #include -#include // To iterate through files in directory + namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -243,13 +241,9 @@ SkyBrowserModule::SkyBrowserModule() } ); } -SkyBrowserModule::~SkyBrowserModule() { - // Call destructor of all allocated xmls - xmls.clear(); -} void SkyBrowserModule::internalDeinitialize() { - + delete dataHandler; } @@ -266,6 +260,7 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); + dataHandler = new WWTDataHandler(); } glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { @@ -292,196 +287,10 @@ ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } -bool SkyBrowserModule::downloadFile(std::string& url, std::string& fileDestination) { - // Get the webpage and save to file - HttpRequest::RequestOptions opt{ 5 }; - SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes); - wtml_root.download(opt); - return wtml_root.hasSucceeded(); +WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { + return dataHandler; } -void SkyBrowserModule::loadWTMLCollectionsFromURL(std::string url, std::string fileName) { - // Get file - std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/") + fileName + ".aspx"; - if (!downloadFile(url, fileDestination)) { - LINFO("Couldn't download file " + url); - return; - } - // Parse to XML - using namespace tinyxml2; - tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - doc->LoadFile(fileDestination.c_str()); - - XMLElement* root = doc->RootElement(); - XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); - // If there are no folders, or there are folder but without urls, stop recursion - if (!element || (element && !element->FindAttribute("Url"))) { - - imageUrls.push_back(url); - xmls.push_back(doc); - LINFO("Saving " + url); - - return; - } - // Iterate through all the folders - while (element && std::string(element->Value()) == "Folder") { - // Get all attributes for the - std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : ""; - std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : ""; - if (subUrl != "" && subName != "") { - loadWTMLCollectionsFromURL(subUrl, subName); - } - element = element->NextSiblingElement(); - } -} - -void SkyBrowserModule::loadWTMLCollectionsFromDirectory(std::string directory) { - - for (const auto& entry : std::filesystem::directory_iterator(directory)) { - tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - std::cout << entry.path().u8string().c_str() << std::endl; - if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) { - xmls.push_back(doc); - } - } -} - -std::ostream& operator<<(std::ostream& os, const ImageData& img) { - os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl; - os << "Thumbnail: " << img.thumbnailUrl << std::endl; - os << "Collection: " << img.collection << std::endl << std::endl; - return os; -} - - -int SkyBrowserModule::loadAllImagesFromXMLs() { - for(tinyxml2::XMLDocument* doc : xmls) { - tinyxml2::XMLElement* root = doc->FirstChildElement(); - std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; - loadImagesFromXML(root, collectionName); - } - - for (ImageData img : images) { - std::cout << img; - } - return images.size(); -} - -void SkyBrowserModule::printAllUrls() { - for (auto it = imageUrls.begin(); it != imageUrls.end(); it++) { - LINFO(*it); - } -} - -void SkyBrowserModule::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) { - // Get direct child of node called "Place" - using namespace tinyxml2; - XMLElement* folder = getChildNode(node->FirstChildElement(), "Folder"); - - // Terminate recursion if no folders - if (!folder) { - // When we are at leaf folder - // Iterate through all the places and load as images - // Prefer places over Image Sets as they contain same info - XMLElement* place = getChildNode(node->FirstChildElement(), "Place"); - // No place found - look for images instead - if (!place) { - XMLElement* imageSet = getChildNode(node->FirstChildElement(), "ImageSet"); - while (imageSet) { - loadImageSet(imageSet, collectionName); - imageSet = imageSet->NextSiblingElement(); - } - } - // Place found - look through places - while (place) { - loadPlace(place, collectionName); - place = place->NextSiblingElement(); - } - } - else { - // Open all folders at same level - while (folder) { - std::string newCollectionName = collectionName + "/"; - if (folder->FindAttribute("Name")) { - newCollectionName += std::string(folder->FindAttribute("Name")->Value()); - } - loadImagesFromXML(folder, newCollectionName); - folder = folder->NextSiblingElement(); - } - } -} - -int SkyBrowserModule::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) { - // Only load "Sky" type images - if (std::string(place->FindAttribute("DataSetType")->Value()) != "Sky") - return - 1; - - std::string url = ""; - // If the place doesn't have a thumbnail url data attribute, - // Load the containing image set instead - if (!place->FindAttribute("Thumbnail")) { - // Traverse the children and look at all their first child to find ImageSet - tinyxml2::XMLElement* child = place->FirstChildElement(); - tinyxml2::XMLElement* imageSet = nullptr; - while (child) { - imageSet = getChildNode(child, "ImageSet"); - if (imageSet) break; - child = child->NextSiblingElement(); - } - // If the place doesn't contain an image, nothing to add - if (!imageSet) return -1; - - // Collect thumbnail url from ImageSet - url = getURLFromImageSet(imageSet); - if (url == "") return -1; - } - ImageData image; - // Get attributes for the image - image.name = place->FindAttribute("Name") ? place->FindAttribute("Name")->Value() : ""; - image.celestCoords.x = place->FindAttribute("RA") ? std::stof(place->FindAttribute("RA")->Value()) : 0.f; - image.celestCoords.y = place->FindAttribute("Dec") ? std::stof(place->FindAttribute("Dec")->Value()) : 0.f; - image.thumbnailUrl = url == "" ? place->FindAttribute("Thumbnail")->Value() : url; - image.collection = collectionName; - - images.push_back(image); - // Return index of image in vector - return images.size(); -} -int SkyBrowserModule::loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName) { - std::string type = imageSet->FindAttribute("DataSetType") ? imageSet->FindAttribute("DataSetType")->Value() : ""; - // Only load "Sky" type images - if (type != "Sky") - return - 1; - - ImageData image; - - // Get attributes for the image - image.name = imageSet->FindAttribute("Name") ? imageSet->FindAttribute("Name")->Value() : ""; - image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f; - image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f; - image.thumbnailUrl = getURLFromImageSet(imageSet); - image.collection = collectionName; - - images.push_back(image); - // Return index of image in vector - return images.size(); -} - -std::string SkyBrowserModule::getURLFromImageSet(tinyxml2::XMLElement* imageSet) { - // FInd the thumbnail image url - // The thumbnail is the last node so traverse backwards for speed - tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement("ThumbnailUrl"); - return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; -} - -tinyxml2::XMLElement* SkyBrowserModule::getChildNode(tinyxml2::XMLElement* node, std::string name) { - while (node && std::string(node->Name()) != name) { - node = node->FirstChildElement(); - } - return node; -} - - /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index ee7b79a138..ff402b4be7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -26,7 +26,7 @@ #define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ #include -#include + #include #include #include @@ -38,40 +38,25 @@ namespace openspace { class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; class ScreenSpaceRenderable; +class WWTDataHandler; -struct ImageData { - std::string name; - std::string thumbnailUrl; - glm::vec2 celestCoords; - std::string collection; -}; class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; SkyBrowserModule(); - virtual ~SkyBrowserModule(); + virtual ~SkyBrowserModule() = default; glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); - // Image downloading and xml parsing - bool downloadFile(std::string& url, std::string& fileDestination); - void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); - void loadWTMLCollectionsFromURL(std::string url, std::string fileName); - void loadWTMLCollectionsFromDirectory(std::string directory); - int loadAllImagesFromXMLs(); - void printAllUrls(); - + WWTDataHandler* getWWTDataHandler(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; - int loadPlace(tinyxml2::XMLElement* place, std::string collectionName); - int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName); - std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet); - tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); + // Using snake case on these casting functions to make them similar to eg std::to_string ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr); ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr); @@ -92,10 +77,7 @@ protected: // Current interaction status bool currentlyResizingBrowser; bool currentlyDraggingObject; - - std::vector images; - std::vector imageUrls; - std::vector xmls; + WWTDataHandler* dataHandler; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index dc0b5c6243..43d084d04e 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -49,9 +49,9 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - module->loadWTMLCollectionsFromURL(root, "root"); - module->printAllUrls(); - LINFO(std::to_string( module->loadAllImagesFromXMLs())); + module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); + module->getWWTDataHandler()->printAllUrls(); + LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); return 1; } @@ -59,9 +59,9 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); - module->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); - module->printAllUrls(); - LINFO(std::to_string(module->loadAllImagesFromXMLs())); + module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); + module->getWWTDataHandler()->printAllUrls(); + LINFO(std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs())); return 1; } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp new file mode 100644 index 0000000000..422b0182b7 --- /dev/null +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -0,0 +1,212 @@ +#include +#include // For downloading files from url +#include // To iterate through files in directory +#include +#include + +namespace { + constexpr const char* _loggerCat = "WWTDataHandler"; + + + + +} //namespace + +namespace openspace { + + WWTDataHandler::~WWTDataHandler() { + // Call destructor of all allocated xmls + xmls.clear(); + } + + bool WWTDataHandler::downloadFile(std::string& url, std::string& fileDestination) { + // Get the webpage and save to file + HttpRequest::RequestOptions opt{ 5 }; + SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes); + wtml_root.download(opt); + return wtml_root.hasSucceeded(); + } + + void WWTDataHandler::loadWTMLCollectionsFromURL(std::string url, std::string fileName) { + // Get file + std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/") + fileName + ".aspx"; + if (!downloadFile(url, fileDestination)) { + LINFO("Couldn't download file " + url); + return; + } + // Parse to XML + using namespace tinyxml2; + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + doc->LoadFile(fileDestination.c_str()); + + XMLElement* root = doc->RootElement(); + XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); + // If there are no folders, or there are folder but without urls, stop recursion + if (!element || (element && !element->FindAttribute("Url"))) { + + imageUrls.push_back(url); + xmls.push_back(doc); + LINFO("Saving " + url); + + return; + } + // Iterate through all the folders + while (element && std::string(element->Value()) == "Folder") { + // Get all attributes for the + std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : ""; + std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : ""; + if (subUrl != "" && subName != "") { + loadWTMLCollectionsFromURL(subUrl, subName); + } + element = element->NextSiblingElement(); + } + } + + void WWTDataHandler::loadWTMLCollectionsFromDirectory(std::string directory) { + + for (const auto& entry : std::filesystem::directory_iterator(directory)) { + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + std::cout << entry.path().u8string().c_str() << std::endl; + if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) { + xmls.push_back(doc); + } + } + } + + std::ostream& operator<<(std::ostream& os, const ImageData& img) { + os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl; + os << "Thumbnail: " << img.thumbnailUrl << std::endl; + os << "Collection: " << img.collection << std::endl << std::endl; + return os; + } + + + int WWTDataHandler::loadAllImagesFromXMLs() { + for (tinyxml2::XMLDocument* doc : xmls) { + tinyxml2::XMLElement* root = doc->FirstChildElement(); + std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; + loadImagesFromXML(root, collectionName); + } + + for (ImageData img : images) { + std::cout << img; + } + return images.size(); + } + + void WWTDataHandler::printAllUrls() { + for (auto it = imageUrls.begin(); it != imageUrls.end(); it++) { + LINFO(*it); + } + } + + void WWTDataHandler::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) { + // Get direct child of node called "Place" + using namespace tinyxml2; + XMLElement* folder = getChildNode(node->FirstChildElement(), "Folder"); + + // Terminate recursion if no folders + if (!folder) { + // When we are at leaf folder + // Iterate through all the places and load as images + // Prefer places over Image Sets as they contain same info + XMLElement* place = getChildNode(node->FirstChildElement(), "Place"); + // No place found - look for images instead + if (!place) { + XMLElement* imageSet = getChildNode(node->FirstChildElement(), "ImageSet"); + while (imageSet) { + loadImageSet(imageSet, collectionName); + imageSet = imageSet->NextSiblingElement(); + } + } + // Place found - look through places + while (place) { + loadPlace(place, collectionName); + place = place->NextSiblingElement(); + } + } + else { + // Open all folders at same level + while (folder) { + std::string newCollectionName = collectionName + "/"; + if (folder->FindAttribute("Name")) { + newCollectionName += std::string(folder->FindAttribute("Name")->Value()); + } + loadImagesFromXML(folder, newCollectionName); + folder = folder->NextSiblingElement(); + } + } + } + + int WWTDataHandler::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) { + // Only load "Sky" type images + if (std::string(place->FindAttribute("DataSetType")->Value()) != "Sky") + return -1; + + std::string url = ""; + // If the place doesn't have a thumbnail url data attribute, + // Load the containing image set instead + if (!place->FindAttribute("Thumbnail")) { + // Traverse the children and look at all their first child to find ImageSet + tinyxml2::XMLElement* child = place->FirstChildElement(); + tinyxml2::XMLElement* imageSet = nullptr; + while (child) { + imageSet = getChildNode(child, "ImageSet"); + if (imageSet) break; + child = child->NextSiblingElement(); + } + // If the place doesn't contain an image, nothing to add + if (!imageSet) return -1; + + // Collect thumbnail url from ImageSet + url = getURLFromImageSet(imageSet); + if (url == "") return -1; + } + ImageData image; + // Get attributes for the image + image.name = place->FindAttribute("Name") ? place->FindAttribute("Name")->Value() : ""; + image.celestCoords.x = place->FindAttribute("RA") ? std::stof(place->FindAttribute("RA")->Value()) : 0.f; + image.celestCoords.y = place->FindAttribute("Dec") ? std::stof(place->FindAttribute("Dec")->Value()) : 0.f; + image.thumbnailUrl = url == "" ? place->FindAttribute("Thumbnail")->Value() : url; + image.collection = collectionName; + + images.push_back(image); + // Return index of image in vector + return images.size(); + } + + int WWTDataHandler::loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName) { + std::string type = imageSet->FindAttribute("DataSetType") ? imageSet->FindAttribute("DataSetType")->Value() : ""; + // Only load "Sky" type images + if (type != "Sky") + return -1; + + ImageData image; + + // Get attributes for the image + image.name = imageSet->FindAttribute("Name") ? imageSet->FindAttribute("Name")->Value() : ""; + image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f; + image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f; + image.thumbnailUrl = getURLFromImageSet(imageSet); + image.collection = collectionName; + + images.push_back(image); + // Return index of image in vector + return images.size(); + } + + std::string WWTDataHandler::getURLFromImageSet(tinyxml2::XMLElement* imageSet) { + // FInd the thumbnail image url + // The thumbnail is the last node so traverse backwards for speed + tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement("ThumbnailUrl"); + return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; + } + + tinyxml2::XMLElement* WWTDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) { + while (node && std::string(node->Name()) != name) { + node = node->FirstChildElement(); + } + return node; + } + +} From c234b6943650e11567d51cd59c1ea953c32b4ecf Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Tue, 6 Apr 2021 08:44:42 +0200 Subject: [PATCH 054/251] Add function to drag and change view within browser --- .../include/screenspaceskybrowser.h | 5 +- modules/skybrowser/skybrowsermodule.cpp | 72 +++++++++++++++++-- modules/skybrowser/skybrowsermodule.h | 5 +- modules/skybrowser/skybrowsermodule_lua.inl | 8 +++ .../skybrowser/src/screenspaceskybrowser.cpp | 20 +++--- .../skybrowser/src/screenspaceskytarget.cpp | 4 +- 6 files changed, 94 insertions(+), 20 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 0313dceb58..c816d5f1d1 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -28,14 +28,13 @@ namespace openspace { glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; float fieldOfView() const; void scrollZoom(float scroll); + ScreenSpaceSkyTarget* getSkyTarget(); // Translation //void translate(glm::vec2 translation); // Position and dimension and corners - - glm::vec2 getScreenSpaceBrowserDimension(); - + glm::vec2 getBrowserPixelDimensions(); glm::vec2 coordIsOnResizeArea(glm::vec2 coord); // Scaling void scale(glm::vec2 scalingFactor); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 79ffc0851a..c51d74d411 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -93,7 +93,15 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" - } + }, + { + "adjustCamera", + & skybrowser::luascriptfunctions::adjustCamera, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, }; return res; @@ -107,6 +115,7 @@ SkyBrowserModule::SkyBrowserModule() , currentlyDraggingObject(false) , resizeVector(0.f, 0.f) , shouldInitialize(true) + , changeViewWithinBrowser(false) { global::callback::mousePosition->emplace_back( [&](double x, double y) { @@ -127,7 +136,37 @@ SkyBrowserModule::SkyBrowserModule() _mousePosition = getMousePositionInScreenSpaceCoords(pos); if (currentlyDraggingObject) { - _mouseOnObject->translate(_mousePosition - startDragMousePos, startDragObjectPos); + + glm::dvec2 move = _mousePosition - startDragMousePos; + + // Change view within the browser and move target accordingly to mousedrag movement + if (changeViewWithinBrowser) { + // WWT FOV + double WWTVerticalFOV = to_browser(_mouseOnObject)->fieldOfView(); + glm::dvec2 browserDim = to_browser(_mouseOnObject)->getScreenSpaceDimensions(); + double browserRatio = browserDim.x / browserDim.y; + glm::dvec2 WWTFOV = glm::dvec2(WWTVerticalFOV * browserRatio, WWTVerticalFOV); + + // OpenSpace FOV + glm::dvec2 windowDim = global::windowDelegate->currentWindowSize(); + double windowRatio = windowDim.y / windowDim.x; + double OpenSpaceHorizontalFOV = global::windowDelegate->getHorizFieldOfView(); + glm::dvec2 OpenSpaceFOV = glm::dvec2(OpenSpaceHorizontalFOV, OpenSpaceHorizontalFOV * windowRatio); + + + glm::dvec2 angleResult = WWTFOV * (move / browserDim); + glm::dvec2 OSresult = angleResult / OpenSpaceFOV; + + // Calculate translation in ScreenSpaceCoordinates + glm::dvec2 screenSpaceCoord{ (2 / windowRatio), 2.f }; + glm::dvec2 result = screenSpaceCoord * OSresult; + + to_browser(_mouseOnObject)->getSkyTarget()->translate(-result, startDragObjectPos); + + } + // Move browser or target + else _mouseOnObject->translate(move, startDragObjectPos); + } else if (currentlyResizingBrowser) { // Calculate scaling factor @@ -214,18 +253,22 @@ SkyBrowserModule::SkyBrowserModule() currentlyDraggingObject = true; return true; - } + } else if (to_browser(_mouseOnObject) && button == MouseButton::Right) { - //startDragMousePos = _mousePosition; - //startDragObjectPos = dynamic_cast(_mouseOnObject)->->getScreenSpacePosition(); - //currentlyDraggingObject = true; + // Change view (by moving target) within browser if right mouse click on browser + startDragMousePos = _mousePosition; + startDragObjectPos = to_browser(_mouseOnObject)->getSkyTarget()->getScreenSpacePosition(); + changeViewWithinBrowser = true; + currentlyDraggingObject = true; + return true; } } else if (action == MouseAction::Release) { if (currentlyDraggingObject) { currentlyDraggingObject = false; + changeViewWithinBrowser = false; return true; } if (currentlyResizingBrowser) { @@ -285,6 +328,23 @@ ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { } +glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { + // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> + // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 + -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 + -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 + }); + + glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; + float ra = atan2(rICRS[1], rICRS[0]); + float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); + + ra = ra > 0 ? ra : ra + (2 * glm::pi()); + + return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); +} /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index aa26181e56..3ef6718e3e 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -49,10 +49,12 @@ public: glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); + glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; + scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; -protected: +protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; // Using snake case on these casting functions to make them similar to eg std::to_string @@ -67,6 +69,7 @@ protected: // Dragging glm::vec2 startDragMousePos; glm::vec2 startDragObjectPos; + bool changeViewWithinBrowser; // Resizing glm::vec2 startResizeBrowserSize; glm::vec2 resizeVector; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 1c068aaf22..7b84734392 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -23,6 +23,9 @@ #include #include +#include +#include + namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; @@ -52,6 +55,11 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); + return 1; + } + int adjustCamera(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); + return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 53d4094d1c..52abf26572 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -18,10 +18,11 @@ #include #include #include -#include #include #include // Milliseconds +#include // to adjust camera angle +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -79,7 +80,7 @@ namespace openspace { setConnectedTarget(); } else { - glm::vec2 dim = getScreenSpaceBrowserDimension(); + glm::vec2 dim = getBrowserPixelDimensions(); _skyTarget->setDimensions(dim); } }); @@ -126,7 +127,7 @@ namespace openspace { global::moduleEngine->module()->addRenderable(this); setConnectedTarget(); if (_skyTarget) { - _skyTarget->setDimensions(getScreenSpaceBrowserDimension()); + _skyTarget->setDimensions(getBrowserPixelDimensions()); } WWTfollowCamera(); @@ -149,12 +150,18 @@ namespace openspace { return _skyTarget != nullptr; } + ScreenSpaceSkyTarget* ScreenSpaceSkyBrowser::getSkyTarget() { + return _skyTarget; + } + float ScreenSpaceSkyBrowser::fieldOfView() const { return _fieldOfView; } void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { - float zoom = scroll > 0.0 ? -log(_fieldOfView + 1.1f) : log(_fieldOfView + 1.1f); + + float zoomFactor = log(_fieldOfView + 1.1f); + float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; _fieldOfView = std::clamp(_fieldOfView + zoom, 0.001f, 70.0f); } @@ -277,9 +284,6 @@ namespace openspace { _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); }*/ - - - glm::vec2 ScreenSpaceSkyBrowser::coordIsOnResizeArea(glm::vec2 coord) { glm::vec2 resizePosition = glm::vec2{ 0 }; // Make sure coord is on browser @@ -338,7 +342,7 @@ namespace openspace { _scale = _startScale * scalingFactor; } - glm::vec2 ScreenSpaceSkyBrowser::getScreenSpaceBrowserDimension() { + glm::vec2 ScreenSpaceSkyBrowser::getBrowserPixelDimensions() { return _browserDimensions.value(); } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 00f2cbd417..e649c3cdef 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -72,7 +72,7 @@ namespace openspace { : ScreenSpaceRenderable(dictionary) , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) - , _showCrosshairThreshold(CrosshairThresholdInfo, 3.f, 1.f, 70.f) + , _showCrosshairThreshold(CrosshairThresholdInfo, 2.f, 1.f, 70.f) , _borderColor(220.f, 220.f, 220.f) { // Handle target dimension property @@ -204,7 +204,7 @@ namespace openspace { glDisable(GL_CULL_FACE); glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float borderWidth = 0.005f/_scale.value(); + float borderWidth = 0.002f/_scale.value(); glm::vec2 targetDim; bool showCrosshair; _targetDimensions.value() == glm::vec2(0) ? targetDim = glm::vec2(1) : targetDim = _targetDimensions.value(); From d74de3273b35ea4cdd4e8e7f87c634161433e558 Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Tue, 6 Apr 2021 09:01:48 +0200 Subject: [PATCH 055/251] Merge with master --- apps/OpenSpace/ext/sgct | 2 +- ext/ghoul | 2 +- modules/kameleon/ext/kameleon | 2 +- support/coding/codegen | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 669fbc16a9..eefd275cce 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 669fbc16a9910b28333427f5e07235baa43ea7a6 +Subproject commit eefd275ccec15c9316e4bc91d7232f3beea083a2 diff --git a/ext/ghoul b/ext/ghoul index 1413844185..1625701baa 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 1413844185b244559b8b90a06e03ddcea33fb2b5 +Subproject commit 1625701baa17a568163d96a3532489d306d18e0e diff --git a/modules/kameleon/ext/kameleon b/modules/kameleon/ext/kameleon index 606edb945b..8a5e966659 160000 --- a/modules/kameleon/ext/kameleon +++ b/modules/kameleon/ext/kameleon @@ -1 +1 @@ -Subproject commit 606edb945b62d0151f20270ddb2db4a9f558aaa1 +Subproject commit 8a5e9666599e9578d50bf3801dd07a9edf95ccdb diff --git a/support/coding/codegen b/support/coding/codegen index d1e354f072..b3c0a745fa 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit d1e354f07257d37b241d7c8d3a85eef3d0cb62bd +Subproject commit b3c0a745fa68e5f762de8a06732038e3a6fd5e02 From b8d1c33eedae8dde39007536bf8f29966a677e0e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 6 Apr 2021 15:11:14 +0200 Subject: [PATCH 056/251] Add Lua function to send the image thumbnail url:s to the api --- data/assets/customization/gui.asset | 2 +- modules/skybrowser/include/wwtdatahandler.h | 2 ++ modules/skybrowser/skybrowsermodule_lua.inl | 9 +++++++++ modules/skybrowser/src/wwtdatahandler.cpp | 8 ++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/data/assets/customization/gui.asset b/data/assets/customization/gui.asset index e18cd44a7f..6a43444b0a 100644 --- a/data/assets/customization/gui.asset +++ b/data/assets/customization/gui.asset @@ -1,4 +1,4 @@ -asset.export("webguiDevelopmentMode", false) +asset.export("webguiDevelopmentMode", true) -- To make changes to the webgui: diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 8898327368..847cb9a44b 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -27,6 +27,8 @@ namespace openspace { void loadWTMLCollectionsFromDirectory(std::string directory); int loadAllImagesFromXMLs(); void printAllUrls(); + std::vector getAllThumbnailUrls(); + private: int loadPlace(tinyxml2::XMLElement* place, std::string collectionName); int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 43d084d04e..ec1c152388 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -67,7 +67,16 @@ namespace openspace::skybrowser::luascriptfunctions { int createBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); + SkyBrowserModule* module = global::moduleEngine->module(); + std::vector names = module->getWWTDataHandler()->getAllThumbnailUrls(); + lua_newtable(L); + int number = 1; + for (const std::string& s : names) { + lua_pushstring(L, s.c_str()); + lua_rawseti(L, -2, number); + ++number; + } return 1; } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 422b0182b7..f87a581fbc 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -209,4 +209,12 @@ namespace openspace { return node; } + std::vector WWTDataHandler::getAllThumbnailUrls() { + std::vector imgUrls; + std::for_each(images.begin(), images.end(), [&](ImageData obj) { + imgUrls.push_back(obj.thumbnailUrl); + }); + return imgUrls; + } + } From 3f68ea9b4d724f5199fce99bbb2468540c96ef0e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 7 Apr 2021 16:09:14 +0200 Subject: [PATCH 057/251] Send over image name and url to GUI api --- modules/skybrowser/include/wwtdatahandler.h | 3 ++- modules/skybrowser/skybrowsermodule_lua.inl | 24 +++++++++++++++------ modules/skybrowser/src/wwtdatahandler.cpp | 13 ++++++----- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 847cb9a44b..488924df6e 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -27,7 +27,8 @@ namespace openspace { void loadWTMLCollectionsFromDirectory(std::string directory); int loadAllImagesFromXMLs(); void printAllUrls(); - std::vector getAllThumbnailUrls(); + std::vector < std::pair < std::string, std::string> > getAllThumbnailUrls(); + const std::vector& getImages() const; private: int loadPlace(tinyxml2::XMLElement* place, std::string collectionName); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 0062cdf0b5..35e0eded1a 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -63,24 +63,36 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); - module->getWWTDataHandler()->printAllUrls(); - LINFO(std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs())); + std::string noOfLoadedImgs = std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs()); + LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); return 1; } int createBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector names = module->getWWTDataHandler()->getAllThumbnailUrls(); + // If no data has been loaded yet, load it! + if (module->getWWTDataHandler()->getImages().size() == 0) { + moveBrowser(L); + } + + std::vector> names = module->getWWTDataHandler()->getAllThumbnailUrls(); lua_newtable(L); + int number = 1; - for (const std::string& s : names) { - lua_pushstring(L, s.c_str()); + for (const std::pair& s : names) { + + lua_newtable(L); + lua_pushstring(L, s.first.c_str()); + lua_rawseti(L, -2, 1); + lua_pushstring(L, s.second.c_str()); + lua_rawseti(L, -2, 2); + lua_rawseti(L, -2, number); ++number; } - + return 1; } int adjustCamera(lua_State* L) { diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index f87a581fbc..daccfeaf9d 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -209,12 +209,15 @@ namespace openspace { return node; } - std::vector WWTDataHandler::getAllThumbnailUrls() { - std::vector imgUrls; + std::vector < std::pair < std::string, std::string> > WWTDataHandler::getAllThumbnailUrls() { + std::vector < std::pair < std::string, std::string> > imgResult; std::for_each(images.begin(), images.end(), [&](ImageData obj) { - imgUrls.push_back(obj.thumbnailUrl); + imgResult.push_back(std::pair(obj.name, obj.thumbnailUrl)); }); - return imgUrls; + return imgResult; + } + + const std::vector& WWTDataHandler::getImages() const { + return images; } - } From 67a39652d52e86349f879ffb3dd58f2a464be9a7 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 8 Apr 2021 09:35:46 +0200 Subject: [PATCH 058/251] Make it possible to select images in GUI and thereby loading them into WWT, and bugfix for parsing xml --- modules/skybrowser/include/wwtdatahandler.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 22 ++++++++---- modules/skybrowser/src/wwtdatahandler.cpp | 37 ++++++++++----------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 488924df6e..500ca67c5c 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -26,7 +26,7 @@ namespace openspace { void loadWTMLCollectionsFromURL(std::string url, std::string fileName); void loadWTMLCollectionsFromDirectory(std::string directory); int loadAllImagesFromXMLs(); - void printAllUrls(); + const std::vector& getAllImageCollectionUrls() const; std::vector < std::pair < std::string, std::string> > getAllThumbnailUrls(); const std::vector& getImages() const; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 35e0eded1a..ad562c4a9a 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -35,40 +35,50 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { int loadImgCollection(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::loadCollection"); + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); + const std::string& imageName = ghoul::lua::value(L, 1); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - std::string url = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=wise"; - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); - browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT("Andromeda Galaxy")); + + browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(imageName)); + LINFO("Loading image " + imageName); // browser->sendMessageToWWT(browser->createMessageForMovingWWTCamera(glm::vec2(0.712305533333333, 41.269167), 24.0f)); browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 1; } int followCamera(lua_State* L) { + // Load images from url ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); SkyBrowserModule* module = global::moduleEngine->module(); std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); - module->getWWTDataHandler()->printAllUrls(); LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); return 1; } int moveBrowser(lua_State* L) { + // Load images from local directory ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); std::string noOfLoadedImgs = std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs()); LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); + + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); + for (const std::string url : imageUrls) { + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); + } return 1; } int createBrowser(lua_State* L) { + // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); // If no data has been loaded yet, load it! @@ -82,7 +92,7 @@ namespace openspace::skybrowser::luascriptfunctions { int number = 1; for (const std::pair& s : names) { - + // Push a table { image name, image url } with index : number lua_newtable(L); lua_pushstring(L, s.first.c_str()); lua_rawseti(L, -2, 1); diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index daccfeaf9d..dbb2cdf697 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -94,10 +94,8 @@ namespace openspace { return images.size(); } - void WWTDataHandler::printAllUrls() { - for (auto it = imageUrls.begin(); it != imageUrls.end(); it++) { - LINFO(*it); - } + const std::vector& WWTDataHandler::getAllImageCollectionUrls() const { + return imageUrls; } void WWTDataHandler::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) { @@ -108,22 +106,23 @@ namespace openspace { // Terminate recursion if no folders if (!folder) { // When we are at leaf folder - // Iterate through all the places and load as images - // Prefer places over Image Sets as they contain same info - XMLElement* place = getChildNode(node->FirstChildElement(), "Place"); - // No place found - look for images instead - if (!place) { - XMLElement* imageSet = getChildNode(node->FirstChildElement(), "ImageSet"); - while (imageSet) { - loadImageSet(imageSet, collectionName); - imageSet = imageSet->NextSiblingElement(); + // Iterate through all the :s and :s and load as images + // Go down to the level where places and image sets are + XMLElement* ptr = getChildNode(node->FirstChildElement(), "Place"); + if (!ptr) { + ptr = getChildNode(node->FirstChildElement(), "ImageSet"); + } + // Iterate through all siblings at same level and load + while (ptr) { + if (std::string(ptr->Name()) == "ImageSet") { + loadImageSet(ptr, collectionName); } - } - // Place found - look through places - while (place) { - loadPlace(place, collectionName); - place = place->NextSiblingElement(); - } + else if (std::string(ptr->Name()) == "Place") { + loadPlace(ptr, collectionName); + } + + ptr = ptr->NextSiblingElement(); + } } else { // Open all folders at same level From a84e8ee48b6fcfa6fab322a5a719089d187e241a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 8 Apr 2021 09:49:07 +0200 Subject: [PATCH 059/251] Bugfix for parsing the xml. Now all images (only with non-empty urls though) are loaded. --- modules/skybrowser/src/wwtdatahandler.cpp | 35 +++++++++-------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index dbb2cdf697..4bce1b3724 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -101,17 +101,10 @@ namespace openspace { void WWTDataHandler::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) { // Get direct child of node called "Place" using namespace tinyxml2; - XMLElement* folder = getChildNode(node->FirstChildElement(), "Folder"); + XMLElement* ptr = node->FirstChildElement(); - // Terminate recursion if no folders - if (!folder) { - // When we are at leaf folder - // Iterate through all the :s and :s and load as images - // Go down to the level where places and image sets are - XMLElement* ptr = getChildNode(node->FirstChildElement(), "Place"); - if (!ptr) { - ptr = getChildNode(node->FirstChildElement(), "ImageSet"); - } + // Go through all siblings of ptr and open folders recursively + while (ptr) { // Iterate through all siblings at same level and load while (ptr) { if (std::string(ptr->Name()) == "ImageSet") { @@ -120,21 +113,17 @@ namespace openspace { else if (std::string(ptr->Name()) == "Place") { loadPlace(ptr, collectionName); } + else if (std::string(ptr->Name()) == "Folder") { + std::string newCollectionName = collectionName + "/"; + if (ptr->FindAttribute("Name")) { + newCollectionName += std::string(ptr->FindAttribute("Name")->Value()); + } + loadImagesFromXML(ptr, newCollectionName); + } ptr = ptr->NextSiblingElement(); } } - else { - // Open all folders at same level - while (folder) { - std::string newCollectionName = collectionName + "/"; - if (folder->FindAttribute("Name")) { - newCollectionName += std::string(folder->FindAttribute("Name")->Value()); - } - loadImagesFromXML(folder, newCollectionName); - folder = folder->NextSiblingElement(); - } - } } int WWTDataHandler::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) { @@ -187,6 +176,10 @@ namespace openspace { image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f; image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f; image.thumbnailUrl = getURLFromImageSet(imageSet); + // Only load images that have a thumbnail + if (image.thumbnailUrl == "") { + return -1; + } image.collection = collectionName; images.push_back(image); From 4e358fe122ff7e2935061b8e2246af769751fd57 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 8 Apr 2021 11:18:23 +0200 Subject: [PATCH 060/251] Restructure code for parsing xml to make it more readable --- modules/skybrowser/include/wwtdatahandler.h | 11 +- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- modules/skybrowser/src/wwtdatahandler.cpp | 110 ++++++++++---------- 3 files changed, 64 insertions(+), 59 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 500ca67c5c..fc93c3954b 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -25,15 +25,20 @@ namespace openspace { void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); void loadWTMLCollectionsFromURL(std::string url, std::string fileName); void loadWTMLCollectionsFromDirectory(std::string directory); + int loadAllImagesFromXMLs(); const std::vector& getAllImageCollectionUrls() const; std::vector < std::pair < std::string, std::string> > getAllThumbnailUrls(); - const std::vector& getImages() const; + const std::vector& getLoadedImages() const; private: - int loadPlace(tinyxml2::XMLElement* place, std::string collectionName); - int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName); + + int loadImage(tinyxml2::XMLElement* imageSet, std::string collectionName); + void setImageDataValues(tinyxml2::XMLElement* node, std::string thumbnail, std::string collectionName, ImageData& img); + std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet); + std::string getURLFromPlace(tinyxml2::XMLElement* place); + tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, std::string name); tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); std::vector images; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index ad562c4a9a..b3df686425 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -82,7 +82,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); SkyBrowserModule* module = global::moduleEngine->module(); // If no data has been loaded yet, load it! - if (module->getWWTDataHandler()->getImages().size() == 0) { + if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { moveBrowser(L); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 4bce1b3724..9b3cff79d7 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -107,12 +107,11 @@ namespace openspace { while (ptr) { // Iterate through all siblings at same level and load while (ptr) { - if (std::string(ptr->Name()) == "ImageSet") { - loadImageSet(ptr, collectionName); - } - else if (std::string(ptr->Name()) == "Place") { - loadPlace(ptr, collectionName); + // If node is an image or place, load it + if (std::string(ptr->Name()) == "ImageSet" || std::string(ptr->Name()) == "Place") { + loadImage(ptr, collectionName); } + // If node is another folder, open recursively else if (std::string(ptr->Name()) == "Folder") { std::string newCollectionName = collectionName + "/"; if (ptr->FindAttribute("Name")) { @@ -126,61 +125,27 @@ namespace openspace { } } - int WWTDataHandler::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) { + int WWTDataHandler::loadImage(tinyxml2::XMLElement* node, std::string collectionName) { // Only load "Sky" type images - if (std::string(place->FindAttribute("DataSetType")->Value()) != "Sky") + if (std::string(node->FindAttribute("DataSetType")->Value()) != "Sky") return -1; - std::string url = ""; - // If the place doesn't have a thumbnail url data attribute, - // Load the containing image set instead - if (!place->FindAttribute("Thumbnail")) { - // Traverse the children and look at all their first child to find ImageSet - tinyxml2::XMLElement* child = place->FirstChildElement(); - tinyxml2::XMLElement* imageSet = nullptr; - while (child) { - imageSet = getChildNode(child, "ImageSet"); - if (imageSet) break; - child = child->NextSiblingElement(); - } - // If the place doesn't contain an image, nothing to add - if (!imageSet) return -1; - - // Collect thumbnail url from ImageSet - url = getURLFromImageSet(imageSet); - if (url == "") return -1; + std::string url; + // Get url + if (std::string(node->Name()) == "ImageSet") { + url = getURLFromImageSet(node); } - ImageData image; - // Get attributes for the image - image.name = place->FindAttribute("Name") ? place->FindAttribute("Name")->Value() : ""; - image.celestCoords.x = place->FindAttribute("RA") ? std::stof(place->FindAttribute("RA")->Value()) : 0.f; - image.celestCoords.y = place->FindAttribute("Dec") ? std::stof(place->FindAttribute("Dec")->Value()) : 0.f; - image.thumbnailUrl = url == "" ? place->FindAttribute("Thumbnail")->Value() : url; - image.collection = collectionName; - - images.push_back(image); - // Return index of image in vector - return images.size(); - } - - int WWTDataHandler::loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName) { - std::string type = imageSet->FindAttribute("DataSetType") ? imageSet->FindAttribute("DataSetType")->Value() : ""; - // Only load "Sky" type images - if (type != "Sky") - return -1; - - ImageData image; - - // Get attributes for the image - image.name = imageSet->FindAttribute("Name") ? imageSet->FindAttribute("Name")->Value() : ""; - image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f; - image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f; - image.thumbnailUrl = getURLFromImageSet(imageSet); + else if (std::string(node->Name()) == "Place") { + url = getURLFromPlace(node); + } + // Only load images that have a thumbnail - if (image.thumbnailUrl == "") { + if (url == "") { return -1; } - image.collection = collectionName; + + ImageData image{}; + setImageDataValues(node, url, collectionName, image); images.push_back(image); // Return index of image in vector @@ -194,13 +159,39 @@ namespace openspace { return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; } - tinyxml2::XMLElement* WWTDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) { + std::string WWTDataHandler::getURLFromPlace(tinyxml2::XMLElement* place) { + // Get thumbnail attribute, if there is one + std::string url = place->FindAttribute("Thumbnail") ? place->FindAttribute("Thumbnail")->Value() : ""; + // Url found! Return it + if (url != "") return url; + + // If the place doesn't have a thumbnail url data attribute, + // Load the image set it stores instead + tinyxml2::XMLElement* imageSet = getChildNode(place, "ImageSet"); + // If it doesn't contain an ImageSet, it doesn't have an url -> return empty string + // If there is an imageSet, collect thumbnail url + return imageSet ? getURLFromImageSet(imageSet) : ""; + } + + tinyxml2::XMLElement* WWTDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) { while (node && std::string(node->Name()) != name) { node = node->FirstChildElement(); } return node; } + tinyxml2::XMLElement* WWTDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) { + // Traverse the children and look at all their first child to find ImageSet + tinyxml2::XMLElement* child = node->FirstChildElement(); + tinyxml2::XMLElement* imageSet = nullptr; + while (child) { + imageSet = getDirectChildNode(child, name); + if (imageSet) break; + child = child->NextSiblingElement(); + } + return imageSet; + } + std::vector < std::pair < std::string, std::string> > WWTDataHandler::getAllThumbnailUrls() { std::vector < std::pair < std::string, std::string> > imgResult; std::for_each(images.begin(), images.end(), [&](ImageData obj) { @@ -208,8 +199,17 @@ namespace openspace { }); return imgResult; } + + void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, std::string thumbnail, std::string collectionName, ImageData& img) { + // Get attributes for the image + img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; + img.celestCoords.x = node->FindAttribute("RA") ? std::stof(node->FindAttribute("RA")->Value()) : 0.f; + img.celestCoords.y = node->FindAttribute("Dec") ? std::stof(node->FindAttribute("Dec")->Value()) : 0.f; + img.collection = collectionName; + img.thumbnailUrl = thumbnail; + } - const std::vector& WWTDataHandler::getImages() const { + const std::vector& WWTDataHandler::getLoadedImages() const { return images; } } From 03cb84c0e27a091e577a95e5e1cbb30f822fc24c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 9 Apr 2021 15:03:18 +0200 Subject: [PATCH 061/251] Add amount of data to Image and make image sending process more efficient --- modules/skybrowser/include/wwtdatahandler.h | 3 +- modules/skybrowser/skybrowsermodule_lua.inl | 42 ++++++++++----------- modules/skybrowser/src/wwtdatahandler.cpp | 22 ++++------- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index fc93c3954b..4d292580fd 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -13,6 +13,8 @@ namespace openspace { std::string thumbnailUrl; glm::vec2 celestCoords; std::string collection; + float zoomLevel; + bool hasCoords; }; class WWTDataHandler { @@ -28,7 +30,6 @@ namespace openspace { int loadAllImagesFromXMLs(); const std::vector& getAllImageCollectionUrls() const; - std::vector < std::pair < std::string, std::string> > getAllThumbnailUrls(); const std::vector& getLoadedImages() const; private: diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b3df686425..6f612f24e1 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -1,15 +1,11 @@ #include - - #include #include #include #include #include - #include #include - #include #include #include @@ -22,9 +18,8 @@ #include #include #include - +#include #include -#include namespace { @@ -37,13 +32,14 @@ namespace openspace::skybrowser::luascriptfunctions { int loadImgCollection(lua_State* L) { // Load image ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); - const std::string& imageName = ghoul::lua::value(L, 1); - - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + const int i = ghoul::lua::value(L, 1); + + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + SkyBrowserModule* module = global::moduleEngine->module(); + const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(resultImage.name)); + LINFO("Loading image " + resultImage.name); - browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(imageName)); - LINFO("Loading image " + imageName); - // browser->sendMessageToWWT(browser->createMessageForMovingWWTCamera(glm::vec2(0.712305533333333, 41.269167), 24.0f)); browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 1; } @@ -70,10 +66,12 @@ namespace openspace::skybrowser::luascriptfunctions { LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); - for (const std::string url : imageUrls) { - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); - } + //const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); + //for (const std::string url : imageUrls) { + // browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); + //} + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); return 1; } @@ -86,21 +84,19 @@ namespace openspace::skybrowser::luascriptfunctions { moveBrowser(L); } - std::vector> names = module->getWWTDataHandler()->getAllThumbnailUrls(); + const std::vector& images = module->getWWTDataHandler()->getLoadedImages(); lua_newtable(L); - int number = 1; - for (const std::pair& s : names) { + for (int i = 0; i < images.size(); i++) { // Push a table { image name, image url } with index : number lua_newtable(L); - lua_pushstring(L, s.first.c_str()); + lua_pushstring(L, images[i].name.c_str()); lua_rawseti(L, -2, 1); - lua_pushstring(L, s.second.c_str()); + lua_pushstring(L, images[i].thumbnailUrl.c_str()); lua_rawseti(L, -2, 2); - lua_rawseti(L, -2, number); - ++number; + lua_rawseti(L, -2, i+1); } return 1; diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 9b3cff79d7..01413700e7 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -66,7 +66,7 @@ namespace openspace { for (const auto& entry : std::filesystem::directory_iterator(directory)) { tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - std::cout << entry.path().u8string().c_str() << std::endl; + if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) { xmls.push_back(doc); } @@ -87,10 +87,6 @@ namespace openspace { std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; loadImagesFromXML(root, collectionName); } - - for (ImageData img : images) { - std::cout << img; - } return images.size(); } @@ -192,21 +188,17 @@ namespace openspace { return imageSet; } - std::vector < std::pair < std::string, std::string> > WWTDataHandler::getAllThumbnailUrls() { - std::vector < std::pair < std::string, std::string> > imgResult; - std::for_each(images.begin(), images.end(), [&](ImageData obj) { - imgResult.push_back(std::pair(obj.name, obj.thumbnailUrl)); - }); - return imgResult; - } - void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, std::string thumbnail, std::string collectionName, ImageData& img) { // Get attributes for the image img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; - img.celestCoords.x = node->FindAttribute("RA") ? std::stof(node->FindAttribute("RA")->Value()) : 0.f; - img.celestCoords.y = node->FindAttribute("Dec") ? std::stof(node->FindAttribute("Dec")->Value()) : 0.f; + img.hasCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); + if (img.hasCoords) { + img.celestCoords.x = std::stof(node->FindAttribute("RA")->Value()); + img.celestCoords.y = std::stof(node->FindAttribute("Dec")->Value()); + } img.collection = collectionName; img.thumbnailUrl = thumbnail; + img.zoomLevel = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) : 0.f; } const std::vector& WWTDataHandler::getLoadedImages() const { From fadf20435d10d44e8bbdc4212401da46ade05b49 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 9 Apr 2021 15:04:19 +0200 Subject: [PATCH 062/251] Move conversion function to target and add some utility functions to target and browser --- .../include/screenspaceskybrowser.h | 2 +- .../skybrowser/include/screenspaceskytarget.h | 4 ++ .../skybrowser/src/screenspaceskybrowser.cpp | 43 ++++--------------- .../skybrowser/src/screenspaceskytarget.cpp | 38 ++++++++++++++++ 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 505aa9423b..b5a0f7f5a6 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -27,8 +27,8 @@ namespace openspace { bool sendMessageToWWT(const ghoul::Dictionary& msg); void sendMouseEvent(CefStructBase event, int x, int y) const; void WWTfollowCamera(); - glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; float fieldOfView() const; + void setFieldOfView(float fov); void scrollZoom(float scroll); ScreenSpaceSkyTarget* getSkyTarget(); diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 663f046692..d2a2545be2 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -33,11 +33,15 @@ namespace openspace { void setDimensions(glm::vec2 currentBrowserDimensions); void updateFOV(float browserFOV); + glm::dvec2 convertGalacticToCelestial(glm::dvec3 rGal) const; + glm::vec2 getCelestialCoords(); glm::vec2 getScreenSpacePosition(); glm::vec2 getAnglePosition(); void setConnectedBrowser(); void setBorderColor(glm::ivec3 color); glm::ivec3 getColor(); + + void setPosition(glm::vec3 pos); void translate(glm::vec2 translation, glm::vec2 position); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index fd86b03433..06b1010544 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -20,9 +19,9 @@ #include #include #include // Milliseconds - +#include #include // to adjust camera angle -#include + namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -158,6 +157,10 @@ namespace openspace { return _fieldOfView; } + void ScreenSpaceSkyBrowser::setFieldOfView(float fov) { + _fieldOfView = fov; + } + void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { float zoomFactor = log(_fieldOfView + 1.1f); @@ -260,19 +263,8 @@ namespace openspace { _threadWWTMessages = std::thread([&] { while (_camIsSyncedWWT) { - // Get camera view direction and orthogonal coordinate system of camera view direction - glm::vec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); - glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); - glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); - - glm::vec2 angleOffset = _skyTarget ? _skyTarget->getAnglePosition() : glm::vec2(0); - // Change view if target is moved - glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); - targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); - - // Convert to celestial coordinates - glm::dvec2 celestCoords = convertGalacticToCelestial(targetDirection); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoords, _fieldOfView); + glm::vec2 celestCoordsTarget = _skyTarget ? _skyTarget->getCelestialCoords() : glm::vec2(0.f); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoordsTarget, _fieldOfView); // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); @@ -282,24 +274,7 @@ namespace openspace { }); } - - glm::dvec2 ScreenSpaceSkyBrowser::convertGalacticToCelestial(glm::dvec3 rGal) const { - // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> - // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 - -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 - -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 - }); - - glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; - float ra = atan2(rICRS[1], rICRS[0]); - float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); - - ra = ra > 0 ? ra : ra + (2 * glm::pi()); - - return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); - } + /* void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { glm::vec3 position = _cartesianPosition; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index e649c3cdef..09900d21d8 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include namespace { @@ -241,6 +243,9 @@ namespace openspace { void ScreenSpaceSkyTarget::translate(glm::vec2 translation, glm::vec2 position) { _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); } + void ScreenSpaceSkyTarget::setPosition(glm::vec3 pos) { + _cartesianPosition = pos; + } glm::vec2 ScreenSpaceSkyTarget::getAnglePosition() { glm::vec3 pos = _cartesianPosition.value(); @@ -275,6 +280,39 @@ namespace openspace { } + glm::vec2 ScreenSpaceSkyTarget::getCelestialCoords() { + // Get camera view direction and orthogonal coordinate system of camera view direction + glm::vec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); + glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); + + glm::vec2 angleOffset = getAnglePosition(); + // Change view if target is moved + glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); + targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); + + // Convert to celestial coordinates + return convertGalacticToCelestial(targetDirection); + } + + glm::dvec2 ScreenSpaceSkyTarget::convertGalacticToCelestial(glm::dvec3 rGal) const { + // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> + // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 + -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 + -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 + }); + + glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; + float ra = atan2(rICRS[1], rICRS[0]); + float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); + + ra = ra > 0 ? ra : ra + (2 * glm::pi()); + + return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); + } + void ScreenSpaceSkyTarget::updateFOV(float browserFOV) { float horizFOV = global::windowDelegate->getHorizFieldOfView(); _scale = std::max((browserFOV/horizFOV),(_showCrosshairThreshold.value()/horizFOV)); From 7e81a05bf097de1fb55cddb3792bb7855dc19c53 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 13 Apr 2021 15:42:51 +0200 Subject: [PATCH 063/251] Make target move to look at image coordinate when clicked in GUI --- .../skybrowser/include/screenspaceskytarget.h | 4 +- modules/skybrowser/include/wwtdatahandler.h | 10 +- modules/skybrowser/skybrowsermodule_lua.inl | 160 ++++++++++-------- .../skybrowser/src/screenspaceskytarget.cpp | 12 ++ modules/skybrowser/src/wwtdatahandler.cpp | 16 +- 5 files changed, 126 insertions(+), 76 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index d2a2545be2..63102a70bf 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -44,7 +44,9 @@ namespace openspace { void setPosition(glm::vec3 pos); void translate(glm::vec2 translation, glm::vec2 position); - + // Only works for galactic coords outside of the solar system + void lookAtGalacticCoord(glm::dvec3 galacticCoord); + glm::vec2 getScreenSpaceDimensions(); glm::vec2 getUpperRightCornerScreenSpace(); glm::vec2 getLowerLeftCornerScreenSpace(); diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 4d292580fd..3e94ee7439 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -17,6 +17,12 @@ namespace openspace { bool hasCoords; }; + struct ImageCollection { + std::string name; + std::string url; + bool loaded = false; + }; + class WWTDataHandler { public: @@ -29,7 +35,7 @@ namespace openspace { void loadWTMLCollectionsFromDirectory(std::string directory); int loadAllImagesFromXMLs(); - const std::vector& getAllImageCollectionUrls() const; + const std::vector& getAllImageCollectionUrls() const; const std::vector& getLoadedImages() const; private: @@ -43,7 +49,7 @@ namespace openspace { tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); std::vector images; - std::vector imageUrls; + std::vector imageUrls; std::vector xmls; }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 6f612f24e1..9d5eae5b8c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -20,92 +20,112 @@ #include #include #include - +#include namespace { - constexpr const char _loggerCat[] = "SkyBrowserModule"; + constexpr const char _loggerCat[] = "SkyBrowserModule"; } // namespace namespace openspace::skybrowser::luascriptfunctions { - int loadImgCollection(lua_State* L) { - // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); - const int i = ghoul::lua::value(L, 1); - - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; - browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(resultImage.name)); - LINFO("Loading image " + resultImage.name); - - browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); - return 1; - } - - int followCamera(lua_State* L) { - // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); + int loadImgCollection(lua_State* L) { + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); + const int i = ghoul::lua::value(L, 1); + + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + SkyBrowserModule* module = global::moduleEngine->module(); + const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + // Load image collection, if it isn't loaded already + const std::vector& collections = module->getWWTDataHandler()->getAllImageCollectionUrls(); + auto it = std::find_if(collections.begin(), collections.end(), [&](const ImageCollection& coll) { + return coll.name == resultImage.collection; + }); + if (!it->loaded) { + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(it->url)); + } + browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(resultImage.name)); - SkyBrowserModule* module = global::moduleEngine->module(); - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + LINFO("Loading image " + resultImage.name); + // Only move camera if the image has coordinates + + if (resultImage.hasCoords) { - module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); - LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); + // The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h)=15 + glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x * 15, resultImage.celestCoords.y, 1.0); + browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); - return 1; - } + // In WWT, VFOV = ZoomLevel * 6 + //browser->setFieldOfView(resultImage.zoomLevel * 6); + } + browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); + return 1; + } + + int followCamera(lua_State* L) { + // Load images from url + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::followCamera"); - int moveBrowser(lua_State* L) { - // Load images from local directory - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - SkyBrowserModule* module = global::moduleEngine->module(); - module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); - std::string noOfLoadedImgs = std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs()); - LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); + //SkyBrowserModule* module = global::moduleEngine->module(); + //std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - //const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); - //for (const std::string url : imageUrls) { - // browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); - //} - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); - return 1; - } + //module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); + //LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); - int createBrowser(lua_State* L) { - // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); - SkyBrowserModule* module = global::moduleEngine->module(); - // If no data has been loaded yet, load it! - if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { - moveBrowser(L); - } - - const std::vector& images = module->getWWTDataHandler()->getLoadedImages(); + return 1; + } - lua_newtable(L); + int moveBrowser(lua_State* L) { + // Load images from local directory + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); + SkyBrowserModule* module = global::moduleEngine->module(); + module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); + std::string noOfLoadedImgs = std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs()); + LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); - for (int i = 0; i < images.size(); i++) { - // Push a table { image name, image url } with index : number - lua_newtable(L); - lua_pushstring(L, images[i].name.c_str()); - lua_rawseti(L, -2, 1); - lua_pushstring(L, images[i].thumbnailUrl.c_str()); - lua_rawseti(L, -2, 2); + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + //const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); + //for (const std::string url : imageUrls) { + // browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); + //} + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + return 1; + } - lua_rawseti(L, -2, i+1); - } - - return 1; - } - int adjustCamera(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); + int createBrowser(lua_State* L) { + // Send image list to GUI + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); + SkyBrowserModule* module = global::moduleEngine->module(); + // If no data has been loaded yet, load it! + if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { + moveBrowser(L); + //followCamera(L); + } + + const std::vector& images = module->getWWTDataHandler()->getLoadedImages(); - return 1; - } - + lua_newtable(L); + + for (int i = 0; i < images.size(); i++) { + // Push a table { image name, image url } with index : number + lua_newtable(L); + lua_pushstring(L, images[i].name.c_str()); + lua_rawseti(L, -2, 1); + lua_pushstring(L, images[i].thumbnailUrl.c_str()); + lua_rawseti(L, -2, 2); + + lua_rawseti(L, -2, i+1); + } + + return 1; + } + int adjustCamera(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); + + return 1; + } + } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 09900d21d8..9b4a4cc4f9 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -294,6 +294,18 @@ namespace openspace { // Convert to celestial coordinates return convertGalacticToCelestial(targetDirection); } + + void ScreenSpaceSkyTarget::lookAtGalacticCoord(glm::dvec3 galacticCoord) { + + glm::dmat4 cameraInvRotMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionLocal = cameraInvRotMat * glm::dvec4(galacticCoord, 1.f); + + glm::dvec2 angleCoordsLocal = glm::dvec2(atan(viewDirectionLocal.x / viewDirectionLocal.z), atan(viewDirectionLocal.y / viewDirectionLocal.z)); + double projPlaneDistance = -2.1f; + glm::dvec2 imageCoordsScreenSpace = glm::dvec2(projPlaneDistance * tan(angleCoordsLocal.x), projPlaneDistance * tan(angleCoordsLocal.y)); + // Translate target + translate(glm::vec2(imageCoordsScreenSpace) - getScreenSpacePosition(), getScreenSpacePosition()); + } glm::dvec2 ScreenSpaceSkyTarget::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 01413700e7..08774747aa 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -43,8 +43,12 @@ namespace openspace { XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); // If there are no folders, or there are folder but without urls, stop recursion if (!element || (element && !element->FindAttribute("Url"))) { - - imageUrls.push_back(url); + // Save the url + std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; + if (collectionName != "") { + ImageCollection newCollection{ collectionName, url }; + imageUrls.push_back(newCollection); + } xmls.push_back(doc); LINFO("Saving " + url); @@ -68,6 +72,12 @@ namespace openspace { tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) { + tinyxml2::XMLElement* root = doc->RootElement(); + std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; + if (collectionName != "") { + ImageCollection newCollection{collectionName, entry.path().u8string()}; + imageUrls.push_back(newCollection); + } xmls.push_back(doc); } } @@ -90,7 +100,7 @@ namespace openspace { return images.size(); } - const std::vector& WWTDataHandler::getAllImageCollectionUrls() const { + const std::vector& WWTDataHandler::getAllImageCollectionUrls() const { return imageUrls; } From f6e4c33db3ffd4652d870ae7381449bc1c5a68aa Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 13 Apr 2021 15:54:38 +0200 Subject: [PATCH 064/251] Set the FOV with respect to the image's zoom level --- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 9d5eae5b8c..8e178bb349 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -57,7 +57,7 @@ namespace openspace::skybrowser::luascriptfunctions { browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); // In WWT, VFOV = ZoomLevel * 6 - //browser->setFieldOfView(resultImage.zoomLevel * 6); + browser->setFieldOfView(resultImage.zoomLevel / 6); } browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 1; From 5653823522c0dd0487481e81cbf06a6d17ca5e7b Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 14 Apr 2021 13:20:58 +0200 Subject: [PATCH 065/251] Make it possible to send coordinates to GUI as well as code clean up and conversion of RA from hours to degrees upon data loading --- modules/skybrowser/skybrowsermodule.cpp | 8 +-- modules/skybrowser/skybrowsermodule_lua.inl | 56 ++++++++++++--------- modules/skybrowser/src/wwtdatahandler.cpp | 3 +- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index a1a2c58c2a..74fa57f026 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -65,8 +65,8 @@ namespace openspace { res.name = "skybrowser"; res.functions = { { - "create", - &skybrowser::luascriptfunctions::createBrowser, + "getListOfImages", + &skybrowser::luascriptfunctions::getListOfImages, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " @@ -89,8 +89,8 @@ namespace openspace { "input. An input string should be the name of the system host star" }, { - "loadCollection", - &skybrowser::luascriptfunctions::loadImgCollection, + "selectImage", + &skybrowser::luascriptfunctions::selectImage, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 8e178bb349..c40b3e695e 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -29,9 +29,9 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { - int loadImgCollection(lua_State* L) { + int selectImage(lua_State* L) { // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadCollection"); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); @@ -52,11 +52,10 @@ namespace openspace::skybrowser::luascriptfunctions { if (resultImage.hasCoords) { - // The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h)=15 - glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x * 15, resultImage.celestCoords.y, 1.0); + glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); - // In WWT, VFOV = ZoomLevel * 6 + // In WWT, VFOV = ZoomLevel / 6 browser->setFieldOfView(resultImage.zoomLevel / 6); } browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); @@ -67,11 +66,11 @@ namespace openspace::skybrowser::luascriptfunctions { // Load images from url ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::followCamera"); - //SkyBrowserModule* module = global::moduleEngine->module(); - //std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + SkyBrowserModule* module = global::moduleEngine->module(); + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - //module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); - //LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); + module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); + LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); return 1; } @@ -94,29 +93,40 @@ namespace openspace::skybrowser::luascriptfunctions { return 1; } - int createBrowser(lua_State* L) { + int getListOfImages(lua_State* L) { // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createBrowser"); + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); SkyBrowserModule* module = global::moduleEngine->module(); // If no data has been loaded yet, load it! if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { + // Read from disc moveBrowser(L); - //followCamera(L); + // Read from URL + // followCamera(L); } - + + // Create Lua table to send to the GUI const std::vector& images = module->getWWTDataHandler()->getLoadedImages(); - - lua_newtable(L); + lua_newtable(L); for (int i = 0; i < images.size(); i++) { - // Push a table { image name, image url } with index : number - lua_newtable(L); - lua_pushstring(L, images[i].name.c_str()); - lua_rawseti(L, -2, 1); - lua_pushstring(L, images[i].thumbnailUrl.c_str()); - lua_rawseti(L, -2, 2); - - lua_rawseti(L, -2, i+1); + std::string name = images[i].name != "" ? images[i].name : "undefined"; + std::string url = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; + + // Index for current ImageData + ghoul::lua::push(L, i + 1); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "Name", name); + lua_settable(L, -3); + ghoul::lua::push(L, "Thumbnail", url); + lua_settable(L, -3); + ghoul::lua::push(L, "Ra", images[i].celestCoords.x); + lua_settable(L, -3); + ghoul::lua::push(L, "Dec", images[i].celestCoords.y); + lua_settable(L, -3); + // Set table for the current ImageData + lua_settable(L, -3); } return 1; diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 08774747aa..70e7b9b7b3 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -203,7 +203,8 @@ namespace openspace { img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; img.hasCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); if (img.hasCoords) { - img.celestCoords.x = std::stof(node->FindAttribute("RA")->Value()); + // The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h) = 15 + img.celestCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value()); img.celestCoords.y = std::stof(node->FindAttribute("Dec")->Value()); } img.collection = collectionName; From a9b73fa352ab489d2ce06ed587873ec5f9957add Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 15 Apr 2021 16:22:32 +0200 Subject: [PATCH 066/251] Remove unneccessary while loop --- modules/skybrowser/src/wwtdatahandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 70e7b9b7b3..feca6b9aee 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -110,7 +110,7 @@ namespace openspace { XMLElement* ptr = node->FirstChildElement(); // Go through all siblings of ptr and open folders recursively - while (ptr) { + // Iterate through all siblings at same level and load while (ptr) { // If node is an image or place, load it @@ -128,7 +128,7 @@ namespace openspace { ptr = ptr->NextSiblingElement(); } - } + } int WWTDataHandler::loadImage(tinyxml2::XMLElement* node, std::string collectionName) { From 05a8580edca3e4886ef00f2e42906d556e27540d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 19 Apr 2021 14:30:49 +0200 Subject: [PATCH 067/251] Add functionality to send credits and target data to GUI --- modules/skybrowser/include/wwtdatahandler.h | 6 ++-- modules/skybrowser/skybrowsermodule.cpp | 8 +++++ modules/skybrowser/skybrowsermodule_lua.inl | 40 +++++++++++++++++++-- modules/skybrowser/src/wwtdatahandler.cpp | 35 ++++++++++++------ 4 files changed, 74 insertions(+), 15 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 3e94ee7439..5fa0b18fdb 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -11,6 +11,8 @@ namespace openspace { struct ImageData { std::string name; std::string thumbnailUrl; + std::string credits; + std::string creditsUrl; glm::vec2 celestCoords; std::string collection; float zoomLevel; @@ -41,9 +43,9 @@ namespace openspace { private: int loadImage(tinyxml2::XMLElement* imageSet, std::string collectionName); - void setImageDataValues(tinyxml2::XMLElement* node, std::string thumbnail, std::string collectionName, ImageData& img); + void setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, std::string collectionName, ImageData& img); - std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet); + std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName); std::string getURLFromPlace(tinyxml2::XMLElement* place); tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, std::string name); tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 74fa57f026..e7227f3494 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -104,6 +104,14 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "getTargetData", + &skybrowser::luascriptfunctions::getTargetData, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, }; return res; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index c40b3e695e..1b4f92af91 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -55,7 +55,7 @@ namespace openspace::skybrowser::luascriptfunctions { glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); - // In WWT, VFOV = ZoomLevel / 6 + // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 browser->setFieldOfView(resultImage.zoomLevel / 6); } browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); @@ -121,16 +121,52 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "Thumbnail", url); lua_settable(L, -3); - ghoul::lua::push(L, "Ra", images[i].celestCoords.x); + ghoul::lua::push(L, "RA", images[i].celestCoords.x); lua_settable(L, -3); ghoul::lua::push(L, "Dec", images[i].celestCoords.y); lua_settable(L, -3); + ghoul::lua::push(L, "HasCoords", images[i].hasCoords); + lua_settable(L, -3); + ghoul::lua::push(L, "Credits", images[i].credits); + lua_settable(L, -3); + ghoul::lua::push(L, "CreditsUrl", images[i].creditsUrl); + lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); } return 1; } + + int getTargetData(lua_State* L) { + // Send image list to GUI + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getTargetData"); + + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyTarget1")); + + float FOV = browser->fieldOfView(); + + glm::vec2 coords = target->getCelestialCoords(); + lua_newtable(L); + + // Index for many browsers + // For now it's only one + ghoul::lua::push(L, 1); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "FOV", FOV); + lua_settable(L, -3); + ghoul::lua::push(L, "RA", coords.x); + lua_settable(L, -3); + ghoul::lua::push(L, "Dec", coords.y); + lua_settable(L, -3); + + // Set table for the current ImageData + lua_settable(L, -3); + + return 1; + } int adjustCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index feca6b9aee..e00adc27c4 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -137,31 +137,42 @@ namespace openspace { return -1; std::string url; - // Get url - if (std::string(node->Name()) == "ImageSet") { - url = getURLFromImageSet(node); + std::string credits; + std::string creditsUrl; + tinyxml2::XMLElement* imageSet = nullptr; + // Get url. The thumbnail can be located either in the Place or the ImageSet + if (std::string(node->Name()) == "ImageSet") { + url = getChildNodeContentFromImageSet(node, "ThumbnailUrl"); + imageSet = node; } else if (std::string(node->Name()) == "Place") { url = getURLFromPlace(node); + imageSet = getChildNode(node, "ImageSet"); } - - // Only load images that have a thumbnail - if (url == "") { + else { return -1; } + // Only load images that have a thumbnail + if (url == "" || !imageSet) { + return -1; + } + // The credits are always children nodes of ImageSet + credits = getChildNodeContentFromImageSet(imageSet, "Credits"); + creditsUrl = getChildNodeContentFromImageSet(imageSet, "CreditsUrl"); + ImageData image{}; - setImageDataValues(node, url, collectionName, image); + setImageDataValues(node, credits, creditsUrl, url, collectionName, image); images.push_back(image); // Return index of image in vector return images.size(); } - std::string WWTDataHandler::getURLFromImageSet(tinyxml2::XMLElement* imageSet) { + std::string WWTDataHandler::getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName) { // FInd the thumbnail image url // The thumbnail is the last node so traverse backwards for speed - tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement("ThumbnailUrl"); + tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement(elementName.c_str()); return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; } @@ -176,7 +187,7 @@ namespace openspace { tinyxml2::XMLElement* imageSet = getChildNode(place, "ImageSet"); // If it doesn't contain an ImageSet, it doesn't have an url -> return empty string // If there is an imageSet, collect thumbnail url - return imageSet ? getURLFromImageSet(imageSet) : ""; + return imageSet ? getChildNodeContentFromImageSet(imageSet, "ThumbnailUrl") : ""; } tinyxml2::XMLElement* WWTDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) { @@ -198,7 +209,7 @@ namespace openspace { return imageSet; } - void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, std::string thumbnail, std::string collectionName, ImageData& img) { + void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, std::string collectionName, ImageData& img) { // Get attributes for the image img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; img.hasCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); @@ -210,6 +221,8 @@ namespace openspace { img.collection = collectionName; img.thumbnailUrl = thumbnail; img.zoomLevel = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) : 0.f; + img.credits = credits; + img.creditsUrl = creditsUrl; } const std::vector& WWTDataHandler::getLoadedImages() const { From cbe038e7d45561ed7c27013e8cfd2cbda9320b39 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 21 Apr 2021 10:59:41 +0200 Subject: [PATCH 068/251] Fix bug with field of view by changing all FOVs to VFOV instead of HFOV --- .../include/screenspaceskybrowser.h | 4 ++-- modules/skybrowser/skybrowsermodule_lua.inl | 6 ++--- .../skybrowser/src/screenspaceskybrowser.cpp | 23 ++++++++++--------- .../skybrowser/src/screenspaceskytarget.cpp | 10 +++++--- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index b5a0f7f5a6..ba582cdc46 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -28,7 +28,7 @@ namespace openspace { void sendMouseEvent(CefStructBase event, int x, int y) const; void WWTfollowCamera(); float fieldOfView() const; - void setFieldOfView(float fov); + void setVerticalFieldOfView(float fov); void scrollZoom(float scroll); ScreenSpaceSkyTarget* getSkyTarget(); @@ -49,7 +49,7 @@ namespace openspace { glm::ivec3 getColor(); // Flag for dimensions bool _browserDimIsDirty; - properties::FloatProperty _fieldOfView; + properties::FloatProperty _vfieldOfView; properties::StringProperty _skyTargetID; private: glm::vec2 _startDimensionsSize; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 1b4f92af91..2a03c411b5 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -56,7 +56,7 @@ namespace openspace::skybrowser::luascriptfunctions { browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 - browser->setFieldOfView(resultImage.zoomLevel / 6); + browser->setVerticalFieldOfView(resultImage.zoomLevel / 6); } browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 1; @@ -64,8 +64,8 @@ namespace openspace::skybrowser::luascriptfunctions { int followCamera(lua_State* L) { // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::followCamera"); - + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); + LINFO("Loading images from url"); SkyBrowserModule* module = global::moduleEngine->module(); std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 06b1010544..bdbee1780c 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -65,7 +65,7 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0.f), glm::ivec2(300.f)) - , _fieldOfView(ZoomInfo, 50.f, 0.1f, 70.f) + , _vfieldOfView(ZoomInfo, 50.f, 0.1f, 70.f) , _skyTargetID(TargetIDInfo) , _camIsSyncedWWT(true) , _skyTarget(nullptr) @@ -85,8 +85,8 @@ namespace openspace { }); addProperty(_browserDimensions); - _fieldOfView = p.zoom.value_or(_fieldOfView); - addProperty(_fieldOfView); + _vfieldOfView = p.zoom.value_or(_vfieldOfView); + addProperty(_vfieldOfView); _skyTargetID = p.targetID.value_or(_skyTargetID); addProperty(_skyTargetID); @@ -95,9 +95,9 @@ namespace openspace { setConnectedTarget(); }); - _fieldOfView.onChange([&]() { + _vfieldOfView.onChange([&]() { if (_skyTarget) { - _skyTarget->updateFOV(_fieldOfView); + _skyTarget->updateFOV(_vfieldOfView); } }); @@ -154,18 +154,18 @@ namespace openspace { } float ScreenSpaceSkyBrowser::fieldOfView() const { - return _fieldOfView; + return _vfieldOfView; } - void ScreenSpaceSkyBrowser::setFieldOfView(float fov) { - _fieldOfView = fov; + void ScreenSpaceSkyBrowser::setVerticalFieldOfView(float fov) { + _vfieldOfView = fov; } void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { - float zoomFactor = log(_fieldOfView + 1.1f); + float zoomFactor = log(_vfieldOfView + 1.1f); float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _fieldOfView = std::clamp(_fieldOfView + zoom, 0.001f, 70.0f); + _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); } void ScreenSpaceSkyBrowser::executeJavascript(std::string& script) const { @@ -196,6 +196,7 @@ namespace openspace { ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { using namespace std::string_literals; ghoul::Dictionary msg; + msg.setValue("event", "center_on_coordinates"s); msg.setValue("ra", static_cast(celestCoords[0])); msg.setValue("dec", static_cast(celestCoords[1])); @@ -264,7 +265,7 @@ namespace openspace { while (_camIsSyncedWWT) { glm::vec2 celestCoordsTarget = _skyTarget ? _skyTarget->getCelestialCoords() : glm::vec2(0.f); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoordsTarget, _fieldOfView); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoordsTarget, _vfieldOfView); // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 9b4a4cc4f9..36d983ac0e 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -325,10 +325,14 @@ namespace openspace { return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } - void ScreenSpaceSkyTarget::updateFOV(float browserFOV) { + void ScreenSpaceSkyTarget::updateFOV(float VFOV) { float horizFOV = global::windowDelegate->getHorizFieldOfView(); - _scale = std::max((browserFOV/horizFOV),(_showCrosshairThreshold.value()/horizFOV)); - _fieldOfView = browserFOV; + glm::ivec2 windowRatio = global::windowDelegate->currentWindowSize(); + + float verticFOV = horizFOV * (static_cast(windowRatio.y) / static_cast(windowRatio.x)); + _scale = std::max((VFOV / verticFOV),(_showCrosshairThreshold.value()/ verticFOV)); + + _fieldOfView = VFOV; } } From e05a9802544bc671a7612b168435f7ee1496e405 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 21 Apr 2021 13:41:41 +0200 Subject: [PATCH 069/251] Add a circle which shows where on the sky an image points at --- data/assets/circle.png | Bin 0 -> 18267 bytes data/assets/hoverCircle.asset | 12 ++++++ modules/skybrowser/skybrowsermodule.cpp | 16 ++++++++ modules/skybrowser/skybrowsermodule_lua.inl | 40 ++++++++++++++++++++ modules/skybrowser/src/wwtdatahandler.cpp | 4 -- 5 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 data/assets/circle.png create mode 100644 data/assets/hoverCircle.asset diff --git a/data/assets/circle.png b/data/assets/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..5f3a08e5c5e0106d6ca8a04d7e22c3615d9cc2ab GIT binary patch literal 18267 zcmYg&cT|&26YrBk?;QcDp-4x1N2P@-2-1s4?}!v>NyGvuy?0(fDM}LrL@@CsV4)YK z3K3tLlmw->+=uVnd(QoX6T( zkKO3WWAK9})Yu^$02uKXKagB0MqU6A1d#gIY@$oHexRP0O+`!}5pOWV^W8h~=;eD3 zvO``Dd3WreSh3%>;x^3XaJcPhkm=>rF09$UMC;ni@KBIC#lVW)fEj*Gl@#OB7i#Mi z={fM`wZxlBiK|tgX?vSfq!nNPEAO0F(Cqv~)LvHM@*pE+;)DJ4aJS)spQmL9@x;Hs zP9T)M0!4*4QvNRdEs5QJCy2~)toeKyUEL=&aF4B-f136+q`l_A2_pcgKzJwS%u3T; zp3~txr$)plnjmHnE(}?&M}VRcm_on8EmunPbDcfS%6UwK&bj80_saX!+DBoLa?_Z& zn48d@xNZ=?^2yd#9LX)h`t;}SIeGnf$H2Y%Br&D3fX6e#y0{Q9j=y?0(~V&h9{J*c zD9m{@T#3y+mfr5UYJdPrJqcQ*a?AwolCV{$D^gxPBW3`u=lIVhx-&_4#b%~yx>M?A z@w2!egsN9>X@oDWb)QAVpweokoh_-&7^`0>LNf9MW%f%cP_P{(6dfrMFN{q$24?q_ zbdA~cSwm?LO$p`%_}EiG-s`%c%phE^=*CobywBJo1s^nlPpu%~gP7(0qB{?#uST;S zrmvs*RaygL6yxS*K(%N8#F?YJY72pk2<2^lJUw8i{Tv`Nf5Ev`AFL)fz}TQ~%V^M! zuL3^08ElRS2yz~m8xx;4=PV*hB|q}w1Yn=grUlHkFU){RNxv~SbFH5Ozyia3We615tcEID*2k)Q*^ly=a~wB&%}H`IvW>&D+fZ@Zlt{g zRa!!Xz0kM{x%un9_HvV0+R_h5cfRku(byt&y}>n%5_2nIFUQ=v@u`-Y;HMfA0eW`K>8%d>NDf^20Qio5t=((NvO z9uva$1$U{k9OtR`)&pAMxbC?76g`Jwf<(P6H%BPwUv2Q)tC!Kn$@i^G}CzU^SX)lx36XhUSBR(0vUKyw@ng;#G zRPiRYJalGn_p>1fR0I#%smi0zEySG+&dqFGIUo@WY;aNUdvUcno;pJ=>S)aXxN``JSJ-e*$71t9^PQ!C8ggmn;|RrRKv6a{r^(6bT(SZA7yfN` z)@;p$012*ebM4I;Wa|!eRJd+l7d{V(rn4r-BmC5dS#CTkqk0m= z8pz0ord*Htt!t)qbh%$l7b&F*>9(+erFmq#ixdD#k1Wr!C<(%(_tkTh&nmeG_|k9V z;1w%fWyeJKn5M;=1mxLO3O;c|S}dh=3(rkUF+e%5>^O=!`!oSEou$Z+Y`B+OfB>2L z>aTZJ08H9AfkD3XpCSkV#0@ZCL#fyn@oYYSFNAjHswzwOC)G zfE?$uVEaVj2FR)#G>%6N%ICTKdFIV#J>O9WpEwSc-BHc@io1Cgw1ulHt3)CnAFt9g16 z1%Qp2#vC@gVC~?U{wFNr+YG!#lmsWWE5hnO!Yi&@e<2HowUc$U=H%)e(ysQ1h7QSK zy7?|SL0nwUqhMHl`oqlXm+JcSx85*BgKR!aV;TNLtLN?4JiCpv_K!OK=~aavBXtQ`vzzctc()CE-?#aXZI5Yi=v*&#_`Ip~ zd50&XQC9sDAIV{m}B>mo0EmiV)mkZ#FlmI^gQl% zYiJX4^Lc-livy+Ur6ZJ_QH7KK?!IY@P86p&zH%S)<4#-stoLc_)fIme zB4QRFIL+;Oi@f$O5pbGCKNjF0O|39j#8~Z zCkN@*kb620J7&}-=+3Bj5W4iI9HDv9Uv=kJylZkK0wIyiJy+jjP+&xWF=kY$R>kJe zuG=m>!tokdN!x6V3l{>r_Fbc^%q@qDrRsbP3*4c~J*fa!lK6=t-UHQNQ}FmjwY&D1 zZmYndkh`3f0=I|8m7B4AR0(uyOSp;!dC1y7ZHJ3Ar?d)dMnkGdt#59kCPzMKA|!;3 z?t^OCo^k!_Euj^kQ|e6SKw;L0LLSeq4efKbTqfPKVxPK4bt_5?(9U{!^21#Ed|_oO zP{d4k*-h|eL4102Sl9f@z4MCuKPn!e*B`lyPkg}{Y9)`_)SwsPu1Ylam)Ow!5(D={ zz?1ioIKr0}6Y_9f{8S20H+qmvL2mo;P@|ozS%xOr>QSubUAoueh`~ZxkYehMF9`QSGa&C{A9lY#85zr! zY;i_}h5)NUgn;xm^X8|u^rvtIR7Ezu+S^uFknTsgd$RLsK)}Q45v(yi;Yg97>_MHr ze3oZwM1KH=IJ!c?8}q~ScQb9Z#UQ4h&}O*o`CG-l-AWYWVR&UXYW$8?k!jIt7<05- zSalSY)g_YsoxMW1G=>Hz{O)k-tJ;L+@uy@~@?6=a@7DMC=;rB8Z+Sd(=T%|6U5dnk zCL{gu87k;G>*6U9SQL_FX(_an8jq+OyNruXs(M_y1tE&nie;k>JkgS+#u7oP9jeRZ8-lS1HnOnHrN{~PsK(4TI3#sB3mY1 z#r}%UHFwA>PTs7t!k1~f=nlC$5AFK675*Wzw_wS% zWpj3qbG$&uNO|0f-^WGr$=YzZ3M$dDp)ZXup_1%RiJy5>lOCfAB>tkPqA&BF*nmDf zSg8J~Ztwlxie$Znnxri>7wF+Z*T+!++(%}A3>NP?BM$Rf%$YM=o_@kC!d%0dEF;Eq zslm{ePl@F-5l-5`N$t}W0?zqGF~Oo`r^Eq1i(+$@*i&)zB9*Ib%96)IM)mTB34Fn* zyFak+7EJxJxFp1AR)={Ij^5~ayd}zWuJh0*HvHZ7ob_{b=Ms1?I`x03Wa`cvR^6!x zepqk~E;CfJhPDkM^)}ehZHGj-4(wEMa4?*kVi+(&hd_zb-2-Now(J3>|`0ezehP z#!!oP85-XpXvXknLWb}0T$y@_%Dchc&kLX?)ymcRue^UF-2r2g?~x%W;}aDr;vO4A zhui9iwV7L*SS@6bGlPreqM=2tE^4cjFp#mcOj+=JBu@m?kO9SS* zxsxeE>{p5xpmBWB65(p*s@LWx4}@C|-%rWO+_GZ-<>kOH+W7X2w^G+#Zl7{@f}fC& z3Gj0GF!tXiNJA}9t^GEg)f^Q$wLik)(L~j;Y!BO!$<%fF5#y`G3gApcqPg zfA8S>#Q~SgWUR$zUEKjFNhu>aD(-iFOh`ZQ4^`4s+ijbBiUrUQW@dC+Q}}F1>iN@& zx2S#7&clO&3(~xYlX82uCa*2?ydES^vqtB1`i)Y4TyUb$qCb@(Y3jS(s#0o)W?Ws4 z*PkJO9Q>*DP2D4B#crq0jYonPPPHQ3lBQ+H-eZ=g5xmc{FNp%4)RNobWwp?jCO{@5@GQjJ7)fI5^t?}=cHE|WMZ_xCV*ZR4|Ex4ZR5x(Pzg zRlCy6`-%GCt3P2CL$=9VRy1Fu@-?Fn+&Uo&4+rU#sF#SXFA!0UR|=aZJ^grhA%txF z*2925hLaNF$xjFGMl?NCse{VvOP@0R$5?%Bo|x}nE0H4Q<)CweZz8^go6l3%CS+5b z_0?Z52ga#)JhMq~!5^e3t{vSz#_5Gl`fd~H^X&su)Eg3lezlUk+5qlh1H9E$c7rzzKLNBvO*!NT;(roAg?e&AIH5=>H@FSA)ICGUDTyHyv^#OSyCH5Y(OXmJ2m>B);`% z-iKw5>FA%4rQewYArLG@+)SUFe_o};Fk9;u>KXT za_$5MI~0ah&Ja5=TtWNUMRgJ>uW;db3RR;dLpPa49s(QgXPekJ6B$!IKSCeBhgMbo z>FYr?5+zBUuvaM&cP)cQI+b}_`aBzdYxB6<>f5Y}hZMotA@6MwtNj!$j=3d0!e?90 zKbSo_HTn+Q&HMEJ1VpdiB?k`ml$$`HAAJKv!GO3EGduX*(u(;}r z)1yP0f;#oo5Ry0C1%6l#aW>OB7?{zVCOG7ca2Z%VJ5OkLgd(H z$W~max>D=aW16LF1a*S-LXv-wVv9_VT!U?{-77eHeH?3ao=23l`g78ON0-lT+97}U zG$IJCxYh#rYkUK~W!F)w;=356d3TX5KN+H1PO)%rCm#%uL7zh#4Lx+h-Ng;G(jE$i zqPhy($NgI}B6H7mZ3Ip`g%u8s~jg$4!LNqdH^eg~3gjLzz$`p0r%wXilj7bm?c=y>t=^*zZ;HuGG~H;C2)xq;NL zJ)s$2MV*qKCA5PcHMo)4=SusS%O}khQ*cC`r4U@vH_LO_vAwDz+(ASNX35E+43x;rxHg zeL7i`!lGc9+@x(JPhYct3?ledn2DL|-1kmt2u?gnD&FN(l))@!NZkSfF~aP0 zvwSo35`*8aq|f{+6r0?SRW9tUdv;4-aX7P5LhK%uNL@UbO_Lt@BQe(8lQ#Wt1HQ}p z&JDcRHSw=+w93Qh+9f&Ad-@KZmY{l;q{AFOJu|SfkIBw4j{zQ}stHF+f(si~K&u4z zwgkrUSQuU%DYGf8uuPn(l+b!2a^*dkHpS#)YDf#{zBMIy@W=yc`B{@7v7Y>&D#s(OlAiLoH;d8?p%7T}7 zId+4e2}RYj#zr}AKpCYhXnenQu0LV<2(tvN3-2m|oEDn0NY*O;T1-PB--5SW4njb5 zEa7@2kbae*tYAdpE;F`=3V71w!j+A4(ia(8A8aumf5TxAmd5S8&m*6wULqNr0kMNn z76JFQ&ouu;CDbH`a2KB=ls_Vul!sp8-UU(c-$C1=uh{|L!Q1c&Ub8g#F$dmq3$=qqXEKhxqU zm(~}1$TOv)X#?H4n#{=GRUOGw8b(DU!AbT~C$1FS#?TD!a{;lH^9^r1bbeAi%E-sW z|Mf1088CM0K-f|6|{ojgpKKSODS{ya-_yPI1@6OG<1R!#3ddBgA*&Z=^kn5m0w$lg|a@T7oM zZS+~F|573@FToaa>;kc;i=z)YEjF(?jS!0x%*q*)C$U@5lngNv_>b?$G=|XVeYKAS z4)!(zCZ`Pu2T4*1XH;@^Z^r`&VN1$m4QSp5;UdV%o5u?yv^bv1qakeqYB@Z=W9z{bM+~7i{`52=BF{G_jQR<}T+^~!rAsEJN*S+k zT&4=!7ljxPp*kS3Cp$+0o025S$TQP%hVk3D4g42?w<_d*fsQllWD_mUamn$Ut&NjRwi$)FRwPdGsO?t8HG~`BbEQ~j41`( zAhc=YN_#X|r#C>R308sU8wH5{)(;NskMGKg`emk6c2dS&=7qj*fa)OA)8PBk5aU#u z_h`-7J#}6%CHNH2iAMPO1yXm)BXW$!%jW)J2-c0gukS+mA1`Pyi~TA7 zpCmna-3=HHq$~jIzl#=xwA_ToC)`45r7XBdYx6x-%J~tJ%q1&ze$4|*(dx}`UobRU;Qfll~FDBhBmZ{srg|LnnM(* z+im9Pj1Voaxuy|I7I_B)^LQ=b$T^3P6xXC0fcsy`QaWj)fQbGo+3BK{vXxdoNMwwz z`8DOKD+18%_;+NCy%*PU`A7K6bM1xB%>_KpAoO2 z_xXT*X&+v9Q4X{%ehkYXb;xI~V5W8U{y+{H@6AD=3`jOP&3Xk$A%WX4-PVWcAt_-? z|E5eSeiA|k{n5A$(cl-{rnb+@MF7RgJJ_Ho{zKRZXuyQ~rPONWnt8O-=JU**)ynY> z;6+Y1j!M3*Bt0a9hQLnp-_}FaJ$4mubSnSMXA~S@-_L*CO?ER^iVS zFBx&AJRHy5-hObW0h&-G`g&ua4!GYa6!@MFCjgprA?V)xUx9}yn#kPrC8(pi4n2Sb zo+R-m%?8p(Q>kTw?W~`Yo^0;SV?5i_xko!BOih5UujJx9Zkq{b=sCUxo0a3n^Y6Ym zJ|Mif0mk^^ZOk>(20;2j`ahVLN!m4F(n}cGwM{)nua>KxHowp-Jhirr0D_3;9Y>Z~ z^{ZN80;Y4t5Ta-1CkR(5P+djw9$h*>Uw=iG*@ql-o?V?{-1G(YC>x^M`uP{yv<`SJ z9DMH7I$z6!ThT?*ncPm4Lt5v$Ale~@_o%Y0 zR@DgI0jC~Pz^kOcUW*p*S+zGi}f_bV3%z z%u}MB3RYtXeF$J9S-P@87KZY^V4*62mvC>}{^~6CX4!`7syQ%zPKLPGe!BMUix**N z{+e-C-X`}JKW!VWnwp&m!9x;w8pCVZ@SM$#?D`qp#C~5u$^xYus+=akZ3wxoqh<1| zE#ZWboLPMw#tS6rpuKE?+ciwVucUBJ?-DZ*GEQ?(p<6JO!F^sjQ9yI$7{^&4{H8w} zG){!foR>$2lT!!eJ4o3Q^Ss-@6?^6 zOXt1uv@aPoPRO?|#y5PXSyJw4@D75P$U*E4HZQk*Y3;P`)70BSWiiV9HsQ|O5ciT4Jt zcu0pj5hK*q{&IoT6ROiOHZzDZ>7{clLRlZoVziz39xSy3<4q$PY84cQ7{zU}sr9e6 zcTDco(=%su;i5pe1*1PE0Oz*Mcs*+}JZKwcPqA5aMAte)^Li^*?VBg80--!{Y4!(| zJPMl81rPD(^kv}%M8U}YdvNh9fLw8cz&UfE1^8~t+bS9=k>9>W>Sq--4jn+H{pl(i z*uaDrHu8d<+r{G0h0!@xJ7_Zsz}SpYw-_Oi{x8GzDJoK#V&*W)rR9Tp06m143RKYZ zr6Uy5|Fsg6d%^UdpyF@1v|&qcQ=olhXCp|SvSj4)BSc-(dCGn;%$W!)2>NGHp;JxL z>tQFfvwR)MGk`!|cR|~$lqIc@n^`Q*CAu~XQIUJbnX9Kb(W%K=fD1a4XpndpH0LU^u7_nzL z{t^}gRHqdV)ghfD*i;y_R-L_UoMoZ$<{ zY%vf>B?VkA71Kjn(^Z!>1+*#BOjC;imu~}zy7+#-)weh?z{Tw1iy`LA{58*JhF}Xo z#fuuzfpo8yNNFE_oLAlM9{_Ep>|#Z~kyafWz64y@f~NWCuna)xr$EKGOZ<6rDu>+K zUGxQ6?^J-;7t5q{_hYaFpti5jNddULK&$_hk$e=Hh&tuj&Q;wBb{Sa+GHdn=E!rHN zRn7T^O0X@G$vDe#Q&Of8h^58d0yS})A7*y$3K9?4(gi^AX5ic$ph6MIhVfD$aD>w! zq2UKC3-LCa13eAvD$=AzW>MB@LZ%DA$w8Qc@2~h#kaR#Sl)w%OFBKsUylOSb96^l1 zC6Lyy?u!F+Zw!RMF<(L5WI29@>w&$mLO{>-7*q$+Ux*C=|6HpH;U40Aj6m|#Zo_eO zVPFGI$Ny~(f#x9IX3*$q8VQh~ zzBgVhpkGE88#){e^&4GnJnMWOmX)QNFKP0F9o{gyp0F@XNXdAnWx^ zxak}2$%O+|GX6n>Grph-3mm>!q-Wn5@$b*6{&0io!LdhUU2TvNK%;1zZwM8 z|7g0mk1oIo(7`gGEsTfY=>E(IB3h^1K0XY0PkCSg0srW}s)LTWaL)|*#hOx36<{cS zXa8?{&;sRj*@fJCfmNkU@x7%21%R0o)8>Wd>#$$nIN#7By={TY&mVncpwY8pzl9@f zulY*;d%<5X;}W+!@5zV8^waV!CX_!KWAi13AaG#>lTn(!M44vti@%98tmtqUeYMGV zh^97;ATqV1cwYtnXDwsd&{18edlT35y&-K8bnY?}%R)%&#OgD$z{?&Q+`%{x)1V8) zcf(3ANfP(r!eU~Ad3Q28!0Xl}vzD6_f|n@8jxU=V1i|-LF60ZR@+D4?B^2vVz=Pp# zTL*13~B$_@q}K$dM_uJq#Y^bv}{I+Cb1end)$$5DO{X0jGyZ7@fo7lSiS3|#0LXv>0LoGCvv2*^! z-v5qFSfFR@iW&kr(2*JG1}M>#6g_|foEE@KwCV|~wRRvhc<5p?%rLU9lILRTH-tm) zv@hD5K}kJjPj3m_z@37z3tnhYarVK699!)nfJ)8KYj?!)4j%@+M0L z7xMz-9QBx^6)S1KXAYCI33A}e?F~s}#N8v^ee$Z-SL`&LFcQOQady8Q!nneypVj6Y zBuDPmIw3b7VhgI;I+%dUN4vj*VaC>b4(C)$I^}o6x5&N1tmxg3HOc?z1u5%$W(UcN zBCTEQ&z~ydj*iX~`*g-EAWe;GCC82iW^k<>Fi;lE9jUR4n$D8zz9%%By$f616Jn|>>ufO2r z<6lKYa4j5%W&)E=f(ZI$@&nz23=! z8HnnPc5kAXMc~^R3DU}SP%XRKSyu?3-(2@k+r#@3&MrKS%hXI|&|i{3(%9J)=U)L? zWk>;}X zU6&Q@nPUu{4diHM>y!d#M(ndWwStF0*31>cq{lw_&I1}fAKr>BjUjXpnMxcv1EQRG zipd%Y>GoAzUg|XHPmo>>cezaP7Vu}n?{iSy{g-eRDpEdSqG0!5R}3&eLA%xZ2Eez2?04& z3Hzy6+#oCli_t|R7#6O1NVRWuv{^6*{HZ)3-zlWglT;{yT1c<{;`Npyxen@y`nivf zVap+ro{TSOhXL_?>+`3%TZLxOMf;DRRQq_AsK3VFh9LahgCUGR=TYc<2gAGPCTwWC zq=1KW!;;_}#xchz-4=?u$ZVWI3;vJpYe9(dizjrrvE_s`%JoKQw6I>*@rGb1clkNw z38o|85u8AvxInNSGMk_Z;LiYJ@0kSXEGLi1LUG5$=wvUI|C*E_YxERd-T#hEz+WXx z;?6)8>Oz7oLwN5|Swn6~SDj$*8i2B>JAagVsM!warrH9?-|u#J$*qSxb72s*mXbfZ zyWaQ4;UshLDpCvG>;+lf>)pbWl*`Y1rCz)9kEF1n!E0;s9OS9p@jD(5Iuieqt3T43 z2}~;z2QQl%m;u<4s{`cG_cLEa^hF-NjD=jFC(O6q5p^J+*fBqXeGIi*o~tO3tuHpd z&kNO5Vf$Ox05u+`&GmZ6Qhx3eQ^b+>i--gt_%b?np5W4K@o~RTE;^*l9HFXS>3@r# zu_TYqZLod9gzS<2e*59Qq>o#;xUjo`6etb>owF!SD7{?A3AQSq1_xJ2pB}^A;Rq8Z zoPlTj*-J^JXapG7x^h60zV=6DGWJY`NOa~67>DXkDbMykY69J3&glV&})!rR&kIXO&oVRg~|BC zuW#nfy1i%hmK-uT1$h_{rT9EYJr-lE7NgZi9>XQ?Q~RJIP{ ze&Dm7RT{l1ifbdg$Kg}+oG;%yfSI=q@KFIwZhY&8b$@%df=x@X0R*q+hOj21Uv5G8 zuMCX;eVwIr!~ZlkskT5vf6Gui0G!Pfno$q$7Rs`0 z_*q&`@4bQoRus`G9K({q6%BZ^jl>Hz)ElRw1pe*E&U8ba*KGf~87;D+8&4n$n^RM@ zb+-5*Oggxum80ada-6ypmt6^rB?r2r^-9aIe?@y+I09rptgb#Dd7{`l=URJ z26a*uysx4i4006!y~*AOSKv9c(ZyPr2Z?LA9IS#a?jACCG@WIxQsw-IFY6&|eAnHY zMUYeg9aaO~bW8OW#wlqANTbP{)To0V16Jn(U->LJN};YVjIznzJo-?1i+QKGJAm7( z;3w$!VP?(Mc~=JRaVTsb^hU3sRBquX$jh#(8rwLq z1=q1~-d9X|I@YCb`uu!rZaF6L*i?Y(gGGtgWGa|NcT2CnE1xy#>xVd|O7`~sbT+*0 zcO1IgG^Yn<#d{7JNvDDzTp5BO{0IvQH9=$RyDzqe-=mp;xvNia+4kyx>s~b?cQL%# zylSWfbLAsUz0P*g7vB^*fgqHpT?tlvhl=G*kk#X(T_%_rV9h~b--ix*afC?{6i)jy zCiVP^|FRGwwf?B)-|-+>F4n9ucI|jP=VsE$w=clqdjZuIeDF8Gwd>#b)=&RAXR;|{YW zgXbUc39l;Q+m)YZ9m?ItbBhbzoxMC{59g6_3UsQ zdnc9Lap8y`<>4;V(G$7nET~b%!Vd|TUsEtb1mp(p8LilZ=@4);P;2Rz94%&nlNQ52 zP?ubuoY3_&0mcPLd+wT9vS>NE^rBsr0!9_4!cu#YP&srkS=mqX$2@ znYhktnpGbtKtgseMJc2KMj+a7Z9@0Ik+1zp#ZXJHw5s3VnG+SIUtG{@-3{}YZ!#)e zjk**K?acf2%*Pz)ss}8`YfjR5Jz--8C!rur=ptdR_+ski)8zN&aixya;kaT0tKF@B z?9qRX0Pa2q!4rHebLSmnB2}1Uvg#2GvhUNm_gld?^N7&AX{f*uhu%J1&=w*Kb#upE z&QN|!1>#T3v!SB4*LdtB3#Jbiv(-y93J?|_OHJ7BwSF!G5Whg+b^!P|i?P*D9IC;@ zcI((%Te#d!5D=GD3LjtmcY(6Z2YmzOeJlBYgtODGgAY%Px7ikb%Z2(W=Dei*2p}p6 z9WAJCMlU~c+Mk?qaCA-Jq_~ci2GH|=s79%k_zB8&mmv(lqKLagq|eCt=;~qm#})UX zy6*u)bS`b+1G}IxZi){k&dKj}!=)oeFL7xxKF{}hptYKiRlN_M3rtq~*zy9$`o}Ip zW#@9M3CB-qZ2`h@#7Cc`@XVRksv>(MgjqRdaM;a^>IAR=gKLa*z}&13D&>!KsPt3| zwy?g_{y7T+#t1y&L^hHO=gR;6np~~(n`ig0yep}dT|9Z1EPWy4J1{?MAj@J4@Itwo z!ox;?)hUT1wQcj3RS2sSbKeJlPJZETd0E;xt`fA&3Un?oNAvMQ^ZnUK0Lk7VFO5EL zQt<+cRd%eKmY9(D+slLC^8GGK(e^6D*f8mdo;X}~XfI^krarrx11XZAYrJ`K6568F zYg4<^Re`d6DZTj&By@ne*rhvUB z@avT(Ox987-5aavCV4F<_*|-f69IZPH}4am$`-@6eNC9D60}WXZRT z&`mILPp89028vv)~6T0Kp$cDGY=BoeIEp|LjH)p`qB;Wh`4b;;&MnV;? zri4wlF_voWjQeRsDIw-T-b31UY}PXPf+dAaMB5NLnb`wo{Kp!LUP1Fig>boO+wuMGToI~gEU_i_CDB4nwKoY4I( z>*8nv0pLEE5tb8M%|C`V0Rfoa^|P)w(r&UTl`5BBSHD1h`*1_Qbwg0Q1wk-~xU1jWhedG8%Z%_41b3o3+ocD%QYveAk8F{qc6rM&1dGZ|R8lR}-^`vOQ+9k*OFEl!VBlhLC z*X7R5mr##lr+Qj=4-J-(AMZZ2P6fMXPZNpH_ZzmphdefexWQcO!++i1VnchfN3%rh zLW(smlt-h?{ySt#lHIY3BpgPZiXmN;@;5?tU(d!*?QM3Y~#O^uk&OAdVv(+ zoBG3P+Cy{qTPqnw9t>fw(IO=9R*r?2ygt#5tE;ny5zla+l88SdKtN%RLghL!RnqP6 zd;3%*ASg>OIq-*rAOIutwnW#dMly5J1i{KcD8rrxF&=52%@Y{~OJ_ca->g)h>$a6Q zDA9<`OZnem6Ci8&@ik2})t@KhYBzA&_{ruiKUZAepaQZXpC^KeRg^q@P#d!$pY(%p(fdo}3AXzNU%wuy(1=B1cxvlc}4jIEMi8P12Rx zCUD#4X%-~-89)ILm8Y@9ySB(YboF=B0RA$=BH${MQu$p(@dY24*D^O#jek_@zFm3b z)bXxV{Cl#`vr6CHv#SkA@E8dze2O8LstMPg7XibNCe}Hqc#)$?c8rX&!s3n1y~QUJ z=2Sl=!|rVk1V#J$*@9Ai@=Smp+Dcb3e6?L#*bITnX=oW2InBP&(#ru6cxA`h3sb0H zI5KiDgx z3nB8pw!^rI*Jm~Sw(<`G6+C; z^c!|5cm5+A@^&DcN&(y+f)FW8)2SJ*78H@}%X-R~NnfJKa`P5gPNAQ3f=Y|tn!y;I z+*7lVJ~x`}JWQkkLgNi_m+?D#R20h!U+xQ&sPKaS+`hk5e|en3tAoYz^eMX3etTq@ zU4eTWEQ>S@r^SDv_3SNy^rK(l2uG$G+S}HqW9ZI<2kU0LJa+3_Y z5<75`Vj3L1pCchrU)0@hB~+=Dx|<@dc)IC*jw-@0xULl?z9YZm>XAdtdwq?@@Xjo{&o9OU>+yNd)1SO~2G699#-b%fwRb>6I9xQ>It%$oiIwbxo;rEp zo0yoBX>iix`i5vjMF%ErYI(N5_K=CMr{GA6~=cSmLL|Dt$XNU?V;-*z63^n#dmG00na zLmRjS1U0x@2U(@Am9uUoZQ)Lm*luXHylYBvKIL+UHlslVpa^~)P(1Z766~idhkYEW-lLk=* z)BJ}wmKreu>WS9cFOCGMFy-FIeki(T6(8rKDG8D$jt$rRj681!a9$CGIAPpyhzeQ5 zB#}oo$@RDZd_1h--Il3oe%U^__9x_=0-86e5`X8W?Se}C$aMH6;%$N!Sc?D-Y8OKf zm@#o4vk@W)Z!D>P8^@k>uv(sUu!tsp_0LVpAi-NhRLp&J4;tHbSW2t|7wv` zOrM?0;CFfiL^#hH4%^&RWzPpd@#$T(AxvyYbPeox&4kpbAKz&>fje~Evtp(zjril^ zZYB1y{qE)2Te@~=6qOc5Nz{&;78}~@Pm+6;8MB;lep1jwERe>Ui@EK_InG{JNCd2A z$zhd+O@FJ2m2PhQdrlBGG>1HmZ#9x232q9ia}ko5!UIyhoc!KsL?9@aQBog@PT`*r zwq`N6`@dPZ$Q)N8_Cncc!wm#1Kbfm|0(X$?NdN(CcQ4(&mA@O`iRp|y0EZRwkG9fG zC&eC{FD)&?z5|4@;{dun^>K%zFZyq%ABIdQ1Rb5Z^`MIo_Y31uTe~mWMZ{ zdlqf-(IZgovuETKu=vL~<{A%lTRaQh^FYM9+?@3b&h}*o{V;$+J{Q#qP`pE|&N}B@ zI`NkSD}IM!Z{R1+3@f38TM4bD;=y~doasA_1vGl;pdZTYq&m${wz&JY7aqpG&NGqx z(SgvE^oYQBn}+kns}gMDdS3#Q!gC+k#Iv(wGaK1q((nEGqOrrVTnoHO$g~uM zh?yLg3Sghv?>oN&3tXYr`zS&v2<8w08-TDqe{i##iCVD&uD>qx_jrwkzp-L`C> zlk~t8J9P0|hTO$t^LH9M#@RkuW?a#awAKebu6u8lo91|ioi7l>%N|3q*%3gBzrrF~() zq_L_7rzeH(8igfh*zZR>aCwJ3uLDt|Qpp>imUrLfvCSEJ{N(?A{C4{wAPF@U(6#VA z^32{b%`RD-tg3ZyP5^v^(vwWwrqVHg&a`h}b@m;}s3B(W3T@WtiQtT`TYL#tzdpfs zIG>(;g1hU1XCrKrk{_mXO-UJ<^)eOa1}g&=uB3Qqg=?jPr7U_b2hUNDYAFMUcry{U z{kDWfm>YB$gr>CMP)(r4ayQ@K^;0AXhGi4B!Qw&d$W_b;3@o2LE6G;?z>>U+GL{nh zL(vir!MdIWq5Ts#c;n>Jbifa=A}`0AVje`29uR0C$gO)hYrDEjm&hOga=RP)-Ny0a z)wc)mUe`DN7>a_A(2#EZoU`<~_4212Xj)@&cstt=CjD-BMfFM-ZCs)6v~B7q0HEBv z_`d-AngKN^9Wj7oEaC+z9_NFGT@)^sY0||pM)P-iwz|23ZP~J{U8QPb(M-V;#`V}M z9$0cK=#JL>i_flxht(B;C(rn0Xns=hQbO5`5#Gf5@^i=t#0{|MTyz892PGvL7-pd$ z*gd6_%O&ggf6^@^T_)$yPRqAoO{D#AI(y4OnzcY0wR9KjZ|2PTM_LfR-Yk@8Auy@e zW#%hRq7F;Prg*F8ay@6+S*hod)=PlGJ+E1hb3( z-J}ARh=SLV%gyPXwxm1Vwl}R4z(PcdGU)L1njI5ZdO8W#D#%$eOqZ()BW3o*b|%S^ z3ImI+XUbrS=iPN#j1$_DwT9xN6w&(Gb6^Cl0VRU*Q;|BqOeT%q&c0v)A-*Z%xvfQ~aXw zC!cEMLAp8iu)v>>rKXdFNID_;S|ix?fi1=bg_0 zIT;9JiRO>yQF}~>?E>2@Tv8uC#aRAQx>hIK#dSV`|Cg8=--V$;b54Gfh-S*9R@2q1 ze<_6Zz0n ztO16IxpB7A0V~}wqc)uG@mh| zy#FNdI&c-3aDb0`%>+Pwmj()TZx1|5Y!6r!kfvP$UICtB`gT6c{OTJM01Zsq9_Wl2 zK0s6j?kDaWuqvQ7ngWK2IsM-P&SIHg17ZT8EK*gVGhy&)2Ew&D z7 z9+N~D|BJxy0VjcRT=Z1~CIG6Xu4G^}kpSES{2V3&>c1(XYyVZ^Y5y2D^QneR091Q3 zl7U^su%Y)8vj#j?s9qQc&Jc_K9}`#ajuDH#`}(RS696?zN(MR!!7gIPz)u4QfsHtD zNQ*N?bnhPp{)p(_A5OpSlfD|k1VD||l?<#R?j*Pc_$lI&qFd6hNgbW1{3F13h^PEf zV$q*+(O1)$0H`%)Bm|p?BZfaoBn10#yP%CaXY{`Vyhc3bPvU~F7BB%&Yt2Xqwi4R} zorGXFHWN0{2+^s36!z0ZgAHSVwFX+yeYidcPM>8}!>0)1~}l!1su!`}1AD?_w`4zyv^Ap;;1xT|{-@ z$I|;-fNi*iuvC-84E@tYDgQqMXVcrc^!tE|y|f%A08*cHB?bUPL?6M9^!E2>{CtRZ zRt-8+^*RgtUopMFpCcOdu5+Q6ddCDn%3wxv0I-2b2(}Rk!Mm7F4t5a77VDNEOc7=I z5#S2(G(Q6T9kIBdAr||Q&Ih=_OM_zqAk{!wmg|WmU=uOGXf4s0xC+<;{0~G=!lv{g z+tcrDOmC}+ #include #include +#include #include #include #include @@ -61,6 +62,45 @@ namespace openspace::skybrowser::luascriptfunctions { browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 1; } + + int moveCircleToHoverImage(lua_State* L) { + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); + const int i = ghoul::lua::value(L, 1); + + ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); + hoverCircle->property("Enabled")->set(true); + SkyBrowserModule* module = global::moduleEngine->module(); + const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + + if (resultImage.hasCoords) { + + glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); + // This is a duplicate of target function "lookAtGalacticCoord". Probably should rewrite this so there are no duplicates... + glm::dmat4 cameraInvRotMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionLocal = cameraInvRotMat * glm::dvec4(imageCoordsGalactic, 1.f); + + glm::dvec2 angleCoordsLocal = glm::dvec2(atan(viewDirectionLocal.x / viewDirectionLocal.z), atan(viewDirectionLocal.y / viewDirectionLocal.z)); + double projPlaneDistance = -2.1f; + glm::dvec2 imageCoordsScreenSpace = glm::dvec2(projPlaneDistance * tan(angleCoordsLocal.x), projPlaneDistance * tan(angleCoordsLocal.y)); + // Translate target + hoverCircle->translate(glm::vec2(imageCoordsScreenSpace) - hoverCircle->getScreenSpacePosition(), hoverCircle->getScreenSpacePosition()); + } + + return 1; + } + + int disableHoverCircle(lua_State* L) { + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); + LINFO("YO"); + ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); + LINFO("YAH"); + hoverCircle->property("Enabled")->set(false); + LINFO("Yu"); + return 1; + } + int followCamera(lua_State* L) { // Load images from url diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index e00adc27c4..46e2af616a 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -6,10 +6,6 @@ namespace { constexpr const char* _loggerCat = "WWTDataHandler"; - - - - } //namespace namespace openspace { From b7c4d94df071e6e74c3af59af29bf0e87a44f77f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 26 Apr 2021 14:26:39 +0200 Subject: [PATCH 070/251] Use doubles for coordinates and some bugfixes --- data/assets/hoverCircle.asset | 3 +- modules/skybrowser/include/wwtdatahandler.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 23 ++++++++++++++ modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 29 ++++++++--------- .../skybrowser/src/screenspaceskybrowser.cpp | 2 +- modules/skybrowser/src/wwtdatahandler.cpp | 31 +++++++++---------- 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index 91b16db98c..d21f18fba3 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -7,6 +7,7 @@ local assetHelper = asset.require('util/asset_helper') FaceCamera = false, Scale= 0.015, Enabled = false, - TexturePath = "D:/Ylvas/OpenSpace/data/assets/circle.png" + TexturePath = "D:/Ylvas/OpenSpace/data/assets/circle.png", + CartesianPosition = { 0, 0, -2.1 }, }; assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 5fa0b18fdb..885c3487a9 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -13,7 +13,7 @@ namespace openspace { std::string thumbnailUrl; std::string credits; std::string creditsUrl; - glm::vec2 celestCoords; + glm::dvec2 celestCoords; std::string collection; float zoomLevel; bool hasCoords; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f7ba805bc5..66d5d3636b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -45,6 +45,8 @@ #include +#define _USE_MATH_DEFINES +#include namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -330,6 +332,27 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { dataHandler = new WWTDataHandler(); } +glm::dvec3 SkyBrowserModule::icrsToGalacticCartesian(double ra, double dec, double distance) { + // Convert to Galactic Coordinates from ICRS right ascension and declination + // https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/ + // chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 + -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 + -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 + }); + double degToRad = M_PI / 180.0; + + glm::dvec3 rICRS = glm::dvec3( + cos(ra * degToRad) * cos(dec * degToRad), + sin(ra * degToRad) * cos(dec * degToRad), + sin(dec * degToRad) + ); + glm::dvec3 rGalactic = conversionMatrix * rICRS; // on the unit sphere + + return distance * rGalactic; +} + glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { glm::vec2 size = global::windowDelegate->currentWindowSize(); // Change origin to middle of the window diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index e0c5a351b4..8722adc11a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -50,6 +50,7 @@ public: glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; + glm::dvec3 icrsToGalacticCartesian(double ra, double dec, double distance); WWTDataHandler* getWWTDataHandler(); scripting::LuaLibrary luaLibrary() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index bf8e4a0fb7..4606f177d6 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -53,14 +53,14 @@ namespace openspace::skybrowser::luascriptfunctions { if (resultImage.hasCoords) { - glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); + glm::dvec3 imageCoordsGalactic = module->icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 browser->setVerticalFieldOfView(resultImage.zoomLevel / 6); } browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); - return 1; + return 0; } int moveCircleToHoverImage(lua_State* L) { @@ -75,7 +75,7 @@ namespace openspace::skybrowser::luascriptfunctions { if (resultImage.hasCoords) { - glm::dvec3 imageCoordsGalactic = icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); + glm::dvec3 imageCoordsGalactic = module->icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); // This is a duplicate of target function "lookAtGalacticCoord". Probably should rewrite this so there are no duplicates... glm::dmat4 cameraInvRotMat = global::navigationHandler->camera()->viewRotationMatrix(); glm::dvec3 viewDirectionLocal = cameraInvRotMat * glm::dvec4(imageCoordsGalactic, 1.f); @@ -87,18 +87,15 @@ namespace openspace::skybrowser::luascriptfunctions { hoverCircle->translate(glm::vec2(imageCoordsScreenSpace) - hoverCircle->getScreenSpacePosition(), hoverCircle->getScreenSpacePosition()); } - return 1; + return 0; } int disableHoverCircle(lua_State* L) { - // Load image ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); - LINFO("YO"); ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); - LINFO("YAH"); hoverCircle->property("Enabled")->set(false); - LINFO("Yu"); - return 1; + + return 0; } @@ -108,8 +105,9 @@ namespace openspace::skybrowser::luascriptfunctions { LINFO("Loading images from url"); SkyBrowserModule* module = global::moduleEngine->module(); std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; - module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); + module->getWWTDataHandler()->loadWTMLCollectionsFromURL(hubble, "root"); LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); return 1; @@ -129,7 +127,8 @@ namespace openspace::skybrowser::luascriptfunctions { // browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); //} std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(hubble)); return 1; } @@ -140,9 +139,9 @@ namespace openspace::skybrowser::luascriptfunctions { // If no data has been loaded yet, load it! if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { // Read from disc - moveBrowser(L); + //moveBrowser(L); // Read from URL - // followCamera(L); + followCamera(L); } // Create Lua table to send to the GUI @@ -171,6 +170,8 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "CreditsUrl", images[i].creditsUrl); lua_settable(L, -3); + ghoul::lua::push(L, "Index", i); + lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); } @@ -210,7 +211,7 @@ namespace openspace::skybrowser::luascriptfunctions { int adjustCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); - return 1; + return 0; } } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index bdbee1780c..7482f25d7e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -163,7 +163,7 @@ namespace openspace { void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { - float zoomFactor = log(_vfieldOfView + 1.1f); + float zoomFactor = 0.25f*log(_vfieldOfView + 1.1f); float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 46e2af616a..c685c6da7b 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -106,24 +106,23 @@ namespace openspace { XMLElement* ptr = node->FirstChildElement(); // Go through all siblings of ptr and open folders recursively - - // Iterate through all siblings at same level and load - while (ptr) { - // If node is an image or place, load it - if (std::string(ptr->Name()) == "ImageSet" || std::string(ptr->Name()) == "Place") { - loadImage(ptr, collectionName); - } - // If node is another folder, open recursively - else if (std::string(ptr->Name()) == "Folder") { - std::string newCollectionName = collectionName + "/"; - if (ptr->FindAttribute("Name")) { - newCollectionName += std::string(ptr->FindAttribute("Name")->Value()); - } - loadImagesFromXML(ptr, newCollectionName); + // Iterate through all siblings at same level and load + while (ptr) { + // If node is an image or place, load it + if (std::string(ptr->Name()) == "ImageSet" || std::string(ptr->Name()) == "Place") { + loadImage(ptr, collectionName); + } + // If node is another folder, open recursively + else if (std::string(ptr->Name()) == "Folder") { + std::string newCollectionName = collectionName + "/"; + if (ptr->FindAttribute("Name")) { + newCollectionName += std::string(ptr->FindAttribute("Name")->Value()); } + loadImagesFromXML(ptr, newCollectionName); + } - ptr = ptr->NextSiblingElement(); - } + ptr = ptr->NextSiblingElement(); + } } From dcbd74ab7a8f8d0f2d4279a23857e3e109002c5e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 30 Apr 2021 09:24:34 +0200 Subject: [PATCH 071/251] Fix offset bug by changing how the target direction is calculated. Move calculations to utility file --- modules/skybrowser/CMakeLists.txt | 2 + .../include/screenspaceskybrowser.h | 4 +- .../skybrowser/include/screenspaceskytarget.h | 20 ++--- modules/skybrowser/skybrowsermodule.cpp | 41 ---------- modules/skybrowser/skybrowsermodule.h | 6 +- modules/skybrowser/skybrowsermodule_lua.inl | 53 ++++++------- .../skybrowser/src/screenspaceskybrowser.cpp | 36 +++++---- .../skybrowser/src/screenspaceskytarget.cpp | 79 +++++-------------- 8 files changed, 77 insertions(+), 164 deletions(-) diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 0241bd1178..f61c79f15b 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -31,6 +31,7 @@ set(HEADER_FILES include/screenspaceskytarget.h include/wwtdatahandler.h tinyxml2/tinyxml2.h + include/utility.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -43,6 +44,7 @@ set(SOURCE_FILES src/screenspaceskytarget.cpp src/wwtdatahandler.cpp tinyxml2/tinyxml2.cpp + src/utility.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index ba582cdc46..877212294c 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -18,8 +18,8 @@ namespace openspace { bool setConnectedTarget(); // Communication with the webpage and WWT - void executeJavascript(std::string& script) const; - ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly = true) const; + void executeJavascript(std::string script) const; + ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly = true) const; ghoul::Dictionary createMessageForPausingWWTTime() const; ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; ghoul::Dictionary createMessageForSettingForegroundWWT(const std::string& name) const; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 63102a70bf..172a5845f2 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -33,24 +33,18 @@ namespace openspace { void setDimensions(glm::vec2 currentBrowserDimensions); void updateFOV(float browserFOV); - glm::dvec2 convertGalacticToCelestial(glm::dvec3 rGal) const; - glm::vec2 getCelestialCoords(); - glm::vec2 getScreenSpacePosition(); - glm::vec2 getAnglePosition(); + glm::dvec3 getTargetDirection(); + glm::dvec2 getScreenSpacePosition(); void setConnectedBrowser(); void setBorderColor(glm::ivec3 color); glm::ivec3 getColor(); - - void setPosition(glm::vec3 pos); - void translate(glm::vec2 translation, glm::vec2 position); - // Only works for galactic coords outside of the solar system - void lookAtGalacticCoord(glm::dvec3 galacticCoord); + void translate(glm::dvec2 translation, glm::dvec2 position); - glm::vec2 getScreenSpaceDimensions(); - glm::vec2 getUpperRightCornerScreenSpace(); - glm::vec2 getLowerLeftCornerScreenSpace(); - bool coordIsInsideCornersScreenSpace(glm::vec2 coord); + glm::dvec2 getScreenSpaceDimensions(); + glm::dvec2 getUpperRightCornerScreenSpace(); + glm::dvec2 getLowerLeftCornerScreenSpace(); + bool coordIsInsideCornersScreenSpace(glm::dvec2 coord); glm::mat4 scaleMatrix() override; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 66d5d3636b..240fc87029 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -45,8 +45,6 @@ #include -#define _USE_MATH_DEFINES -#include namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -313,7 +311,6 @@ SkyBrowserModule::SkyBrowserModule() void SkyBrowserModule::internalDeinitialize() { delete dataHandler; - } void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { @@ -332,27 +329,6 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { dataHandler = new WWTDataHandler(); } -glm::dvec3 SkyBrowserModule::icrsToGalacticCartesian(double ra, double dec, double distance) { - // Convert to Galactic Coordinates from ICRS right ascension and declination - // https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/ - // chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 - -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 - -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 - }); - double degToRad = M_PI / 180.0; - - glm::dvec3 rICRS = glm::dvec3( - cos(ra * degToRad) * cos(dec * degToRad), - sin(ra * degToRad) * cos(dec * degToRad), - sin(dec * degToRad) - ); - glm::dvec3 rGalactic = conversionMatrix * rICRS; // on the unit sphere - - return distance * rGalactic; -} - glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { glm::vec2 size = global::windowDelegate->currentWindowSize(); // Change origin to middle of the window @@ -381,23 +357,6 @@ WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { return dataHandler; } -glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { - // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> - // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 - -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 - -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 - }); - - glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; - float ra = atan2(rICRS[1], rICRS[0]); - float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); - - ra = ra > 0 ? ra : ra + (2 * glm::pi()); - - return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); -} /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 8722adc11a..fd8f11b9ad 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -33,6 +33,10 @@ #include #include + +#include +#include + namespace openspace { class ScreenSpaceSkyBrowser; @@ -49,8 +53,6 @@ public: virtual ~SkyBrowserModule() = default; glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); - glm::dvec2 convertGalacticToCelestial(glm::dvec3 coords) const; - glm::dvec3 icrsToGalacticCartesian(double ra, double dec, double distance); WWTDataHandler* getWWTDataHandler(); scripting::LuaLibrary luaLibrary() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4606f177d6..14154056d1 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -16,12 +17,13 @@ #include #include #include +#include #include #include #include #include -#include #include +#include namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; @@ -39,6 +41,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Load image collection, if it isn't loaded already + // TODO: Update or remove with new WWT API const std::vector& collections = module->getWWTDataHandler()->getAllImageCollectionUrls(); auto it = std::find_if(collections.begin(), collections.end(), [&](const ImageCollection& coll) { return coll.name == resultImage.collection; @@ -46,20 +49,18 @@ namespace openspace::skybrowser::luascriptfunctions { if (!it->loaded) { browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(it->url)); } + LINFO("Loading image " + resultImage.name); browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(resultImage.name)); - - LINFO("Loading image " + resultImage.name); - // Only move camera if the image has coordinates - + browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); + + // Only move target if the image has coordinates if (resultImage.hasCoords) { - - glm::dvec3 imageCoordsGalactic = module->icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); - browser->getSkyTarget()->lookAtGalacticCoord(imageCoordsGalactic); - + glm::dvec2 imageCoordsScreenSpace = skybrowser::J2000ToScreenSpace(resultImage.celestCoords.x, resultImage.celestCoords.y); + browser->getSkyTarget()->property("CartesianPosition")->set(glm::vec3 {imageCoordsScreenSpace, skybrowser::SCREENSPACE_Z }); + // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 - browser->setVerticalFieldOfView(resultImage.zoomLevel / 6); + browser->setVerticalFieldOfView(resultImage.zoomLevel / 6); } - browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); return 0; } @@ -67,24 +68,17 @@ namespace openspace::skybrowser::luascriptfunctions { // Load image ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); const int i = ghoul::lua::value(L, 1); - - ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); - hoverCircle->property("Enabled")->set(true); SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + // Only move and show circle if the image has coordinates if (resultImage.hasCoords) { - - glm::dvec3 imageCoordsGalactic = module->icrsToGalacticCartesian(resultImage.celestCoords.x, resultImage.celestCoords.y, 1.0); - // This is a duplicate of target function "lookAtGalacticCoord". Probably should rewrite this so there are no duplicates... - glm::dmat4 cameraInvRotMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionLocal = cameraInvRotMat * glm::dvec4(imageCoordsGalactic, 1.f); - - glm::dvec2 angleCoordsLocal = glm::dvec2(atan(viewDirectionLocal.x / viewDirectionLocal.z), atan(viewDirectionLocal.y / viewDirectionLocal.z)); - double projPlaneDistance = -2.1f; - glm::dvec2 imageCoordsScreenSpace = glm::dvec2(projPlaneDistance * tan(angleCoordsLocal.x), projPlaneDistance * tan(angleCoordsLocal.y)); - // Translate target - hoverCircle->translate(glm::vec2(imageCoordsScreenSpace) - hoverCircle->getScreenSpacePosition(), hoverCircle->getScreenSpacePosition()); + // Make circle visible + ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); + hoverCircle->property("Enabled")->set(true); + // Calculate coords for the circle and translate + glm::vec2 imageCoordsScreenSpace = skybrowser::J2000ToScreenSpace(resultImage.celestCoords.x, resultImage.celestCoords.y); + hoverCircle->property("CartesianPosition")->set(glm::vec3 {imageCoordsScreenSpace, skybrowser::SCREENSPACE_Z }); } return 0; @@ -122,6 +116,7 @@ namespace openspace::skybrowser::luascriptfunctions { LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); + // Load all image collection urls //const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); //for (const std::string url : imageUrls) { // browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); @@ -188,7 +183,8 @@ namespace openspace::skybrowser::luascriptfunctions { float FOV = browser->fieldOfView(); - glm::vec2 coords = target->getCelestialCoords(); + glm::dvec3 coords = target->getTargetDirection(); + glm::dvec2 celestCoords = skybrowser::galacticCartesianToJ2000(coords); lua_newtable(L); // Index for many browsers @@ -198,9 +194,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Push ("Key", value) ghoul::lua::push(L, "FOV", FOV); lua_settable(L, -3); - ghoul::lua::push(L, "RA", coords.x); + ghoul::lua::push(L, "RA", celestCoords.x); lua_settable(L, -3); - ghoul::lua::push(L, "Dec", coords.y); + ghoul::lua::push(L, "Dec", celestCoords.y); lua_settable(L, -3); // Set table for the current ImageData @@ -210,7 +206,6 @@ namespace openspace::skybrowser::luascriptfunctions { } int adjustCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); - return 0; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 7482f25d7e..008fd07864 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -64,7 +65,7 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) - , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0.f), glm::ivec2(300.f)) + , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0), glm::ivec2(300)) , _vfieldOfView(ZoomInfo, 50.f, 0.1f, 70.f) , _skyTargetID(TargetIDInfo) , _camIsSyncedWWT(true) @@ -110,9 +111,8 @@ namespace openspace { } identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - // The projection plane seems to be located at z = -2.1 so at that place the ScreenSpaceRenderables behaves like - // they are in screen space - _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.1f)); + + _cartesianPosition.setValue(glm::dvec3(_cartesianPosition.value().x, _cartesianPosition.value().y, skybrowser::SCREENSPACE_Z)); // Always make sure that the target and browser are visible together _enabled.onChange([&]() { @@ -168,7 +168,7 @@ namespace openspace { _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); } - void ScreenSpaceSkyBrowser::executeJavascript(std::string& script) const { + void ScreenSpaceSkyBrowser::executeJavascript(std::string script) const { //LINFOC(_loggerCat, "Executing javascript " + script); if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) { CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); @@ -193,14 +193,14 @@ namespace openspace { } - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const float fov, const bool moveInstantly) const { + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly) const { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "center_on_coordinates"s); - msg.setValue("ra", static_cast(celestCoords[0])); - msg.setValue("dec", static_cast(celestCoords[1])); - msg.setValue("fov", static_cast(fov)); + msg.setValue("ra", celestCoords.x); + msg.setValue("dec", celestCoords.y); + msg.setValue("fov", fov); msg.setValue("instant", moveInstantly); return msg; @@ -236,8 +236,6 @@ namespace openspace { return msg; } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForPausingWWTTime() const { using namespace std::string_literals; @@ -263,14 +261,20 @@ namespace openspace { // Start a thread to enable user interaction while sending the calls to WWT _threadWWTMessages = std::thread([&] { while (_camIsSyncedWWT) { + if (_skyTarget) { + // Calculate the galactic coordinate of the target direction + // with infinite radius + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + constexpr double infinity = std::numeric_limits::max(); + glm::dvec3 galCoord = camPos + (infinity * _skyTarget->getTargetDirection()); + glm::dvec2 celestCoordsTarget = skybrowser::galacticCartesianToJ2000(galCoord); + ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoordsTarget, _vfieldOfView); - glm::vec2 celestCoordsTarget = _skyTarget ? _skyTarget->getCelestialCoords() : glm::vec2(0.f); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoordsTarget, _vfieldOfView); - + sendMessageToWWT(message); + } + // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(50)); - sendMessageToWWT(message); - } }); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 36d983ac0e..b1c3c3a5ab 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -102,8 +103,8 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - // Projection plane seems to be at -2.1. The browser is at -2.1 and the browser should have precedence over target - _cartesianPosition.setValue(glm::vec3(_cartesianPosition.value().x, _cartesianPosition.value().y, -2.11f)); + _cartesianPosition.setValue(glm::dvec3(_cartesianPosition.value().x, _cartesianPosition.value().y, skybrowser::SCREENSPACE_Z)); + //_useRadiusAzimuthElevation.setValue(true); // Always make sure that the target and browser are visible together _enabled.onChange([&]() { @@ -240,36 +241,27 @@ namespace openspace { unbindTexture(); } - void ScreenSpaceSkyTarget::translate(glm::vec2 translation, glm::vec2 position) { - _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); + void ScreenSpaceSkyTarget::translate(glm::dvec2 translation, glm::dvec2 position) { + _cartesianPosition = glm::translate(glm::dmat4(1.f), glm::dvec3(translation, 0.0f)) * glm::dvec4(position, _cartesianPosition.value().z, 1.0f); } - void ScreenSpaceSkyTarget::setPosition(glm::vec3 pos) { - _cartesianPosition = pos; - } - - glm::vec2 ScreenSpaceSkyTarget::getAnglePosition() { - glm::vec3 pos = _cartesianPosition.value(); - return glm::vec2(atan(pos.x / pos.z), atan(pos.y / pos.z)); - } - - glm::vec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { + glm::dvec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); } - glm::vec2 ScreenSpaceSkyTarget::getScreenSpaceDimensions() { - return glm::vec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); + glm::dvec2 ScreenSpaceSkyTarget::getScreenSpaceDimensions() { + return glm::dvec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); } - glm::vec2 ScreenSpaceSkyTarget::getUpperRightCornerScreenSpace() { + glm::dvec2 ScreenSpaceSkyTarget::getUpperRightCornerScreenSpace() { - return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0f); + return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0); } - glm::vec2 ScreenSpaceSkyTarget::getLowerLeftCornerScreenSpace() { - return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0f); + glm::dvec2 ScreenSpaceSkyTarget::getLowerLeftCornerScreenSpace() { + return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0); } - bool ScreenSpaceSkyTarget::coordIsInsideCornersScreenSpace(glm::vec2 coord) { + bool ScreenSpaceSkyTarget::coordIsInsideCornersScreenSpace(glm::dvec2 coord) { bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; return lessThanUpperRight && moreThanLowerLeft; @@ -277,53 +269,18 @@ namespace openspace { void ScreenSpaceSkyTarget::setDimensions(glm::vec2 currentBrowserDimensions) { _targetDimensions = currentBrowserDimensions; - } - glm::vec2 ScreenSpaceSkyTarget::getCelestialCoords() { + glm::dvec3 ScreenSpaceSkyTarget::getTargetDirection() { // Get camera view direction and orthogonal coordinate system of camera view direction - glm::vec3 viewDirection = global::navigationHandler->camera()->viewDirectionWorldSpace(); - glm::vec3 upDirection = global::navigationHandler->camera()->lookUpVectorWorldSpace(); - glm::vec3 sideDirection = glm::cross(upDirection, viewDirection); + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 targetPosWorldSpace = glm::inverse(global::navigationHandler->camera()->combinedViewMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0); + glm::dvec3 targetDirection = glm::normalize(targetPosWorldSpace - camPos); - glm::vec2 angleOffset = getAnglePosition(); - // Change view if target is moved - glm::vec3 targetDirection = glm::rotate(viewDirection, angleOffset.x, upDirection); - targetDirection = glm::rotate(targetDirection, angleOffset.y, sideDirection); - - // Convert to celestial coordinates - return convertGalacticToCelestial(targetDirection); + return targetDirection; } - void ScreenSpaceSkyTarget::lookAtGalacticCoord(glm::dvec3 galacticCoord) { - glm::dmat4 cameraInvRotMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionLocal = cameraInvRotMat * glm::dvec4(galacticCoord, 1.f); - - glm::dvec2 angleCoordsLocal = glm::dvec2(atan(viewDirectionLocal.x / viewDirectionLocal.z), atan(viewDirectionLocal.y / viewDirectionLocal.z)); - double projPlaneDistance = -2.1f; - glm::dvec2 imageCoordsScreenSpace = glm::dvec2(projPlaneDistance * tan(angleCoordsLocal.x), projPlaneDistance * tan(angleCoordsLocal.y)); - // Translate target - translate(glm::vec2(imageCoordsScreenSpace) - getScreenSpacePosition(), getScreenSpacePosition()); - } - - glm::dvec2 ScreenSpaceSkyTarget::convertGalacticToCelestial(glm::dvec3 rGal) const { - // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> - // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 - -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 - -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 - }); - - glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; - float ra = atan2(rICRS[1], rICRS[0]); - float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); - - ra = ra > 0 ? ra : ra + (2 * glm::pi()); - - return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); - } void ScreenSpaceSkyTarget::updateFOV(float VFOV) { float horizFOV = global::windowDelegate->getHorizFieldOfView(); From dc0dcd2eb7d903a18ffca9a89cf0b765ce2639e2 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 30 Apr 2021 09:26:33 +0200 Subject: [PATCH 072/251] Add utility files --- modules/skybrowser/include/utility.h | 33 ++++++++++++ modules/skybrowser/src/utility.cpp | 77 ++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 modules/skybrowser/include/utility.h create mode 100644 modules/skybrowser/src/utility.cpp diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h new file mode 100644 index 0000000000..2a9b0068d4 --- /dev/null +++ b/modules/skybrowser/include/utility.h @@ -0,0 +1,33 @@ +#include +#include +#include +#include // For atan2 +#include // For printing glm data +#define _USE_MATH_DEFINES +#include + + +namespace openspace::skybrowser { + const double SCREENSPACE_Z = -2.1; + const double RAD_TO_DEG = 180.0 / M_PI; + const double DEG_TO_RAD = M_PI / 180.0; + + // Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.054875539390, 0.494109453633, -0.867666135681, // col 0 + -0.873437104725, -0.444829594298, -0.198076389622, // col 1 + -0.483834991775, 0.746982248696, 0.455983794523 // col 2 + }); + + // J2000 to galactic conversion and vice versa + glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); + glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); + glm::dvec2 galacticCartesianToJ2000(glm::dvec3 rGal); + glm::dvec3 J2000ToGalacticCartesian(double ra, double dec, double distance); + glm::dvec2 J2000ToScreenSpace(double ra, double dec); + + glm::dvec2 galacticToScreenSpace(glm::dvec3 galacticCoord); +} + + + diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp new file mode 100644 index 0000000000..913e8089c8 --- /dev/null +++ b/modules/skybrowser/src/utility.cpp @@ -0,0 +1,77 @@ + +#include +#include +#include +#include +#include // For atan2 +#include // For printing glm data +#define _USE_MATH_DEFINES +#include + + + +namespace openspace::skybrowser { + + glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) { + + glm::dvec3 cartesian = glm::dvec3( + cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), + sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), + sin(sphericalCoords.y * DEG_TO_RAD) + ); + + return cartesian; + } + + glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) { + + double ra = atan2(cartesianCoords[1], cartesianCoords[0]); + double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1]))); + + ra = ra > 0 ? ra : ra + (2 * M_PI); + + return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec); + } + + glm::dvec2 galacticCartesianToJ2000(glm::dvec3 rGal) { + glm::dvec3 J2000 = glm::transpose(conversionMatrix) * rGal; + return cartesianToSpherical(J2000); + } + + glm::dvec3 J2000ToGalacticCartesian(double ra, double dec, double distance) { + glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(glm::dvec2(ra, dec)); // on the unit sphere + return distance * rGalactic; + } + + glm::dvec2 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { + + // Transform vector to camera's local coordinate system + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 camToCoordsDir = glm::normalize(imageCoordsGalacticCartesian - camPos); + glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); + viewDirectionLocal = glm::normalize(viewDirectionLocal); + + // Calculate screen space coords x and y + long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z; + long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z; + + glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y)); + glm::dvec2 imageCoordsScreenSpace = glm::dvec2(SCREENSPACE_Z * static_cast(std::tanl(angleCoordsLocal.x)), SCREENSPACE_Z * static_cast(std::tanl(angleCoordsLocal.y))); + + return imageCoordsScreenSpace; + } + + glm::dvec2 J2000ToScreenSpace(double ra, double dec) { + // Transform equatorial J2000 to galactic coord with infinite radius + constexpr double infinity = std::numeric_limits::max(); + glm::dvec3 imageCoordsGalacticCartesian = J2000ToGalacticCartesian(ra, dec, infinity); + // Transform galactic coord to screen space + glm::dvec2 imageCoordsScreenSpace = galacticToScreenSpace(imageCoordsGalacticCartesian); + return imageCoordsScreenSpace; + } + + } + + + From 72d931e68d4840e55280cc7a4000dbc41b4ba1fe Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 30 Apr 2021 09:34:48 +0200 Subject: [PATCH 073/251] Remove duplicate of translate function --- modules/skybrowser/include/screenspaceskytarget.h | 2 -- modules/skybrowser/src/screenspaceskytarget.cpp | 3 --- 2 files changed, 5 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 172a5845f2..d4f593e4e9 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -38,8 +38,6 @@ namespace openspace { void setConnectedBrowser(); void setBorderColor(glm::ivec3 color); glm::ivec3 getColor(); - - void translate(glm::dvec2 translation, glm::dvec2 position); glm::dvec2 getScreenSpaceDimensions(); glm::dvec2 getUpperRightCornerScreenSpace(); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index b1c3c3a5ab..bdc181e3ee 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -241,9 +241,6 @@ namespace openspace { unbindTexture(); } - void ScreenSpaceSkyTarget::translate(glm::dvec2 translation, glm::dvec2 position) { - _cartesianPosition = glm::translate(glm::dmat4(1.f), glm::dvec3(translation, 0.0f)) * glm::dvec4(position, _cartesianPosition.value().z, 1.0f); - } glm::dvec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); } From 94101b783c4e85aa5e7346e20d6f7931bf10511c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 30 Apr 2021 10:17:07 +0200 Subject: [PATCH 074/251] Update submodules from master to solve merge conflict issues --- apps/OpenSpace/ext/sgct | 2 +- ext/ghoul | 2 +- modules/kameleon/ext/kameleon | 2 +- support/coding/codegen | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index eefd275cce..669fbc16a9 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit eefd275ccec15c9316e4bc91d7232f3beea083a2 +Subproject commit 669fbc16a9910b28333427f5e07235baa43ea7a6 diff --git a/ext/ghoul b/ext/ghoul index 1625701baa..8f17cc57d9 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 1625701baa17a568163d96a3532489d306d18e0e +Subproject commit 8f17cc57d95cb5682aed07e087feb47d06824503 diff --git a/modules/kameleon/ext/kameleon b/modules/kameleon/ext/kameleon index 8a5e966659..606edb945b 160000 --- a/modules/kameleon/ext/kameleon +++ b/modules/kameleon/ext/kameleon @@ -1 +1 @@ -Subproject commit 8a5e9666599e9578d50bf3801dd07a9edf95ccdb +Subproject commit 606edb945b62d0151f20270ddb2db4a9f558aaa1 diff --git a/support/coding/codegen b/support/coding/codegen index b3c0a745fa..4b06f1ad45 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit b3c0a745fa68e5f762de8a06732038e3a6fd5e02 +Subproject commit 4b06f1ad4586289f0f1523915e11b1c81fe21202 From 7ea8ba0d3b5af0c27503ebff4dfd859d7d2a76b4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 30 Apr 2021 15:05:52 +0200 Subject: [PATCH 075/251] Place browser in left bottom corner of screen on startup --- data/assets/skyBrowser.asset | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/assets/skyBrowser.asset b/data/assets/skyBrowser.asset index fdb723616c..0ae4db96ff 100644 --- a/data/assets/skyBrowser.asset +++ b/data/assets/skyBrowser.asset @@ -6,7 +6,8 @@ local assetHelper = asset.require('util/asset_helper') Name = "SkyBrowser", Url = "http://localhost:8000/", FaceCamera = false, - TargetID = "SkyTarget1" + TargetID = "SkyTarget1", + CartesianPosition = {-1.0, -0.5, -2.1} }; assetHelper.registerScreenSpaceRenderables(asset, { spec }) From 70642b0a55839d449b072b1eee462edb19a6decb Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 30 Apr 2021 15:06:44 +0200 Subject: [PATCH 076/251] Fine tune the zooming function --- modules/skybrowser/src/screenspaceskybrowser.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 008fd07864..73c150fa4a 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -162,8 +162,9 @@ namespace openspace { } void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { - - float zoomFactor = 0.25f*log(_vfieldOfView + 1.1f); + // Make scroll more sensitive the smaller the FOV + float x = _vfieldOfView; + float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); } From 2eecb08bcf0d89cf02a5eac5ffe5f00ae5be623d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 4 May 2021 09:14:35 +0200 Subject: [PATCH 077/251] Add random colored borders to browsers and targets that are sufficiently bright, and add function to pass them to GUI --- .../include/screenspaceskybrowser.h | 5 +- .../skybrowser/include/screenspaceskytarget.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 10 ++++ modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 52 ++++++++++++------- .../skybrowser/src/screenspaceskybrowser.cpp | 34 +++++++++--- .../skybrowser/src/screenspaceskytarget.cpp | 10 +++- 7 files changed, 82 insertions(+), 32 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 877212294c..e4b9a68f31 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -51,15 +51,14 @@ namespace openspace { bool _browserDimIsDirty; properties::FloatProperty _vfieldOfView; properties::StringProperty _skyTargetID; + properties::Vec3Property _borderColor; private: glm::vec2 _startDimensionsSize; float _startScale; properties::Vec2Property _browserDimensions; bool _camIsSyncedWWT; ScreenSpaceSkyTarget* _skyTarget; - std::thread _threadWWTMessages; - glm::ivec3 _borderColor; - + std::thread _threadWWTMessages; }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index d4f593e4e9..1a2a69b264 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -59,7 +59,7 @@ namespace openspace { GLuint _vertexBuffer = 0; float _fieldOfView = 100.f; ScreenSpaceSkyBrowser* _skyBrowser; - glm::vec3 _borderColor; + glm::ivec3 _borderColor; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 240fc87029..17e09e934a 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -357,6 +357,16 @@ WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { return dataHandler; } +std::vector SkyBrowserModule::getSkyBrowsers() { + std::vector browsers; + for (ScreenSpaceRenderable* renderable : renderables) { + if (to_browser(renderable)) { + browsers.push_back(to_browser(renderable)); + } + } + return browsers; +} + /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index fd8f11b9ad..a9158cfee9 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -54,6 +54,7 @@ public: glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); + std::vector getSkyBrowsers(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 14154056d1..616bd140a4 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -178,29 +178,41 @@ namespace openspace::skybrowser::luascriptfunctions { // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getTargetData"); - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - ScreenSpaceSkyTarget* target = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyTarget1")); + SkyBrowserModule* module = global::moduleEngine->module(); - float FOV = browser->fieldOfView(); - - glm::dvec3 coords = target->getTargetDirection(); - glm::dvec2 celestCoords = skybrowser::galacticCartesianToJ2000(coords); lua_newtable(L); + int index = 1; + // Pass data for all the browsers and the corresponding targets + std::vector browsers = module->getSkyBrowsers(); - // Index for many browsers - // For now it's only one - ghoul::lua::push(L, 1); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "FOV", FOV); - lua_settable(L, -3); - ghoul::lua::push(L, "RA", celestCoords.x); - lua_settable(L, -3); - ghoul::lua::push(L, "Dec", celestCoords.y); - lua_settable(L, -3); - - // Set table for the current ImageData - lua_settable(L, -3); + for (int i = 0; i < browsers.size(); i++) { + // Only add browsers that have an initialized target + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (target) { + glm::dvec3 coords = target->getTargetDirection(); + glm::dvec2 celestCoords = skybrowser::galacticCartesianToJ2000(coords); + // Convert color to vector so ghoul can read it + glm::ivec3 color = browsers[i]->_borderColor.value(); + std::vector colorVec = { color.r, color.g, color.b }; + + ghoul::lua::push(L, index); + index++; + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "FOV", browsers[i]->fieldOfView()); + lua_settable(L, -3); + ghoul::lua::push(L, "RA", celestCoords.x); + lua_settable(L, -3); + ghoul::lua::push(L, "Dec", celestCoords.y); + lua_settable(L, -3); + ghoul::lua::push(L, "Color", colorVec); + lua_settable(L, -3); + + // Set table for the current ImageData + lua_settable(L, -3); + } + } + return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 73c150fa4a..b929b443c8 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -44,6 +44,12 @@ namespace { "Target Info", "tjobidabidobidabidopp plupp" }; + constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = + { + "BorderColor", + "Border color Info", + "tjobidabidobidabidopp plupp" + }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -56,6 +62,9 @@ namespace { // [[codegen::verbatim(TargetIDInfo.description)]] std::optional targetID; + + // [[codegen::verbatim(BorderColorInfo.description)]] + std::optional borderColor; }; #include "screenspaceskybrowser_codegen.cpp" @@ -66,12 +75,19 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0), glm::ivec2(300)) - , _vfieldOfView(ZoomInfo, 50.f, 0.1f, 70.f) + , _vfieldOfView(ZoomInfo, 10.f, 0.1f, 70.f) + , _borderColor(BorderColorInfo, glm::ivec3(rand() % 256, rand() % 256, rand() % 256)) , _skyTargetID(TargetIDInfo) , _camIsSyncedWWT(true) , _skyTarget(nullptr) - , _borderColor(220, 220, 220) { + // Ensure the color of the border is bright enough. + // Make sure the RGB color at least is 50% brightness + // By making each channel 50% bright in general + // 222 = sqrt(3*(0.5*256)^2) + while (glm::length(_borderColor.value()) < 222) { + _borderColor = glm::ivec3(rand() % 256, rand() % 256, rand() % 256); + } // Handle target dimension property const Parameters p = codegen::bake(dictionary); _browserDimensions = p.browserDimensions.value_or(_browserDimensions); @@ -145,7 +161,13 @@ namespace openspace { } bool ScreenSpaceSkyBrowser::setConnectedTarget() { + setBorderColor(_borderColor.value()); _skyTarget = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyTargetID.value())); + if (_skyTarget) { + _skyTarget->setBorderColor(_borderColor.value()); + _skyTarget->updateFOV(_vfieldOfView.value()); + _skyTarget->setDimensions(getBrowserPixelDimensions()); + } return _skyTarget != nullptr; } @@ -178,7 +200,7 @@ namespace openspace { } glm::ivec3 ScreenSpaceSkyBrowser::getColor() { - return _borderColor; + return _borderColor.value(); } void ScreenSpaceSkyBrowser::setBorderColor(glm::ivec3 col) { @@ -188,9 +210,9 @@ namespace openspace { } bool ScreenSpaceSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) { - std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; - executeJavascript(script); - return true; + std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; + executeJavascript(script); + return true; } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index bdc181e3ee..d0424410f3 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -76,7 +76,7 @@ namespace openspace { , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.f, 1.f, 70.f) - , _borderColor(220.f, 220.f, 220.f) + , _borderColor(220, 220, 220) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -123,6 +123,12 @@ namespace openspace { void ScreenSpaceSkyTarget::setConnectedBrowser() { _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + if (_skyBrowser) { + _skyBrowser->setBorderColor(_skyBrowser->getColor()); + _borderColor = _skyBrowser->getColor(); + updateFOV(_skyBrowser->_vfieldOfView.value()); + _targetDimensions = _skyBrowser->getBrowserPixelDimensions(); + } } bool ScreenSpaceSkyTarget::isReady() const { @@ -219,7 +225,7 @@ namespace openspace { _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetDimensions, targetDim); _shader->setUniform(_uniformCache.modelTransform, modelTransform); - _shader->setUniform(_uniformCache.borderColor, _borderColor); + _shader->setUniform(_uniformCache.borderColor, glm::vec3(_borderColor)); _shader->setUniform( _uniformCache.viewProj, From 124fbef26f824c4d9158615465d601d35667579d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 4 May 2021 10:50:30 +0200 Subject: [PATCH 078/251] Add locking functionality to target --- .../skybrowser/include/screenspaceskytarget.h | 11 ++++- modules/skybrowser/skybrowsermodule.cpp | 20 ++++++++++ modules/skybrowser/skybrowsermodule_lua.inl | 31 +++++++++++++- .../skybrowser/src/screenspaceskybrowser.cpp | 9 +---- .../skybrowser/src/screenspaceskytarget.cpp | 40 +++++++++++++++++-- 5 files changed, 96 insertions(+), 15 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 1a2a69b264..073eb15952 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -20,7 +20,7 @@ namespace openspace { public: ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); - virtual ~ScreenSpaceSkyTarget() = default; + virtual ~ScreenSpaceSkyTarget(); bool initializeGL() override; bool isReady() const override; @@ -33,7 +33,7 @@ namespace openspace { void setDimensions(glm::vec2 currentBrowserDimensions); void updateFOV(float browserFOV); - glm::dvec3 getTargetDirection(); + glm::dvec3 getTargetDirectionGalactic(); glm::dvec2 getScreenSpacePosition(); void setConnectedBrowser(); void setBorderColor(glm::ivec3 color); @@ -43,11 +43,15 @@ namespace openspace { glm::dvec2 getUpperRightCornerScreenSpace(); glm::dvec2 getLowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::dvec2 coord); + glm::dvec2 getTargetDirectionCelestial(); + void unlock(); + void lock(); glm::mat4 scaleMatrix() override; void bindTexture() override; properties::StringProperty _skyBrowserID; + private: properties::Vec2Property _targetDimensions; @@ -60,6 +64,9 @@ namespace openspace { float _fieldOfView = 100.f; ScreenSpaceSkyBrowser* _skyBrowser; glm::ivec3 _borderColor; + bool isLocked; + glm::dvec2 lockedCelestialCoords; + std::thread _lockTargetThread; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 17e09e934a..0d96da97ed 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -128,6 +128,22 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "lockTarget", + &skybrowser::luascriptfunctions::lockTarget, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "unlockTarget", + &skybrowser::luascriptfunctions::unlockTarget, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, }; return res; @@ -276,6 +292,10 @@ SkyBrowserModule::SkyBrowserModule() return true; } } + // If you start dragging around the target, it should unlock + if (to_target(_mouseOnObject)) { + to_target(_mouseOnObject)->unlock(); + } currentlyDraggingObject = true; return true; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 616bd140a4..0d8629308d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -92,6 +92,35 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } + int lockTarget(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + std::vector browsers = module->getSkyBrowsers(); + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (i < browsers.size()) { + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (target) { + target->lock(); + } + } + return 0; + } + + int unlockTarget(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + std::vector browsers = module->getSkyBrowsers(); + if (i < browsers.size()) { + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (target) { + target->unlock(); + } + } + return 0; + } + int followCamera(lua_State* L) { // Load images from url @@ -189,7 +218,7 @@ namespace openspace::skybrowser::luascriptfunctions { // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (target) { - glm::dvec3 coords = target->getTargetDirection(); + glm::dvec3 coords = target->getTargetDirectionGalactic(); glm::dvec2 celestCoords = skybrowser::galacticCartesianToJ2000(coords); // Convert color to vector so ghoul can read it glm::ivec3 color = browsers[i]->_borderColor.value(); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index b929b443c8..54f5933c60 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -285,14 +285,7 @@ namespace openspace { _threadWWTMessages = std::thread([&] { while (_camIsSyncedWWT) { if (_skyTarget) { - // Calculate the galactic coordinate of the target direction - // with infinite radius - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - constexpr double infinity = std::numeric_limits::max(); - glm::dvec3 galCoord = camPos + (infinity * _skyTarget->getTargetDirection()); - glm::dvec2 celestCoordsTarget = skybrowser::galacticCartesianToJ2000(galCoord); - ghoul::Dictionary message = createMessageForMovingWWTCamera(celestCoordsTarget, _vfieldOfView); - + ghoul::Dictionary message = createMessageForMovingWWTCamera(_skyTarget->getTargetDirectionCelestial(), _vfieldOfView); sendMessageToWWT(message); } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index d0424410f3..0b0e8a0519 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -115,6 +115,12 @@ namespace openspace { } + ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { + if (_lockTargetThread.joinable()) { + _lockTargetThread.join(); + } + } + void ScreenSpaceSkyTarget::bindTexture() { if (_texture) { _texture->bind(); @@ -274,7 +280,7 @@ namespace openspace { _targetDimensions = currentBrowserDimensions; } - glm::dvec3 ScreenSpaceSkyTarget::getTargetDirection() { + glm::dvec3 ScreenSpaceSkyTarget::getTargetDirectionGalactic() { // Get camera view direction and orthogonal coordinate system of camera view direction glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); glm::dvec3 targetPosWorldSpace = glm::inverse(global::navigationHandler->camera()->combinedViewMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0); @@ -282,8 +288,6 @@ namespace openspace { return targetDirection; } - - void ScreenSpaceSkyTarget::updateFOV(float VFOV) { float horizFOV = global::windowDelegate->getHorizFieldOfView(); @@ -294,5 +298,33 @@ namespace openspace { _fieldOfView = VFOV; } - + + void ScreenSpaceSkyTarget::unlock() { + isLocked = false; + if (_lockTargetThread.joinable()) { + _lockTargetThread.join(); + } + } + + void ScreenSpaceSkyTarget::lock() { + isLocked = true; + lockedCelestialCoords = getTargetDirectionCelestial(); + + // Start a thread to enable user interactions while locking target + _lockTargetThread = std::thread([&] { + while (isLocked) { + glm::dvec2 imageCoordsScreenSpace = skybrowser::J2000ToScreenSpace(lockedCelestialCoords.x, lockedCelestialCoords.y); + property("CartesianPosition")->set(glm::vec3 {imageCoordsScreenSpace, skybrowser::SCREENSPACE_Z }); + } + }); + } + + glm::dvec2 ScreenSpaceSkyTarget::getTargetDirectionCelestial() { + // Calculate the galactic coordinate of the target direction + // with infinite radius + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + constexpr double infinity = std::numeric_limits::max(); + glm::dvec3 galCoord = camPos + (infinity * getTargetDirectionGalactic()); + return skybrowser::galacticCartesianToJ2000(galCoord); + } } From 6a2a6b54817ece1c2820036efaad61e9556dc416 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 6 May 2021 10:00:41 +0200 Subject: [PATCH 079/251] Add animation to target and FOV when an image is clicked --- .../skybrowser/include/screenspaceskytarget.h | 12 ++++ modules/skybrowser/include/utility.h | 11 +++- modules/skybrowser/skybrowsermodule.cpp | 8 +++ modules/skybrowser/skybrowsermodule_lua.inl | 15 ++--- .../skybrowser/src/screenspaceskytarget.cpp | 63 ++++++++++++++++++- modules/skybrowser/src/utility.cpp | 31 ++++++--- 6 files changed, 120 insertions(+), 20 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 073eb15952..e2d4b01bec 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -46,6 +46,9 @@ namespace openspace { glm::dvec2 getTargetDirectionCelestial(); void unlock(); void lock(); + void animateToCoord(double deltaTime); + void startAnimation(glm::dvec2 coordsEnd, float FOVEnd); + bool animateFOV(float endFOV, float deltaTime); glm::mat4 scaleMatrix() override; @@ -64,9 +67,18 @@ namespace openspace { float _fieldOfView = 100.f; ScreenSpaceSkyBrowser* _skyBrowser; glm::ivec3 _borderColor; + // Locking target to a coordinate on the sky bool isLocked; glm::dvec2 lockedCelestialCoords; std::thread _lockTargetThread; + // Animating the target + bool isAnimated = false; + // Cartesian celestial coords + glm::dvec3 _coordsToAnimateTo; + glm::dvec3 _coordsStartAnimation; + double animationTime = 1.0; + float FOVToAnimateTo; + float currentFOV; }; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 2a9b0068d4..091c6630cf 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -8,6 +8,8 @@ namespace openspace::skybrowser { + const bool SPHERICAL = true; + const bool CARTESIAN = false; const double SCREENSPACE_Z = -2.1; const double RAD_TO_DEG = 180.0 / M_PI; const double DEG_TO_RAD = M_PI / 180.0; @@ -23,10 +25,13 @@ namespace openspace::skybrowser { glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); glm::dvec2 galacticCartesianToJ2000(glm::dvec3 rGal); - glm::dvec3 J2000ToGalacticCartesian(double ra, double dec, double distance); - glm::dvec2 J2000ToScreenSpace(double ra, double dec); + glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance); + glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance); + // Convert J2000, spherical or Cartesian, to screen space + glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords); + glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); - glm::dvec2 galacticToScreenSpace(glm::dvec3 galacticCoord); + glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord); } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 0d96da97ed..d20e416a60 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -327,6 +327,14 @@ SkyBrowserModule::SkyBrowserModule() return false; } ); + + global::callback::preSync->emplace_back([this]() { + for (ScreenSpaceSkyBrowser* browser : getSkyBrowsers()) { + if (browser->getSkyTarget()) { + browser->getSkyTarget()->animateToCoord(global::windowDelegate->deltaTime()); + } + } + }); } void SkyBrowserModule::internalDeinitialize() { diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 0d8629308d..da55d1092e 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -55,11 +55,12 @@ namespace openspace::skybrowser::luascriptfunctions { // Only move target if the image has coordinates if (resultImage.hasCoords) { - glm::dvec2 imageCoordsScreenSpace = skybrowser::J2000ToScreenSpace(resultImage.celestCoords.x, resultImage.celestCoords.y); - browser->getSkyTarget()->property("CartesianPosition")->set(glm::vec3 {imageCoordsScreenSpace, skybrowser::SCREENSPACE_Z }); - - // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 - browser->setVerticalFieldOfView(resultImage.zoomLevel / 6); + // Animate the target to the image coord position + // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 + if (browser->getSkyTarget()) { + browser->getSkyTarget()->unlock(); + browser->getSkyTarget()->startAnimation(resultImage.celestCoords, resultImage.zoomLevel / 6); + } } return 0; } @@ -77,8 +78,8 @@ namespace openspace::skybrowser::luascriptfunctions { ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(true); // Calculate coords for the circle and translate - glm::vec2 imageCoordsScreenSpace = skybrowser::J2000ToScreenSpace(resultImage.celestCoords.x, resultImage.celestCoords.y); - hoverCircle->property("CartesianPosition")->set(glm::vec3 {imageCoordsScreenSpace, skybrowser::SCREENSPACE_Z }); + glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(resultImage.celestCoords); + hoverCircle->property("CartesianPosition")->set(imageCoordsScreenSpace); } return 0; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 0b0e8a0519..8deac38412 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -25,6 +25,8 @@ #include #include #include +#define _USE_MATH_DEFINES +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; @@ -307,14 +309,17 @@ namespace openspace { } void ScreenSpaceSkyTarget::lock() { + if (isLocked) { + unlock(); + } isLocked = true; lockedCelestialCoords = getTargetDirectionCelestial(); // Start a thread to enable user interactions while locking target _lockTargetThread = std::thread([&] { while (isLocked) { - glm::dvec2 imageCoordsScreenSpace = skybrowser::J2000ToScreenSpace(lockedCelestialCoords.x, lockedCelestialCoords.y); - property("CartesianPosition")->set(glm::vec3 {imageCoordsScreenSpace, skybrowser::SCREENSPACE_Z }); + glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(lockedCelestialCoords); + _cartesianPosition = imageCoordsScreenSpace; } }); } @@ -327,4 +332,58 @@ namespace openspace { glm::dvec3 galCoord = camPos + (infinity * getTargetDirectionGalactic()); return skybrowser::galacticCartesianToJ2000(galCoord); } + + void ScreenSpaceSkyTarget::animateToCoord(double deltaTime) { + if (isAnimated) { + // Find smallest angle between the two vectors + double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsToAnimateTo) / (glm::length(_coordsStartAnimation) * glm::length(_coordsToAnimateTo))); + // Only keep animating when target is not at final position + if (abs(smallestAngle) > 0.0005) { + // Calculate rotation this frame + double rotationAngle = smallestAngle * deltaTime * 5.0; + // Create the rotation matrix + glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsToAnimateTo)); + glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); + // Rotate target direction + glm::dvec3 newDir = rotmat * glm::dvec4(_coordsStartAnimation, 1.0); + // Convert to screenspace + _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(newDir); + // Update position + _coordsStartAnimation = glm::normalize(newDir); + } + else { + // Set the exact target position and lock target when it first arrives + // to the position + if (!isLocked) { + _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsToAnimateTo); + lock(); + } + // When target is in position, animate the FOV until it has finished + if(animateFOV(FOVToAnimateTo, deltaTime)) { + isAnimated = false; + } + } + } + } + + bool ScreenSpaceSkyTarget::animateFOV(float endFOV, float deltaTime) { + double distance = static_cast(_skyBrowser->_vfieldOfView.value()) - endFOV; + // If distance is too large, keep animating + if (abs(distance) > 0.01) { + _skyBrowser->setVerticalFieldOfView(_skyBrowser->_vfieldOfView.value() - (distance * deltaTime * 2.0)); + return false; + } + // Animation is finished + return true; + } + + void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd) { + // Save the Cartesian celestial coordinates for animation + // to make sure wrap around works + _coordsToAnimateTo = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd)); + _coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian(getTargetDirectionCelestial())); + FOVToAnimateTo = FOVEnd; + isAnimated = true; + } + } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 913e8089c8..5504dc8529 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -38,12 +38,17 @@ namespace openspace::skybrowser { return cartesianToSpherical(J2000); } - glm::dvec3 J2000ToGalacticCartesian(double ra, double dec, double distance) { - glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(glm::dvec2(ra, dec)); // on the unit sphere + glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) { + glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere return distance * rGalactic; } - glm::dvec2 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { + glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) { + glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere + return distance * rGalactic; + } + + glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { // Transform vector to camera's local coordinate system glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); @@ -51,24 +56,34 @@ namespace openspace::skybrowser { glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); viewDirectionLocal = glm::normalize(viewDirectionLocal); + // Ensure that if the coord is behind the camera, the converted coord will be there too + double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z; // Calculate screen space coords x and y long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z; long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z; glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y)); - glm::dvec2 imageCoordsScreenSpace = glm::dvec2(SCREENSPACE_Z * static_cast(std::tanl(angleCoordsLocal.x)), SCREENSPACE_Z * static_cast(std::tanl(angleCoordsLocal.y))); + glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast(std::tanl(angleCoordsLocal.x)), zCoord * static_cast(std::tanl(angleCoordsLocal.y)), zCoord); return imageCoordsScreenSpace; } - glm::dvec2 J2000ToScreenSpace(double ra, double dec) { + glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) { // Transform equatorial J2000 to galactic coord with infinite radius constexpr double infinity = std::numeric_limits::max(); - glm::dvec3 imageCoordsGalacticCartesian = J2000ToGalacticCartesian(ra, dec, infinity); + glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity); // Transform galactic coord to screen space - glm::dvec2 imageCoordsScreenSpace = galacticToScreenSpace(imageCoordsGalacticCartesian); - return imageCoordsScreenSpace; + return galacticToScreenSpace(imageCoordsGalacticCartesian); + } + + glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) { + + // Transform equatorial J2000 to galactic coord with infinite radius + constexpr double infinity = std::numeric_limits::max(); + glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity); + // Transform galactic coord to screen space + return galacticToScreenSpace(imageCoordsGalacticCartesian); } } From 9514fda861bb69729bacda9af4d2a3d49c06c5a4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 6 May 2021 13:50:54 +0200 Subject: [PATCH 080/251] Send window FOV and direction to GUI --- modules/skybrowser/skybrowsermodule_lua.inl | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index da55d1092e..d5838bba1d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -212,6 +212,29 @@ namespace openspace::skybrowser::luascriptfunctions { lua_newtable(L); int index = 1; + + // Add the window data for OpenSpace + ghoul::lua::push(L, index); + index++; + lua_newtable(L); + // Calculate camera view direction in celestial spherical coordinates + glm::dvec3 viewDir = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::dvec2 viewDirCelest = skybrowser::galacticCartesianToJ2000(viewDir); + // Convert to vector so ghoul can read it + std::vector viewDirCelestVec = { viewDirCelest.x, viewDirCelest.y }; + // Calculate the smallest FOV of vertical and horizontal + float HFOV = global::windowDelegate->getHorizFieldOfView(); + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + float VFOV = HFOV * (windowRatio.y / windowRatio.x); + double FOV = std::min(HFOV, VFOV); + // Push window data + ghoul::lua::push(L, "WindowHFOV", FOV); + lua_settable(L, -3); + ghoul::lua::push(L, "WindowDirection", viewDirCelestVec); + lua_settable(L, -3); + // Set table for the current ImageData + lua_settable(L, -3); + // Pass data for all the browsers and the corresponding targets std::vector browsers = module->getSkyBrowsers(); @@ -238,7 +261,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::push(L, "Color", colorVec); lua_settable(L, -3); - // Set table for the current ImageData + // Set table for the current target lua_settable(L, -3); } } From 16e83fdcddf28c5748341888f333b8886d1f82de Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 6 May 2021 15:29:06 +0200 Subject: [PATCH 081/251] Bugfix of crashing when scrolling too fast - add cap of update of scroll callback --- modules/skybrowser/skybrowsermodule.cpp | 21 ++++++++++++--------- modules/skybrowser/skybrowsermodule.h | 3 +++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index d20e416a60..293fe89143 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -195,7 +195,6 @@ SkyBrowserModule::SkyBrowserModule() double OpenSpaceHorizontalFOV = global::windowDelegate->getHorizFieldOfView(); glm::dvec2 OpenSpaceFOV = glm::dvec2(OpenSpaceHorizontalFOV, OpenSpaceHorizontalFOV * windowRatio); - glm::dvec2 angleResult = WWTFOV * (move / browserDim); glm::dvec2 OSresult = angleResult / OpenSpaceFOV; @@ -259,15 +258,19 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - // If mouse is on browser, apply zoom - if (to_browser(_mouseOnObject)) { - to_browser(_mouseOnObject)->scrollZoom(scroll); - return true; + // Cap how often the zoom is allowed to update + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + if (now - _lastUpdateTime > TimeUpdateInterval) { + // If mouse is on browser or target, apply zoom + if (to_browser(_mouseOnObject)) { + to_browser(_mouseOnObject)->scrollZoom(scroll); + return true; + } + else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { + to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); + } + _lastUpdateTime = std::chrono::system_clock::now(); } - else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { - to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); - } - return false; } ); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index a9158cfee9..8d3aebd090 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -85,6 +85,9 @@ protected: bool currentlyResizingBrowser; bool currentlyDraggingObject; WWTDataHandler* dataHandler; + // For capping the calls to change the zoom from scrolling + constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 50 }; + std::chrono::system_clock::time_point _lastUpdateTime; }; } // namespace openspace From 2472d07c1cb70aa7b0fe44c7bace2a34ab4dc56a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 6 May 2021 15:30:01 +0200 Subject: [PATCH 082/251] Send cartesian equatorial J2000 coords to GUI for better calculation of distance sort --- modules/skybrowser/skybrowsermodule_lua.inl | 32 +++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index d5838bba1d..4eb0aefc08 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -176,6 +176,8 @@ namespace openspace::skybrowser::luascriptfunctions { for (int i = 0; i < images.size(); i++) { std::string name = images[i].name != "" ? images[i].name : "undefined"; std::string url = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; + glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestCoords); + std::vector cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z }; // Index for current ImageData ghoul::lua::push(L, i + 1); @@ -189,6 +191,8 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "Dec", images[i].celestCoords.y); lua_settable(L, -3); + ghoul::lua::push(L, "CartesianDirection", cartCoordsVec); + lua_settable(L, -3); ghoul::lua::push(L, "HasCoords", images[i].hasCoords); lua_settable(L, -3); ghoul::lua::push(L, "Credits", images[i].credits); @@ -217,11 +221,14 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::push(L, index); index++; lua_newtable(L); - // Calculate camera view direction in celestial spherical coordinates - glm::dvec3 viewDir = global::navigationHandler->camera()->viewDirectionWorldSpace(); - glm::dvec2 viewDirCelest = skybrowser::galacticCartesianToJ2000(viewDir); + // Get the view direction of the screen in cartesian J2000 coordinates + + glm::dvec2 sphericalJ2000 = galacticCartesianToJ2000(global::navigationHandler->camera()->viewDirectionWorldSpace()); + glm::dvec3 cartesianJ2000 = skybrowser::sphericalToCartesian(sphericalJ2000); // Convert to vector so ghoul can read it - std::vector viewDirCelestVec = { viewDirCelest.x, viewDirCelest.y }; + std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; + + // Calculate the smallest FOV of vertical and horizontal float HFOV = global::windowDelegate->getHorizFieldOfView(); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); @@ -230,7 +237,11 @@ namespace openspace::skybrowser::luascriptfunctions { // Push window data ghoul::lua::push(L, "WindowHFOV", FOV); lua_settable(L, -3); - ghoul::lua::push(L, "WindowDirection", viewDirCelestVec); + ghoul::lua::push(L, "CartesianDirection", viewDirCelestVec); + lua_settable(L, -3); + ghoul::lua::push(L, "RA", sphericalJ2000.x); + lua_settable(L, -3); + ghoul::lua::push(L, "Dec", sphericalJ2000.y); lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); @@ -242,8 +253,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (target) { - glm::dvec3 coords = target->getTargetDirectionGalactic(); - glm::dvec2 celestCoords = skybrowser::galacticCartesianToJ2000(coords); + glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial(); + glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical); + std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; // Convert color to vector so ghoul can read it glm::ivec3 color = browsers[i]->_borderColor.value(); std::vector colorVec = { color.r, color.g, color.b }; @@ -254,9 +266,11 @@ namespace openspace::skybrowser::luascriptfunctions { // Push ("Key", value) ghoul::lua::push(L, "FOV", browsers[i]->fieldOfView()); lua_settable(L, -3); - ghoul::lua::push(L, "RA", celestCoords.x); + ghoul::lua::push(L, "CartesianDirection", celestialCartVec); lua_settable(L, -3); - ghoul::lua::push(L, "Dec", celestCoords.y); + ghoul::lua::push(L, "RA", celestialSpherical.x); + lua_settable(L, -3); + ghoul::lua::push(L, "Dec", celestialSpherical.y); lua_settable(L, -3); ghoul::lua::push(L, "Color", colorVec); lua_settable(L, -3); From a58d29b0ceb77dcd52e6c9c62594c38b27050ec7 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 09:54:05 +0200 Subject: [PATCH 083/251] Make coordinate conversion functions more modular --- modules/skybrowser/include/utility.h | 8 ++++---- modules/skybrowser/src/utility.cpp | 24 +++++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 091c6630cf..4cfd90e5f9 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -8,11 +8,10 @@ namespace openspace::skybrowser { - const bool SPHERICAL = true; - const bool CARTESIAN = false; const double SCREENSPACE_Z = -2.1; const double RAD_TO_DEG = 180.0 / M_PI; const double DEG_TO_RAD = M_PI / 180.0; + constexpr double infinity = std::numeric_limits::max(); // Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1 const glm::dmat3 conversionMatrix = glm::dmat3({ @@ -25,8 +24,9 @@ namespace openspace::skybrowser { glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); glm::dvec2 galacticCartesianToJ2000(glm::dvec3 rGal); - glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance); - glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance); + glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords); + glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance = infinity); + glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance = infinity); // Convert J2000, spherical or Cartesian, to screen space glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords); glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 5504dc8529..8dbad4ea40 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -50,12 +50,7 @@ namespace openspace::skybrowser { glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { - // Transform vector to camera's local coordinate system - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 camToCoordsDir = glm::normalize(imageCoordsGalacticCartesian - camPos); - glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); - viewDirectionLocal = glm::normalize(viewDirectionLocal); + glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian); // Ensure that if the coord is behind the camera, the converted coord will be there too double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z; @@ -69,18 +64,25 @@ namespace openspace::skybrowser { return imageCoordsScreenSpace; } + glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) { + // Transform vector to camera's local coordinate system + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos); + glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); + viewDirectionLocal = glm::normalize(viewDirectionLocal); + return viewDirectionLocal; + } + glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) { - // Transform equatorial J2000 to galactic coord with infinite radius - constexpr double infinity = std::numeric_limits::max(); + // Transform equatorial J2000 to galactic coord with infinite radius glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity); // Transform galactic coord to screen space return galacticToScreenSpace(imageCoordsGalacticCartesian); } - glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) { - + glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) { // Transform equatorial J2000 to galactic coord with infinite radius - constexpr double infinity = std::numeric_limits::max(); glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity); // Transform galactic coord to screen space return galacticToScreenSpace(imageCoordsGalacticCartesian); From ed027c9224ab75b651bfac3f9ce8f16399d31756 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 09:55:10 +0200 Subject: [PATCH 084/251] Add camera animation rotation to look at coordinate --- modules/skybrowser/skybrowsermodule.cpp | 37 +++++++++++++++++++++ modules/skybrowser/skybrowsermodule.h | 6 ++++ modules/skybrowser/skybrowsermodule_lua.inl | 9 ++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 293fe89143..19cf31ed07 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -337,6 +337,9 @@ SkyBrowserModule::SkyBrowserModule() browser->getSkyTarget()->animateToCoord(global::windowDelegate->deltaTime()); } } + if (isRotating) { + rotateCamera(global::windowDelegate->deltaTime()); + } }); } @@ -398,6 +401,40 @@ std::vector SkyBrowserModule::getSkyBrowsers() { return browsers; } +void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { + + // Save coordinates to rotate to in galactic world coordinates + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + _coordsToAnimateTo = skybrowser::J2000SphericalToGalacticCartesian(coordsEnd); + _coordsStartAnimation = (global::navigationHandler->camera()->viewDirectionWorldSpace() * skybrowser::infinity) + camPos; + isRotating = true; +} + +void SkyBrowserModule::rotateCamera(double deltaTime) { + + // Find smallest angle between the two vectors + double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsToAnimateTo) / (glm::length(_coordsStartAnimation) * glm::length(_coordsToAnimateTo))); + // Only keep animating when target is not at final position + if (abs(smallestAngle) > 0.0001) { + // Calculate rotation this frame + double rotationAngle = smallestAngle * deltaTime; + // Create the rotation matrix for local camera space + glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsToAnimateTo)); + glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(rotationAxis, 1.0); + glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); + // Rotate + global::navigationHandler->camera()->rotate(glm::quat_cast(rotmat)); + + // Update camera direction + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + _coordsStartAnimation = (global::navigationHandler->camera()->viewDirectionWorldSpace() * skybrowser::infinity) + camPos; + } + else { + isRotating = false; + } +} + /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 8d3aebd090..3d9248cafc 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -55,6 +55,8 @@ public: void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); std::vector getSkyBrowsers(); + void startRotation(glm::dvec2 coordsEnd); + void rotateCamera(double deltaTime); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -88,6 +90,10 @@ protected: // For capping the calls to change the zoom from scrolling constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 50 }; std::chrono::system_clock::time_point _lastUpdateTime; + // For animating rotation of camera to look at coordinate + glm::dvec3 _coordsToAnimateTo; + glm::dvec3 _coordsStartAnimation; + bool isRotating = false; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4eb0aefc08..9f822b936c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -284,7 +284,14 @@ namespace openspace::skybrowser::luascriptfunctions { return 1; } int adjustCamera(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::adjustCamera"); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + //module->getSkyBrowsers()[0]->getSkyTarget()->lock(); + if (module->getSkyBrowsers().size() > i) { + module->startRotation(module->getSkyBrowsers()[i]->getSkyTarget()->getTargetDirectionCelestial()); + } + return 0; } From e73656b1d9314acb6331c886b7c44e5c8cae24fc Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 10:52:45 +0200 Subject: [PATCH 085/251] Rotate camera if selected image is outside of screen --- modules/skybrowser/skybrowsermodule_lua.inl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 9f822b936c..9891bae7f8 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -60,6 +60,15 @@ namespace openspace::skybrowser::luascriptfunctions { if (browser->getSkyTarget()) { browser->getSkyTarget()->unlock(); browser->getSkyTarget()->startAnimation(resultImage.celestCoords, resultImage.zoomLevel / 6); + glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + float r = windowRatio.x / windowRatio.y; + // Check if image coordinate is within current FOV + if (!(abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0) + || imgCoordsOnScreen.z > 0) { + module->startRotation(resultImage.celestCoords); + } + } } return 0; From c882cdd3a3f0480ca41f5572ae290cbfcfee915c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 11:50:13 +0200 Subject: [PATCH 086/251] Add selection functionality to send index from and to GUI and move capping of scroll too browser --- .../include/screenspaceskybrowser.h | 3 ++ modules/skybrowser/skybrowsermodule.cpp | 53 +++++++++++++------ modules/skybrowser/skybrowsermodule.h | 11 ++-- modules/skybrowser/skybrowsermodule_lua.inl | 19 +++++-- .../skybrowser/src/screenspaceskybrowser.cpp | 15 ++++-- .../skybrowser/src/screenspaceskytarget.cpp | 18 ++++--- 6 files changed, 85 insertions(+), 34 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index e4b9a68f31..1df60ea0ed 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -59,6 +59,9 @@ namespace openspace { bool _camIsSyncedWWT; ScreenSpaceSkyTarget* _skyTarget; std::thread _threadWWTMessages; + // For capping the calls to change the zoom from scrolling + constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 25 }; + std::chrono::system_clock::time_point _lastUpdateTime; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 19cf31ed07..6ce9f54186 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -120,6 +120,14 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "setSelectedBrowser", + & skybrowser::luascriptfunctions::setSelectedBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, { "getTargetData", &skybrowser::luascriptfunctions::getTargetData, @@ -234,7 +242,6 @@ SkyBrowserModule::SkyBrowserModule() // Selection has changed if (lastObj != _mouseOnObject) { - glm::ivec3 highlightAddition{ 35, 35, 35 }; // Remove highlight if (to_browser(lastObj)) { to_browser(lastObj)->setBorderColor(to_browser(lastObj)->getColor() - highlightAddition); @@ -258,19 +265,16 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - // Cap how often the zoom is allowed to update - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - if (now - _lastUpdateTime > TimeUpdateInterval) { - // If mouse is on browser or target, apply zoom - if (to_browser(_mouseOnObject)) { - to_browser(_mouseOnObject)->scrollZoom(scroll); - return true; - } - else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { - to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); - } - _lastUpdateTime = std::chrono::system_clock::now(); + + // If mouse is on browser or target, apply zoom + if (to_browser(_mouseOnObject)) { + to_browser(_mouseOnObject)->scrollZoom(scroll); + return true; } + else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { + to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); + } + return false; } ); @@ -278,9 +282,13 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { - if (action == MouseAction::Press) { + if (_mouseOnObject && action == MouseAction::Press) { - if (_mouseOnObject && button == MouseButton::Left) { + // Get the currently selected browser + setSelectedBrowser(_mouseOnObject); + + + if (button == MouseButton::Left) { startDragMousePos = _mousePosition; startDragObjectPos = _mouseOnObject->getScreenSpacePosition(); @@ -435,6 +443,21 @@ void SkyBrowserModule::rotateCamera(double deltaTime) { } } +void SkyBrowserModule::setSelectedBrowser(ScreenSpaceRenderable* ptr) { + ScreenSpaceSkyBrowser* browser = to_browser(ptr) ? to_browser(ptr) : to_target(ptr)->getSkyBrowser(); + std::vector browsers = getSkyBrowsers(); + auto it = std::find(browsers.begin(), browsers.end(), browser); + // Get index + selectedBrowser = std::distance(browsers.begin(), it); +} + +void SkyBrowserModule::setSelectedBrowser(int i) { + selectedBrowser = i; +} + +int SkyBrowserModule::getSelectedBrowserIndex() { + return selectedBrowser; +} /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 3d9248cafc..46e5f48064 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -57,6 +57,9 @@ public: std::vector getSkyBrowsers(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); + void setSelectedBrowser(ScreenSpaceRenderable* ptr); + void setSelectedBrowser(int i); + int getSelectedBrowserIndex(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -86,14 +89,16 @@ protected: // Current interaction status bool currentlyResizingBrowser; bool currentlyDraggingObject; + // Data handler WWTDataHandler* dataHandler; - // For capping the calls to change the zoom from scrolling - constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 50 }; - std::chrono::system_clock::time_point _lastUpdateTime; + // For animating rotation of camera to look at coordinate glm::dvec3 _coordsToAnimateTo; glm::dvec3 _coordsStartAnimation; bool isRotating = false; + // For tracking the currently selected browser + int selectedBrowser{ -1 }; + glm::ivec3 highlightAddition{ 35, 35, 35 }; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 9891bae7f8..bafb28b719 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -36,9 +36,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Load image ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); - - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - SkyBrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule* module = global::moduleEngine->module(); + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; + const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Load image collection, if it isn't loaded already // TODO: Update or remove with new WWT API @@ -252,6 +252,8 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "Dec", sphericalJ2000.y); lua_settable(L, -3); + ghoul::lua::push(L, "SelectedBrowserIndex", module->getSelectedBrowserIndex()); + lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); @@ -296,13 +298,22 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - //module->getSkyBrowsers()[0]->getSkyTarget()->lock(); if (module->getSkyBrowsers().size() > i) { module->startRotation(module->getSkyBrowsers()[i]->getSkyTarget()->getTargetDirectionCelestial()); } return 0; } + + int setSelectedBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getSkyBrowsers().size() < i) { + module->setSelectedBrowser(i); + } + return 0; + } } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 54f5933c60..77e62cb548 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -184,11 +184,16 @@ namespace openspace { } void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { - // Make scroll more sensitive the smaller the FOV - float x = _vfieldOfView; - float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; - float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); + // Cap how often the zoom is allowed to update + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + if (now - _lastUpdateTime > TimeUpdateInterval) { + // Make scroll more sensitive the smaller the FOV + float x = _vfieldOfView; + float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; + float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; + _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); + _lastUpdateTime = std::chrono::system_clock::now(); + } } void ScreenSpaceSkyBrowser::executeJavascript(std::string script) const { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 8deac38412..742190bb6d 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -367,14 +367,18 @@ namespace openspace { } bool ScreenSpaceSkyTarget::animateFOV(float endFOV, float deltaTime) { - double distance = static_cast(_skyBrowser->_vfieldOfView.value()) - endFOV; - // If distance is too large, keep animating - if (abs(distance) > 0.01) { - _skyBrowser->setVerticalFieldOfView(_skyBrowser->_vfieldOfView.value() - (distance * deltaTime * 2.0)); - return false; + if (_skyBrowser) { + double distance = static_cast(_skyBrowser->_vfieldOfView.value()) - endFOV; + // If distance is too large, keep animating + if (abs(distance) > 0.01) { + _skyBrowser->scrollZoom(distance); + return false; + } + // Animation is finished + return true; } - // Animation is finished - return true; + LINFO("Browser not connected to target!"); + return true; } void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd) { From 317a62cb905789e6b44943066dce266d07d478cd Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 14:02:11 +0200 Subject: [PATCH 087/251] Add comment to explain why data handler is created dynamically --- modules/skybrowser/skybrowsermodule.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 6ce9f54186..3567b1235b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -367,7 +367,8 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { // register ScreenSpaceTarget ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); - + // Create data handler dynamically to avoid the linking error that + // came up when including the include file in the module header file dataHandler = new WWTDataHandler(); } From 03dbbd1352789f168b8f5efc4976eeb1f12c9fc3 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 14:37:15 +0200 Subject: [PATCH 088/251] Lower the cap on zooming so it looks better --- modules/skybrowser/include/screenspaceskybrowser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 1df60ea0ed..b358a00790 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -60,7 +60,7 @@ namespace openspace { ScreenSpaceSkyTarget* _skyTarget; std::thread _threadWWTMessages; // For capping the calls to change the zoom from scrolling - constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 25 }; + constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; std::chrono::system_clock::time_point _lastUpdateTime; }; } From a456b68b204d85878fdb9f289b4eb7a4e1b63e28 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 7 May 2021 14:37:52 +0200 Subject: [PATCH 089/251] Make it more efficient to get the vector of browsers --- modules/skybrowser/skybrowsermodule.cpp | 16 ++++------- modules/skybrowser/skybrowsermodule.h | 3 +- modules/skybrowser/skybrowsermodule_lua.inl | 32 ++++++++++----------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 3567b1235b..955db4b4cb 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -340,7 +340,7 @@ SkyBrowserModule::SkyBrowserModule() ); global::callback::preSync->emplace_back([this]() { - for (ScreenSpaceSkyBrowser* browser : getSkyBrowsers()) { + for (ScreenSpaceSkyBrowser* browser : browsers) { if (browser->getSkyTarget()) { browser->getSkyTarget()->animateToCoord(global::windowDelegate->deltaTime()); } @@ -387,6 +387,9 @@ void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { renderables.push_back(object); // Sort on z coordinate, objects closer to camera are in beginning of list std::sort(renderables.begin(), renderables.end()); + if (to_browser(object)) { + browsers.push_back(to_browser(object)); + } } ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { @@ -400,14 +403,8 @@ WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { return dataHandler; } -std::vector SkyBrowserModule::getSkyBrowsers() { - std::vector browsers; - for (ScreenSpaceRenderable* renderable : renderables) { - if (to_browser(renderable)) { - browsers.push_back(to_browser(renderable)); - } - } - return browsers; +std::vector* SkyBrowserModule::getSkyBrowsers() { + return &browsers; } void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { @@ -446,7 +443,6 @@ void SkyBrowserModule::rotateCamera(double deltaTime) { void SkyBrowserModule::setSelectedBrowser(ScreenSpaceRenderable* ptr) { ScreenSpaceSkyBrowser* browser = to_browser(ptr) ? to_browser(ptr) : to_target(ptr)->getSkyBrowser(); - std::vector browsers = getSkyBrowsers(); auto it = std::find(browsers.begin(), browsers.end(), browser); // Get index selectedBrowser = std::distance(browsers.begin(), it); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 46e5f48064..5594fd9cf1 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -54,7 +54,7 @@ public: glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); - std::vector getSkyBrowsers(); + std::vector* getSkyBrowsers(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); void setSelectedBrowser(ScreenSpaceRenderable* ptr); @@ -76,6 +76,7 @@ protected: // Renderable vector and ptr to where mouse is std::vector renderables; + std::vector browsers; ScreenSpaceRenderable* _mouseOnObject; // Dragging glm::vec2 startDragMousePos; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index bafb28b719..50312fa439 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -37,7 +37,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; + ScreenSpaceSkyBrowser* browser = (*module->getSkyBrowsers())[module->getSelectedBrowserIndex()]; const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Load image collection, if it isn't loaded already @@ -106,10 +106,10 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector browsers = module->getSkyBrowsers(); - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); - if (i < browsers.size()) { - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + std::vector* browsers = module->getSkyBrowsers(); + ScreenSpaceSkyTarget* target = (*browsers)[i]->getSkyTarget(); + if (i < browsers->size()) { + ScreenSpaceSkyTarget* target = (*browsers)[i]->getSkyTarget(); if (target) { target->lock(); } @@ -121,9 +121,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector browsers = module->getSkyBrowsers(); - if (i < browsers.size()) { - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + std::vector* browsers = module->getSkyBrowsers(); + if (i < browsers->size()) { + ScreenSpaceSkyTarget* target = (*browsers)[i]->getSkyTarget(); if (target) { target->unlock(); } @@ -258,24 +258,24 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); // Pass data for all the browsers and the corresponding targets - std::vector browsers = module->getSkyBrowsers(); + std::vector* browsers = module->getSkyBrowsers(); - for (int i = 0; i < browsers.size(); i++) { + for (ScreenSpaceSkyBrowser* browser : *browsers) { // Only add browsers that have an initialized target - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial(); glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical); std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; // Convert color to vector so ghoul can read it - glm::ivec3 color = browsers[i]->_borderColor.value(); + glm::ivec3 color = browser->_borderColor.value(); std::vector colorVec = { color.r, color.g, color.b }; ghoul::lua::push(L, index); index++; lua_newtable(L); // Push ("Key", value) - ghoul::lua::push(L, "FOV", browsers[i]->fieldOfView()); + ghoul::lua::push(L, "FOV", browser->fieldOfView()); lua_settable(L, -3); ghoul::lua::push(L, "CartesianDirection", celestialCartVec); lua_settable(L, -3); @@ -298,8 +298,8 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getSkyBrowsers().size() > i) { - module->startRotation(module->getSkyBrowsers()[i]->getSkyTarget()->getTargetDirectionCelestial()); + if (module->getSkyBrowsers()->size() > i) { + module->startRotation((*module->getSkyBrowsers())[i]->getSkyTarget()->getTargetDirectionCelestial()); } return 0; @@ -309,7 +309,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getSkyBrowsers().size() < i) { + if (module->getSkyBrowsers()->size() < i) { module->setSelectedBrowser(i); } return 0; From 4126be26043af1cb769c2eb49cbe865d5fff826f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 10 May 2021 09:19:00 +0200 Subject: [PATCH 090/251] Sort the images on image name --- modules/skybrowser/src/wwtdatahandler.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index c685c6da7b..964fbbcbad 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -93,6 +93,18 @@ namespace openspace { std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; loadImagesFromXML(root, collectionName); } + // Sort images in alphabetial order + std::sort(images.begin(), images.end(), [](ImageData a, ImageData b) { + // If the first charachter in the names are lowercase, make it upper case + if (std::islower(a.name[0])) { + // convert string to upper case + a.name[0] = ::toupper(a.name[0]); + } + if (std::islower(b.name[0])) { + b.name[0] = ::toupper(b.name[0]); + } + return a.name < b.name; + }); return images.size(); } From 3ef357f56e6c45d8fd820db9bc316fa36798b698 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 10 May 2021 09:20:11 +0200 Subject: [PATCH 091/251] Get the vector of browsers by reference instead of as a pointer --- modules/skybrowser/skybrowsermodule.cpp | 9 ++++--- modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 26 +++++++++---------- .../skybrowser/src/screenspaceskytarget.cpp | 9 ++++++- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 955db4b4cb..2539c09524 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -312,7 +312,10 @@ SkyBrowserModule::SkyBrowserModule() return true; } else if (to_browser(_mouseOnObject) && button == MouseButton::Right) { - + // If you start dragging around on the browser, the target should unlock + if (to_browser(_mouseOnObject) && to_browser(_mouseOnObject)->getSkyTarget()) { + to_browser(_mouseOnObject)->getSkyTarget()->unlock(); + } // Change view (by moving target) within browser if right mouse click on browser startDragMousePos = _mousePosition; startDragObjectPos = to_browser(_mouseOnObject)->getSkyTarget()->getScreenSpacePosition(); @@ -403,8 +406,8 @@ WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { return dataHandler; } -std::vector* SkyBrowserModule::getSkyBrowsers() { - return &browsers; +std::vector& SkyBrowserModule::getSkyBrowsers() { + return browsers; } void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 5594fd9cf1..5017f8687a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -54,7 +54,7 @@ public: glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); - std::vector* getSkyBrowsers(); + std::vector& getSkyBrowsers(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); void setSelectedBrowser(ScreenSpaceRenderable* ptr); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 50312fa439..0161f55380 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -37,7 +37,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* browser = (*module->getSkyBrowsers())[module->getSelectedBrowserIndex()]; + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Load image collection, if it isn't loaded already @@ -106,10 +106,10 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector* browsers = module->getSkyBrowsers(); - ScreenSpaceSkyTarget* target = (*browsers)[i]->getSkyTarget(); - if (i < browsers->size()) { - ScreenSpaceSkyTarget* target = (*browsers)[i]->getSkyTarget(); + std::vector browsers = module->getSkyBrowsers(); + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (i < browsers.size()) { + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (target) { target->lock(); } @@ -121,9 +121,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector* browsers = module->getSkyBrowsers(); - if (i < browsers->size()) { - ScreenSpaceSkyTarget* target = (*browsers)[i]->getSkyTarget(); + std::vector browsers = module->getSkyBrowsers(); + if (i < browsers.size()) { + ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (target) { target->unlock(); } @@ -258,9 +258,9 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); // Pass data for all the browsers and the corresponding targets - std::vector* browsers = module->getSkyBrowsers(); + std::vector browsers = module->getSkyBrowsers(); - for (ScreenSpaceSkyBrowser* browser : *browsers) { + for (ScreenSpaceSkyBrowser* browser : browsers) { // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { @@ -298,8 +298,8 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getSkyBrowsers()->size() > i) { - module->startRotation((*module->getSkyBrowsers())[i]->getSkyTarget()->getTargetDirectionCelestial()); + if (module->getSkyBrowsers().size() > i) { + module->startRotation(module->getSkyBrowsers()[i]->getSkyTarget()->getTargetDirectionCelestial()); } return 0; @@ -309,7 +309,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getSkyBrowsers()->size() < i) { + if (module->getSkyBrowsers().size() < i) { module->setSelectedBrowser(i); } return 0; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 742190bb6d..573510677b 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -367,6 +367,10 @@ namespace openspace { } bool ScreenSpaceSkyTarget::animateFOV(float endFOV, float deltaTime) { + if (!_skyBrowser) { + ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + setBrowser(browser); + } if (_skyBrowser) { double distance = static_cast(_skyBrowser->_vfieldOfView.value()) - endFOV; // If distance is too large, keep animating @@ -377,7 +381,10 @@ namespace openspace { // Animation is finished return true; } - LINFO("Browser not connected to target!"); + else { + LINFO("Target can't connect to browser!"); + } + return true; } From 9f13bf69cc50257792cc7733e9d6b6a2e977157e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 10 May 2021 14:12:13 +0200 Subject: [PATCH 092/251] Add functionality to load speck files and add the matching names as 3D positions --- modules/skybrowser/include/wwtdatahandler.h | 131 +++++++--- modules/skybrowser/skybrowsermodule_lua.inl | 11 +- modules/skybrowser/src/wwtdatahandler.cpp | 273 ++++++++++++++++++++ 3 files changed, 373 insertions(+), 42 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 885c3487a9..687843fe09 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -3,59 +3,108 @@ #include #include +#include +// For speck loading +#include +#include +#include +#include +#include +#include namespace openspace::documentation { struct Documentation; } +// Copied from the branch feature/speck-loader +// Should be changed to a more general way of loading +// Speck files one that has been created +namespace openspace::speck { + + BooleanType(SkipAllZeroLines); + + struct Dataset { + struct Variable { + int index; + std::string name; + }; + std::vector variables; + + struct Texture { + int index; + std::string file; + }; + std::vector textures; + + int textureDataIndex = -1; + int orientationDataIndex = -1; + + struct Entry { + glm::dvec3 position; + std::vector data; + std::optional comment; + }; + std::vector entries; + }; + + // In-out methods + Dataset loadSpeckFile(std::filesystem::path path, + SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + +} // namespace openspace::speck + namespace openspace { - struct ImageData { - std::string name; - std::string thumbnailUrl; - std::string credits; - std::string creditsUrl; - glm::dvec2 celestCoords; - std::string collection; - float zoomLevel; - bool hasCoords; - }; + struct ImageData { + std::string name; + std::string thumbnailUrl; + std::string credits; + std::string creditsUrl; + glm::dvec2 celestCoords; + std::string collection; + float zoomLevel; + bool hasCoords; + glm::dvec3 position3d; + }; - struct ImageCollection { - std::string name; - std::string url; - bool loaded = false; - }; + struct ImageCollection { + std::string name; + std::string url; + bool loaded = false; + }; - class WWTDataHandler { - - public: - WWTDataHandler() = default; - ~WWTDataHandler(); - // Image downloading and xml parsing - bool downloadFile(std::string& url, std::string& fileDestination); - void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); - void loadWTMLCollectionsFromURL(std::string url, std::string fileName); - void loadWTMLCollectionsFromDirectory(std::string directory); - - int loadAllImagesFromXMLs(); - const std::vector& getAllImageCollectionUrls() const; - const std::vector& getLoadedImages() const; + class WWTDataHandler { + + public: + WWTDataHandler() = default; + ~WWTDataHandler(); + // Image downloading and xml parsing + bool downloadFile(std::string& url, std::string& fileDestination); + void loadWTMLCollectionsFromURL(std::string url, std::string fileName); + void loadWTMLCollectionsFromDirectory(std::string directory); + int loadAllImagesFromXMLs(); - private: - - int loadImage(tinyxml2::XMLElement* imageSet, std::string collectionName); - void setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, std::string collectionName, ImageData& img); + const std::vector& getAllImageCollectionUrls() const; + const std::vector& getLoadedImages() const; + void loadSpeckData(speck::Dataset& dataset); - std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName); - std::string getURLFromPlace(tinyxml2::XMLElement* place); - tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, std::string name); - tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); + private: + void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); + int loadImage(tinyxml2::XMLElement* imageSet, std::string collectionName); + void setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, std::string collectionName, ImageData& img); - std::vector images; - std::vector imageUrls; - std::vector xmls; + std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName); + std::string getURLFromPlace(tinyxml2::XMLElement* place); + tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, std::string name); + tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); - }; + std::vector images; + std::vector imageUrls; + std::vector xmls; + // 3D position data loaded from speck files + std::unordered_map _3dPositions; + }; } + + #endif // __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 0161f55380..bcbf6a8cfd 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -130,7 +130,6 @@ namespace openspace::skybrowser::luascriptfunctions { } return 0; } - int followCamera(lua_State* L) { // Load images from url @@ -170,6 +169,16 @@ namespace openspace::skybrowser::luascriptfunctions { // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); SkyBrowserModule* module = global::moduleEngine->module(); + // Load speck files for 3D positions + std::filesystem::path globularClusters = absPath("${BASE}/sync/http/digitaluniverse_globularclusters_speck/2/gc.speck"); + std::filesystem::path openClusters = absPath("${BASE}/sync/http/digitaluniverse_openclusters_speck/2/oc.speck"); + + speck::Dataset speckGlobularClusters = speck::loadSpeckFile(globularClusters); + speck::Dataset speckOpenClusters = speck::loadSpeckFile(openClusters); + + module->getWWTDataHandler()->loadSpeckData(speckGlobularClusters); + module->getWWTDataHandler()->loadSpeckData(speckOpenClusters); + // If no data has been loaded yet, load it! if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { // Read from disc diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 964fbbcbad..bdedc757c6 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -4,6 +4,13 @@ #include #include +// For loading the speck files +#include +#include +#include +#include +#include + namespace { constexpr const char* _loggerCat = "WWTDataHandler"; } //namespace @@ -230,9 +237,275 @@ namespace openspace { img.zoomLevel = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) : 0.f; img.credits = credits; img.creditsUrl = creditsUrl; + // Look for 3D position in the data loaded from speck files + auto it = _3dPositions.find(img.name); + if (it != _3dPositions.end()) { + img.position3d = it->second; + } } const std::vector& WWTDataHandler::getLoadedImages() const { return images; } + + void WWTDataHandler::loadSpeckData(speck::Dataset& dataset) { + for (speck::Dataset::Entry entry : dataset.entries) { + if (entry.comment.has_value()) { + _3dPositions[entry.comment.value()] = std::move(entry.position); + } + } + LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + " entries!"); + } } + +// Loading of speck files +namespace { + constexpr bool startsWith(std::string_view lhs, std::string_view rhs) noexcept { + return (rhs.size() <= lhs.size()) && (lhs.substr(0, rhs.size()) == rhs); + } + + void strip(std::string& line) noexcept { + // 1. Remove all spaces from the beginning + // 2. Remove # + // 3. Remove all spaces from the new beginning + // 4. Remove all spaces from the end + + while (!line.empty() && line[0] == ' ') { + line = line.substr(1); + } + + if (!line.empty() && line[0] == '#') { + line = line.substr(1); + } + + while (!line.empty() && line[0] == ' ') { + line = line.substr(1); + } + + while (!line.empty() && line.back() == ' ') { + line = line.substr(0, line.size() - 2); + } + } + + template + void checkSize(U value, std::string_view message) { + if (value > std::numeric_limits::max()) { + throw ghoul::RuntimeError(fmt::format("Error saving file: {}", message)); + } + } +} // namespace + +namespace openspace::speck { + + Dataset loadSpeckFile(std::filesystem::path path, + SkipAllZeroLines skipAllZeroLines) + { + ghoul_assert(std::filesystem::exists(path), "File must exist"); + + std::ifstream file(path); + if (!file.good()) { + throw ghoul::RuntimeError(fmt::format("Failed to open speck file '{}'", path)); + } + + Dataset res; + + int nDataValues = 0; + + std::string line; + // First phase: Loading the header information + while (std::getline(file, line)) { + // Ignore empty line or commented-out lines + if (line.empty() || line[0] == '#') { + continue; + } + + // Guard against wrong line endings (copying files from Windows to Mac) causes + // lines to have a final \r + if (line.back() == '\r') { + line = line.substr(0, line.length() - 1); + } + + strip(line); + + // If the first character is a digit, we have left the preamble and are in the + // data section of the file + if (std::isdigit(line[0]) || line[0] == '-') { + break; + } + + + if (startsWith(line, "datavar")) { + // each datavar line is following the form: + // datavar + // with being the index of the data variable + + std::stringstream str(line); + std::string dummy; + Dataset::Variable v; + str >> dummy >> v.index >> v.name; + + //if (v.name == "orientation" || v.name == "ori" || v.name == "texture") { + // // The values for orientation and the texture indices are handled by + // // their own keywords + //} + //else { + nDataValues += 1; + res.variables.push_back(v); + //} + + continue; + } + + if (startsWith(line, "texturevar")) { + // each texturevar line is following the form: + // texturevar + // where is the data value index where the texture index is stored + if (res.textureDataIndex != -1) { + throw ghoul::RuntimeError(fmt::format( + "Error loading speck file '{}': Texturevar defined twice", + path + )); + } + + std::stringstream str(line); + std::string dummy; + str >> dummy >> res.textureDataIndex; + + //nDataValues += 1; + continue; + } + + if (startsWith(line, "polyorivar")) { + // each texturevar line is following the form: + // texturevar + // where is the data value index where the orientation index storage + // starts. There are 6 values stored in total, xyz + uvw + + if (res.orientationDataIndex != -1) { + throw ghoul::RuntimeError(fmt::format( + "Error loading speck file '{}': Orientation index defined twice", + path + )); + } + + std::stringstream str(line); + std::string dummy; + str >> dummy >> res.orientationDataIndex; + + //nDataValues += 6; + continue; + } + + if (startsWith(line, "texture")) { + // each texture line is following one of two forms: + // 1: texture -M 1 halo.sgi + // 2: texture 1 M1.sgi + // The parameter in #1 is currently being ignored + + std::stringstream str(line); + + std::string dummy; + str >> dummy; + + if (line.find('-') != std::string::npos) { + str >> dummy; + } + + Dataset::Texture texture; + str >> texture.index >> texture.file; + res.textures.push_back(texture); + continue; + } + } + + std::sort( + res.variables.begin(), res.variables.end(), + [](const Dataset::Variable& lhs, const Dataset::Variable& rhs) { + return lhs.index < rhs.index; + } + ); + + std::sort( + res.textures.begin(), res.textures.end(), + [](const Dataset::Texture& lhs, const Dataset::Texture& rhs) { + return lhs.index < rhs.index; + } + ); + + // For the first line, we already loaded it and rejected it above, so if we do another + // std::getline, we'd miss the first data value line + bool isFirst = true; + while (isFirst || std::getline(file, line)) { + isFirst = false; + + // Ignore empty line or commented-out lines + if (line.empty() || line[0] == '#') { + continue; + } + + // Guard against wrong line endings (copying files from Windows to Mac) causes + // lines to have a final \r + if (line.back() == '\r') { + line = line.substr(0, line.length() - 1); + } + + strip(line); + + if (line.empty()) { + continue; + } + + // If the first character is a digit, we have left the preamble and are in the + // data section of the file + if (!std::isdigit(line[0]) && line[0] != '-') { + throw ghoul::RuntimeError(fmt::format( + "Error loading speck file '{}': Header information and datasegment " + "intermixed", path + )); + } + + bool allZero = true; + + std::stringstream str(line); + Dataset::Entry entry; + str >> entry.position.x >> entry.position.y >> entry.position.z; + allZero &= (entry.position == glm::dvec3(0.0)); + + entry.data.resize(nDataValues); + for (int i = 0; i < nDataValues; i += 1) { + str >> entry.data[i]; + allZero &= (entry.data[i] == 0.0); + } + + if (skipAllZeroLines && allZero) { + continue; + } + + std::string rest; + std::getline(str, rest); + if (!rest.empty()) { + + strip(rest); + entry.comment = rest; + } + + res.entries.push_back(std::move(entry)); + + } + +#ifdef _DEBUG + if (!res.entries.empty()) { + size_t nDataValues = res.entries[0].data.size(); + for (const Dataset::Entry& e : res.entries) { + ghoul_assert( + e.data.size() == nDataValues, + "Row had different number of data values" + ); + } + } +#endif + + return res; + } + +} // namespace openspace::speck From 49c03149079285587a1baf32b5c034e250400968 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 11 May 2021 08:44:02 +0200 Subject: [PATCH 093/251] Add class renderable sky browser --- modules/skybrowser/CMakeLists.txt | 2 ++ .../skybrowser/include/renderableskybrowser.h | 23 ++++++++++++++ .../skybrowser/src/renderableskybrowser.cpp | 30 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 modules/skybrowser/include/renderableskybrowser.h create mode 100644 modules/skybrowser/src/renderableskybrowser.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index f61c79f15b..f792be4c41 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -32,6 +32,7 @@ set(HEADER_FILES include/wwtdatahandler.h tinyxml2/tinyxml2.h include/utility.h + include/renderableskybrowser.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -45,6 +46,7 @@ set(SOURCE_FILES src/wwtdatahandler.cpp tinyxml2/tinyxml2.cpp src/utility.cpp + src/renderableskybrowser.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h new file mode 100644 index 0000000000..3eabb6115c --- /dev/null +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -0,0 +1,23 @@ +#ifndef __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ + +#include +#include + +namespace openspace::documentation { struct Documentation; } + +namespace openspace { + + class RenderableSkyBrowser : public RenderablePlane + { + public: + RenderableSkyBrowser(const ghoul::Dictionary& dictionary); + virtual ~RenderableSkyBrowser() = default; + + private: + + }; +} + +#endif // __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ + diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp new file mode 100644 index 0000000000..6fb2c27fd7 --- /dev/null +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -0,0 +1,30 @@ +#include + +namespace { + constexpr const char* _loggerCat = "RenderableSkyBrowser"; + + constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = + { + "BrowserDimensions", + "Browser Dimensions Info", + "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " + }; + + + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { + + // [[codegen::verbatim(BrowserDimensionInfo.description)]] + std::optional browserDimensions; + }; + +#include "renderableskybrowser_codegen.cpp" +} // namespace + +namespace openspace { + + RenderableSkyBrowser::RenderableSkyBrowser(const ghoul::Dictionary& dictionary) + : RenderablePlane(dictionary) + { + } + +} // namespace From fe06e487daac805691ed2f01cd1b14e4ab066a97 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 11 May 2021 14:09:11 +0200 Subject: [PATCH 094/251] Separate conversion functions to a spherical and cartesian and att constant for north pole in J2000 --- modules/skybrowser/include/utility.h | 4 +++- modules/skybrowser/skybrowsermodule_lua.inl | 8 +++++--- modules/skybrowser/src/screenspaceskytarget.cpp | 2 +- modules/skybrowser/src/utility.cpp | 9 ++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 4cfd90e5f9..92cbe93b76 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -11,6 +11,7 @@ namespace openspace::skybrowser { const double SCREENSPACE_Z = -2.1; const double RAD_TO_DEG = 180.0 / M_PI; const double DEG_TO_RAD = M_PI / 180.0; + const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 }; constexpr double infinity = std::numeric_limits::max(); // Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1 @@ -23,7 +24,8 @@ namespace openspace::skybrowser { // J2000 to galactic conversion and vice versa glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); - glm::dvec2 galacticCartesianToJ2000(glm::dvec3 rGal); + glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal); + glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal); glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords); glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance = infinity); glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance = infinity); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index bcbf6a8cfd..3ddb867d0c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -240,9 +240,11 @@ namespace openspace::skybrowser::luascriptfunctions { index++; lua_newtable(L); // Get the view direction of the screen in cartesian J2000 coordinates - - glm::dvec2 sphericalJ2000 = galacticCartesianToJ2000(global::navigationHandler->camera()->viewDirectionWorldSpace()); - glm::dvec3 cartesianJ2000 = skybrowser::sphericalToCartesian(sphericalJ2000); + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + constexpr double infinity = std::numeric_limits::max(); + glm::dvec3 galCoord = camPos + (infinity * global::navigationHandler->camera()->viewDirectionWorldSpace()); + glm::dvec3 cartesianJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(galCoord); + glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000); // Convert to vector so ghoul can read it std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 573510677b..7f1918269e 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -330,7 +330,7 @@ namespace openspace { glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); constexpr double infinity = std::numeric_limits::max(); glm::dvec3 galCoord = camPos + (infinity * getTargetDirectionGalactic()); - return skybrowser::galacticCartesianToJ2000(galCoord); + return skybrowser::galacticCartesianToJ2000Spherical(galCoord); } void ScreenSpaceSkyTarget::animateToCoord(double deltaTime) { diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 8dbad4ea40..d6a358fc8a 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -33,9 +33,12 @@ namespace openspace::skybrowser { return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec); } - glm::dvec2 galacticCartesianToJ2000(glm::dvec3 rGal) { - glm::dvec3 J2000 = glm::transpose(conversionMatrix) * rGal; - return cartesianToSpherical(J2000); + glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) { + return glm::transpose(conversionMatrix) * rGal; + } + + glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) { + return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal)); } glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) { From f1750642cb1ee5218422a956893a9a5b38e030f8 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 11 May 2021 14:09:43 +0200 Subject: [PATCH 095/251] Calculate roll of camera compared to J2000 north pole and send to WWT --- modules/skybrowser/src/screenspaceskybrowser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 77e62cb548..85e54296db 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -225,10 +225,15 @@ namespace openspace { using namespace std::string_literals; ghoul::Dictionary msg; + glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(global::navigationHandler->camera()->lookUpVectorWorldSpace()); + glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(global::navigationHandler->camera()->viewDirectionWorldSpace()); + double angle = glm::degrees(atan2(glm::dot(glm::cross(camUpJ2000, skybrowser::NORTH_POLE), camForwardJ2000), glm::dot(skybrowser::NORTH_POLE, camUpJ2000))); + msg.setValue("event", "center_on_coordinates"s); msg.setValue("ra", celestCoords.x); msg.setValue("dec", celestCoords.y); msg.setValue("fov", fov); + msg.setValue("roll", angle); msg.setValue("instant", moveInstantly); return msg; From 810319ace7ee9394b86c8d9465212c39a6a98c51 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 11 May 2021 14:30:06 +0200 Subject: [PATCH 096/251] Add functions for new calls in the WWT API --- .../include/screenspaceskybrowser.h | 5 +++ modules/skybrowser/skybrowsermodule_lua.inl | 6 +++- .../skybrowser/src/screenspaceskybrowser.cpp | 35 +++++++++++++++++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index b358a00790..f8ecc95fe1 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -24,6 +24,10 @@ namespace openspace { ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; ghoul::Dictionary createMessageForSettingForegroundWWT(const std::string& name) const; ghoul::Dictionary createMessageForSettingForegroundOpacityWWT(double val) const; + ghoul::Dictionary createMessageForAddingImageLayerWWT(const std::string& url); + ghoul::Dictionary createMessageForRemovingImageLayerWWT(int id) const; + ghoul::Dictionary createMessageForSettingOpacityLayerWWT(int id, double opacity) const; + bool sendMessageToWWT(const ghoul::Dictionary& msg); void sendMouseEvent(CefStructBase event, int x, int y) const; void WWTfollowCamera(); @@ -62,6 +66,7 @@ namespace openspace { // For capping the calls to change the zoom from scrolling constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; std::chrono::system_clock::time_point _lastUpdateTime; + int imageId = 0; }; } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 3ddb867d0c..96e2aaf1e4 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -139,9 +139,13 @@ namespace openspace::skybrowser::luascriptfunctions { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; - module->getWWTDataHandler()->loadWTMLCollectionsFromURL(hubble, "root"); + module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); + for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + } + return 1; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 85e54296db..74a9536d71 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -245,22 +245,53 @@ namespace openspace { ghoul::Dictionary msg; msg.setValue("event", "load_image_collection"s); msg.setValue("url", url); + msg.setValue("loadChildFolders", true); return msg; } ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundWWT(const std::string& name) const { - // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "set_foreground_by_name"s); msg.setValue("name", name); + return msg; + } + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForAddingImageLayerWWT(const std::string& url) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_create"s); + msg.setValue("id", std::to_string(imageId)); + msg.setValue("name", url); + // Update ID to ensure that all ID's are unique + imageId++; + + return msg; + } + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForRemovingImageLayerWWT(int id) const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_remove"s); + msg.setValue("id", std::to_string(id)); + + return msg; + } + + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingOpacityLayerWWT(int id, double opacity) const { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_set"s); + msg.setValue("id", std::to_string(id)); + msg.setValue("setting", "opacity"s); + msg.setValue("value", opacity); + return msg; } ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundOpacityWWT(double val) const { - // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "set_foreground_opacity"s); From d8d8cbf2fd7b50e90180e5642d98d5df307a4e9f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 12 May 2021 12:14:18 +0200 Subject: [PATCH 097/251] Add new API functions and load images in a cleaner way from module instead of lua --- .../include/screenspaceskybrowser.h | 9 +- modules/skybrowser/include/wwtdatahandler.h | 28 ++++-- modules/skybrowser/skybrowsermodule.cpp | 34 ++++++- modules/skybrowser/skybrowsermodule.h | 3 + modules/skybrowser/skybrowsermodule_lua.inl | 95 +++++++------------ .../skybrowser/src/screenspaceskybrowser.cpp | 24 ++--- modules/skybrowser/src/wwtdatahandler.cpp | 42 +++++--- 7 files changed, 138 insertions(+), 97 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index f8ecc95fe1..ddde91d386 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -2,6 +2,7 @@ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ #include +#include #include namespace openspace { @@ -24,9 +25,9 @@ namespace openspace { ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; ghoul::Dictionary createMessageForSettingForegroundWWT(const std::string& name) const; ghoul::Dictionary createMessageForSettingForegroundOpacityWWT(double val) const; - ghoul::Dictionary createMessageForAddingImageLayerWWT(const std::string& url); - ghoul::Dictionary createMessageForRemovingImageLayerWWT(int id) const; - ghoul::Dictionary createMessageForSettingOpacityLayerWWT(int id, double opacity) const; + ghoul::Dictionary createMessageForAddingImageLayerWWT(ImageData& url); + ghoul::Dictionary createMessageForRemovingImageLayerWWT(const std::string& id) const; + ghoul::Dictionary createMessageForSettingOpacityLayerWWT(const ImageData& id, double opacity) const; bool sendMessageToWWT(const ghoul::Dictionary& msg); void sendMouseEvent(CefStructBase event, int x, int y) const; @@ -66,7 +67,7 @@ namespace openspace { // For capping the calls to change the zoom from scrolling constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; std::chrono::system_clock::time_point _lastUpdateTime; - int imageId = 0; + int _imageId{ 0 }; }; } diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 687843fe09..7920879e9c 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -54,8 +54,10 @@ namespace openspace::speck { namespace openspace { struct ImageData { + static constexpr int NO_ID = -1; std::string name; std::string thumbnailUrl; + std::string imageUrl; std::string credits; std::string creditsUrl; glm::dvec2 celestCoords; @@ -63,6 +65,7 @@ namespace openspace { float zoomLevel; bool hasCoords; glm::dvec3 position3d; + int id{ NO_ID }; }; struct ImageCollection { @@ -80,20 +83,30 @@ namespace openspace { bool downloadFile(std::string& url, std::string& fileDestination); void loadWTMLCollectionsFromURL(std::string url, std::string fileName); void loadWTMLCollectionsFromDirectory(std::string directory); - int loadAllImagesFromXMLs(); + int loadImagesFromLoadedXMLs(); const std::vector& getAllImageCollectionUrls() const; - const std::vector& getLoadedImages() const; + std::vector& getLoadedImages(); void loadSpeckData(speck::Dataset& dataset); private: - void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName); - int loadImage(tinyxml2::XMLElement* imageSet, std::string collectionName); - void setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, std::string collectionName, ImageData& img); + void loadImagesFromXML(tinyxml2::XMLElement* node, + std::string collectionName); + int loadImageFromXmlNode(tinyxml2::XMLElement* imageSet, + std::string collectionName); + void setImageDataValues(tinyxml2::XMLElement* node, + std::string credits, + std::string creditsUrl, + std::string thumbnail, + std::string collectionName, + std::string imageUrl, + ImageData& img); - std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName); + std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, + std::string elementName); std::string getURLFromPlace(tinyxml2::XMLElement* place); - tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, std::string name); + tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, + std::string name); tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); std::vector images; @@ -101,6 +114,7 @@ namespace openspace { std::vector xmls; // 3D position data loaded from speck files std::unordered_map _3dPositions; + int nImagesWith3dPositions = 0; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 2539c09524..af42ea86e2 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -97,8 +97,8 @@ namespace openspace { "input. An input string should be the name of the system host star" }, { - "follow", - &skybrowser::luascriptfunctions::followCamera, + "loadImagesToWWT", + &skybrowser::luascriptfunctions::loadImagesToWWT, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " @@ -458,6 +458,36 @@ void SkyBrowserModule::setSelectedBrowser(int i) { int SkyBrowserModule::getSelectedBrowserIndex() { return selectedBrowser; } + +int SkyBrowserModule::loadImages(const std::string& root, int readingMode) { + + // Load speck files for 3D positions + std::filesystem::path globularClusters = absPath("${BASE}/sync/http/digitaluniverse_globularclusters_speck/2/gc.speck"); + std::filesystem::path openClusters = absPath("${BASE}/sync/http/digitaluniverse_openclusters_speck/2/oc.speck"); + + speck::Dataset speckGlobularClusters = speck::loadSpeckFile(globularClusters); + speck::Dataset speckOpenClusters = speck::loadSpeckFile(openClusters); + + dataHandler->loadSpeckData(speckGlobularClusters); + dataHandler->loadSpeckData(speckOpenClusters); + + int nLoadedImages; + // Read from disc + if (readingMode == FROM_DIRECTORY) { + LINFO("Loading images from directory"); + dataHandler->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); + + } + // Reading from url + else if (readingMode == FROM_URL) { + LINFO("Loading images from url"); + dataHandler->loadWTMLCollectionsFromURL(root, "root"); + } + nLoadedImages = dataHandler->loadImagesFromLoadedXMLs(); + LINFO("Loaded " + std::to_string(nLoadedImages) + " WorldWide Telescope images."); + + return nLoadedImages; +} /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 5017f8687a..cf9d984ad4 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -48,6 +48,8 @@ class WWTDataHandler; class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; + constexpr static const int FROM_DIRECTORY = 0; + constexpr static const int FROM_URL = 1; SkyBrowserModule(); virtual ~SkyBrowserModule() = default; @@ -60,6 +62,7 @@ public: void setSelectedBrowser(ScreenSpaceRenderable* ptr); void setSelectedBrowser(int i); int getSelectedBrowserIndex(); + int loadImages(const std::string& root, int readingMode = FROM_URL); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 96e2aaf1e4..dafc3ec543 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -37,40 +37,39 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; + ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; + ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); - const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; - // Load image collection, if it isn't loaded already - // TODO: Update or remove with new WWT API - const std::vector& collections = module->getWWTDataHandler()->getAllImageCollectionUrls(); - auto it = std::find_if(collections.begin(), collections.end(), [&](const ImageCollection& coll) { - return coll.name == resultImage.collection; - }); - if (!it->loaded) { - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(it->url)); - } - LINFO("Loading image " + resultImage.name); - browser->sendMessageToWWT(browser->createMessageForSettingForegroundWWT(resultImage.name)); - browser->sendMessageToWWT(browser->createMessageForSettingForegroundOpacityWWT(100)); - - // Only move target if the image has coordinates + ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + + // Load image, if the image has not been loaded yet + if (resultImage.id == ImageData::NO_ID) { + LINFO("Loading image " + resultImage.name); + ghoul::Dictionary msg = selectedBrowser->createMessageForAddingImageLayerWWT(resultImage); + selectedBrowser->sendMessageToWWT(msg); + selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForSettingOpacityLayerWWT(resultImage, 1.0)); + } + + // If the image has coordinates, move the target if (resultImage.hasCoords) { // Animate the target to the image coord position // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 - if (browser->getSkyTarget()) { - browser->getSkyTarget()->unlock(); - browser->getSkyTarget()->startAnimation(resultImage.celestCoords, resultImage.zoomLevel / 6); + if (selectedTarget) { + selectedTarget->unlock(); + selectedTarget->startAnimation(resultImage.celestCoords, resultImage.zoomLevel / 6); glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); float r = windowRatio.x / windowRatio.y; // Check if image coordinate is within current FOV - if (!(abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0) - || imgCoordsOnScreen.z > 0) { + bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); + bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; + // If the coordinate is not in view, rotate camera + if (!coordIsWithinView || coordIsBehindCamera) { module->startRotation(resultImage.celestCoords); } - } } + return 0; } @@ -131,20 +130,16 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } - int followCamera(lua_State* L) { + int loadImagesToWWT(lua_State* L) { // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::followCamera"); - LINFO("Loading images from url"); - SkyBrowserModule* module = global::moduleEngine->module(); - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::loadImagesToWWT"); + SkyBrowserModule* module = global::moduleEngine->module(); - module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root"); - LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs())); - - for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); - } + // Load the collections here because here we know that the browser can execute javascript + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + } return 1; } @@ -152,20 +147,7 @@ namespace openspace::skybrowser::luascriptfunctions { int moveBrowser(lua_State* L) { // Load images from local directory ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - SkyBrowserModule* module = global::moduleEngine->module(); - module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); - std::string noOfLoadedImgs = std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs()); - LINFO("Loaded " + noOfLoadedImgs + " WorldWide Telescope images."); - - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable("SkyBrowser1")); - // Load all image collection urls - //const std::vector& imageUrls = module->getWWTDataHandler()->getAllImageCollectionUrls(); - //for (const std::string url : imageUrls) { - // browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(url)); - //} - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(hubble)); + return 1; } @@ -173,22 +155,15 @@ namespace openspace::skybrowser::luascriptfunctions { // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); SkyBrowserModule* module = global::moduleEngine->module(); - // Load speck files for 3D positions - std::filesystem::path globularClusters = absPath("${BASE}/sync/http/digitaluniverse_globularclusters_speck/2/gc.speck"); - std::filesystem::path openClusters = absPath("${BASE}/sync/http/digitaluniverse_openclusters_speck/2/oc.speck"); - speck::Dataset speckGlobularClusters = speck::loadSpeckFile(globularClusters); - speck::Dataset speckOpenClusters = speck::loadSpeckFile(openClusters); + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; - module->getWWTDataHandler()->loadSpeckData(speckGlobularClusters); - module->getWWTDataHandler()->loadSpeckData(speckOpenClusters); + module->loadImages(root, SkyBrowserModule::FROM_DIRECTORY); - // If no data has been loaded yet, load it! + // If no data has been loaded yet, download the data from the web! if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { - // Read from disc - //moveBrowser(L); - // Read from URL - followCamera(L); + module->loadImages(root, SkyBrowserModule::FROM_URL); } // Create Lua table to send to the GUI diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 74a9536d71..57de4ccf18 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,7 @@ namespace openspace { } bool ScreenSpaceSkyBrowser::initializeGL() { + global::moduleEngine->module()->addRenderable(this); setConnectedTarget(); if (_skyTarget) { @@ -240,7 +242,6 @@ namespace openspace { } ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForLoadingWWTImgColl(const std::string& url) const { - // https://docs.worldwidetelescope.org/data-guide/1/data-file-formats/collections/sample-blank-collection.wtml using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "load_image_collection"s); @@ -259,32 +260,33 @@ namespace openspace { return msg; } - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForAddingImageLayerWWT(const std::string& url) { + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForAddingImageLayerWWT(ImageData& image) { + std::string idString = std::to_string(_imageId); using namespace std::string_literals; ghoul::Dictionary msg; + image.id = _imageId; msg.setValue("event", "image_layer_create"s); - msg.setValue("id", std::to_string(imageId)); - msg.setValue("name", url); - // Update ID to ensure that all ID's are unique - imageId++; - + msg.setValue("id", idString); + msg.setValue("url", image.imageUrl); + _imageId++; return msg; } - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForRemovingImageLayerWWT(int id) const { + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForRemovingImageLayerWWT(const std::string& id) const { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_remove"s); - msg.setValue("id", std::to_string(id)); + msg.setValue("id", id); return msg; } - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingOpacityLayerWWT(int id, double opacity) const { + ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingOpacityLayerWWT(const ImageData& image, double opacity) const { + std::string idString = std::to_string(image.id); using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_set"s); - msg.setValue("id", std::to_string(id)); + msg.setValue("id", idString); msg.setValue("setting", "opacity"s); msg.setValue("value", opacity); diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index bdedc757c6..3eb5b51248 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -94,7 +94,7 @@ namespace openspace { } - int WWTDataHandler::loadAllImagesFromXMLs() { + int WWTDataHandler::loadImagesFromLoadedXMLs() { for (tinyxml2::XMLDocument* doc : xmls) { tinyxml2::XMLElement* root = doc->FirstChildElement(); std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; @@ -112,6 +112,8 @@ namespace openspace { } return a.name < b.name; }); + LINFO(std::to_string(nImagesWith3dPositions) + " 3D positions were matched in the speck files!"); + return images.size(); } @@ -129,7 +131,7 @@ namespace openspace { while (ptr) { // If node is an image or place, load it if (std::string(ptr->Name()) == "ImageSet" || std::string(ptr->Name()) == "Place") { - loadImage(ptr, collectionName); + loadImageFromXmlNode(ptr, collectionName); } // If node is another folder, open recursively else if (std::string(ptr->Name()) == "Folder") { @@ -145,38 +147,44 @@ namespace openspace { } - int WWTDataHandler::loadImage(tinyxml2::XMLElement* node, std::string collectionName) { + int WWTDataHandler::loadImageFromXmlNode(tinyxml2::XMLElement* node, std::string collectionName) { // Only load "Sky" type images if (std::string(node->FindAttribute("DataSetType")->Value()) != "Sky") return -1; - std::string url; + std::string thumbnailUrl; std::string credits; std::string creditsUrl; + std::string imageUrl; tinyxml2::XMLElement* imageSet = nullptr; // Get url. The thumbnail can be located either in the Place or the ImageSet if (std::string(node->Name()) == "ImageSet") { - url = getChildNodeContentFromImageSet(node, "ThumbnailUrl"); + thumbnailUrl = getChildNodeContentFromImageSet(node, "ThumbnailUrl"); imageSet = node; } else if (std::string(node->Name()) == "Place") { - url = getURLFromPlace(node); + thumbnailUrl = getURLFromPlace(node); imageSet = getChildNode(node, "ImageSet"); } else { return -1; } - - // Only load images that have a thumbnail - if (url == "" || !imageSet) { + + // Only load images that have a thumbnail image url + if (thumbnailUrl == "" || !imageSet) { return -1; } - // The credits are always children nodes of ImageSet + // Only load images that contain a image url + if (!imageSet->FindAttribute("Url")) { + return -1; + } + // The credits and image url are always children nodes of ImageSet credits = getChildNodeContentFromImageSet(imageSet, "Credits"); creditsUrl = getChildNodeContentFromImageSet(imageSet, "CreditsUrl"); + imageUrl = imageSet->FindAttribute("Url")->Value(); ImageData image{}; - setImageDataValues(node, credits, creditsUrl, url, collectionName, image); + setImageDataValues(node, credits, creditsUrl, thumbnailUrl, collectionName, imageUrl, image); images.push_back(image); // Return index of image in vector @@ -223,7 +231,13 @@ namespace openspace { return imageSet; } - void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, std::string collectionName, ImageData& img) { + void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, + std::string credits, + std::string creditsUrl, + std::string thumbnail, + std::string collectionName, + std::string imageUrl, + ImageData& img) { // Get attributes for the image img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; img.hasCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); @@ -237,14 +251,16 @@ namespace openspace { img.zoomLevel = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) : 0.f; img.credits = credits; img.creditsUrl = creditsUrl; + img.imageUrl = imageUrl; // Look for 3D position in the data loaded from speck files auto it = _3dPositions.find(img.name); if (it != _3dPositions.end()) { img.position3d = it->second; + nImagesWith3dPositions++; } } - const std::vector& WWTDataHandler::getLoadedImages() const { + std::vector& WWTDataHandler::getLoadedImages() { return images; } From b95fa7a701b4379b4c493b7584e099799533bf44 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 12 May 2021 15:10:43 +0200 Subject: [PATCH 098/251] Load images from url automatically if the folder WWTimagedata doesn't exist in module --- .../include/screenspaceskybrowser.h | 3 ++ modules/skybrowser/include/wwtdatahandler.h | 5 ++- modules/skybrowser/skybrowsermodule.cpp | 23 ++++------ modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 22 ++++------ .../skybrowser/src/screenspaceskybrowser.cpp | 8 ++++ modules/skybrowser/src/wwtdatahandler.cpp | 43 ++++++++++++++++--- 7 files changed, 68 insertions(+), 38 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index ddde91d386..89be3644e0 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -36,6 +36,8 @@ namespace openspace { void setVerticalFieldOfView(float fov); void scrollZoom(float scroll); ScreenSpaceSkyTarget* getSkyTarget(); + bool hasLoadedCollections(); + void setHasLoadedCollections(bool isLoaded); // Translation //void translate(glm::vec2 translation); @@ -68,6 +70,7 @@ namespace openspace { constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; std::chrono::system_clock::time_point _lastUpdateTime; int _imageId{ 0 }; + bool _hasLoadedCollections{ false }; }; } diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 7920879e9c..0847026e46 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -81,8 +81,8 @@ namespace openspace { ~WWTDataHandler(); // Image downloading and xml parsing bool downloadFile(std::string& url, std::string& fileDestination); - void loadWTMLCollectionsFromURL(std::string url, std::string fileName); - void loadWTMLCollectionsFromDirectory(std::string directory); + void loadWTMLCollectionsFromURL(std::string directory, std::string url, std::string fileName); + bool loadWTMLCollectionsFromDirectory(std::string directory); int loadImagesFromLoadedXMLs(); const std::vector& getAllImageCollectionUrls() const; @@ -101,6 +101,7 @@ namespace openspace { std::string collectionName, std::string imageUrl, ImageData& img); + bool directoryExists(std::string& path); std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index af42ea86e2..03baf99093 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -88,14 +88,6 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, - { - "move", - &skybrowser::luascriptfunctions::moveBrowser, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, { "loadImagesToWWT", &skybrowser::luascriptfunctions::loadImagesToWWT, @@ -459,7 +451,7 @@ int SkyBrowserModule::getSelectedBrowserIndex() { return selectedBrowser; } -int SkyBrowserModule::loadImages(const std::string& root, int readingMode) { +int SkyBrowserModule::loadImages(const std::string& root, const std::string& directory) { // Load speck files for 3D positions std::filesystem::path globularClusters = absPath("${BASE}/sync/http/digitaluniverse_globularclusters_speck/2/gc.speck"); @@ -473,16 +465,17 @@ int SkyBrowserModule::loadImages(const std::string& root, int readingMode) { int nLoadedImages; // Read from disc - if (readingMode == FROM_DIRECTORY) { + + bool loadedImages = dataHandler->loadWTMLCollectionsFromDirectory(directory); + // Reading from url if there is no directory + if (loadedImages) { LINFO("Loading images from directory"); - dataHandler->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/")); - } - // Reading from url - else if (readingMode == FROM_URL) { + else { LINFO("Loading images from url"); - dataHandler->loadWTMLCollectionsFromURL(root, "root"); + dataHandler->loadWTMLCollectionsFromURL(directory, root, "root"); } + nLoadedImages = dataHandler->loadImagesFromLoadedXMLs(); LINFO("Loaded " + std::to_string(nLoadedImages) + " WorldWide Telescope images."); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index cf9d984ad4..c4fb200214 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -62,7 +62,7 @@ public: void setSelectedBrowser(ScreenSpaceRenderable* ptr); void setSelectedBrowser(int i); int getSelectedBrowserIndex(); - int loadImages(const std::string& root, int readingMode = FROM_URL); + int loadImages(const std::string& root, const std::string& directory); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index dafc3ec543..b42fc9aa8a 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -45,8 +45,7 @@ namespace openspace::skybrowser::luascriptfunctions { // Load image, if the image has not been loaded yet if (resultImage.id == ImageData::NO_ID) { LINFO("Loading image " + resultImage.name); - ghoul::Dictionary msg = selectedBrowser->createMessageForAddingImageLayerWWT(resultImage); - selectedBrowser->sendMessageToWWT(msg); + selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForAddingImageLayerWWT(resultImage)); selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForSettingOpacityLayerWWT(resultImage, 1.0)); } @@ -138,17 +137,13 @@ namespace openspace::skybrowser::luascriptfunctions { // Load the collections here because here we know that the browser can execute javascript std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + if (!browser->hasLoadedCollections()) { + browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + browser->setHasLoadedCollections(true); + } } - return 1; - } - - int moveBrowser(lua_State* L) { - // Load images from local directory - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser"); - - return 1; + return 0; } int getListOfImages(lua_State* L) { @@ -158,12 +153,11 @@ namespace openspace::skybrowser::luascriptfunctions { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; - - module->loadImages(root, SkyBrowserModule::FROM_DIRECTORY); + std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); // If no data has been loaded yet, download the data from the web! if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { - module->loadImages(root, SkyBrowserModule::FROM_URL); + module->loadImages(root, directory); } // Create Lua table to send to the GUI diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 57de4ccf18..63bf9c9809 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -177,6 +177,14 @@ namespace openspace { return _skyTarget; } + bool ScreenSpaceSkyBrowser::hasLoadedCollections() { + return _hasLoadedCollections; + } + + void ScreenSpaceSkyBrowser::setHasLoadedCollections(bool isLoaded) { + _hasLoadedCollections = isLoaded; + } + float ScreenSpaceSkyBrowser::fieldOfView() const { return _vfieldOfView; } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 3eb5b51248..6a58a60269 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -3,6 +3,8 @@ #include // To iterate through files in directory #include #include +#include +#include // For loading the speck files #include @@ -30,17 +32,25 @@ namespace openspace { return wtml_root.hasSucceeded(); } - void WWTDataHandler::loadWTMLCollectionsFromURL(std::string url, std::string fileName) { + void WWTDataHandler::loadWTMLCollectionsFromURL(std::string directory, std::string url, std::string fileName) { + // Look for WWT image data folder + if (!directoryExists(directory)) { + std::string newDir = directory; + newDir.pop_back(); + LINFO("Creating directory WWTimagedata"); + std::filesystem::create_directory(newDir); + } + // Get file - std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/") + fileName + ".aspx"; - if (!downloadFile(url, fileDestination)) { + std::string file = directory + fileName + ".aspx"; + if (!downloadFile(url, file)) { LINFO("Couldn't download file " + url); return; } // Parse to XML using namespace tinyxml2; tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - doc->LoadFile(fileDestination.c_str()); + doc->LoadFile(file.c_str()); XMLElement* root = doc->RootElement(); XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); @@ -63,13 +73,33 @@ namespace openspace { std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : ""; std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : ""; if (subUrl != "" && subName != "") { - loadWTMLCollectionsFromURL(subUrl, subName); + loadWTMLCollectionsFromURL(directory, subUrl, subName); } element = element->NextSiblingElement(); } } - void WWTDataHandler::loadWTMLCollectionsFromDirectory(std::string directory) { + + bool WWTDataHandler::directoryExists(std::string& path) + { + struct stat info; + + int statRC = stat(path.c_str(), &info); + if (statRC != 0) + { + if (errno == ENOENT) { return false; } // something along the path does not exist + if (errno == ENOTDIR) { return false; } // something in path prefix is not a dir + return false; + } + + bool directoryExists = (info.st_mode & S_IFDIR); + + return directoryExists; + } + + bool WWTDataHandler::loadWTMLCollectionsFromDirectory(std::string directory) { + + if (!directoryExists(directory)) return false; for (const auto& entry : std::filesystem::directory_iterator(directory)) { tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); @@ -84,6 +114,7 @@ namespace openspace { xmls.push_back(doc); } } + return true; } std::ostream& operator<<(std::ostream& os, const ImageData& img) { From 546362c93073f5dd76f367df9746b700be397592 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 12 May 2021 16:04:36 +0200 Subject: [PATCH 099/251] Add radius, azimuth, elevation to assets but set it to use cartesian positions as default --- data/assets/hoverCircle.asset | 2 ++ data/assets/skyBrowser.asset | 4 +++- data/assets/skyTarget.asset | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index d21f18fba3..f943b13beb 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -5,6 +5,8 @@ local assetHelper = asset.require('util/asset_helper') Type = "ScreenSpaceImageLocal", Name = "HoverCircle", FaceCamera = false, + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome Scale= 0.015, Enabled = false, TexturePath = "D:/Ylvas/OpenSpace/data/assets/circle.png", diff --git a/data/assets/skyBrowser.asset b/data/assets/skyBrowser.asset index 0ae4db96ff..93315772fb 100644 --- a/data/assets/skyBrowser.asset +++ b/data/assets/skyBrowser.asset @@ -7,7 +7,9 @@ local assetHelper = asset.require('util/asset_helper') Url = "http://localhost:8000/", FaceCamera = false, TargetID = "SkyTarget1", - CartesianPosition = {-1.0, -0.5, -2.1} + CartesianPosition = {-1.0, -0.5, -2.1}, + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome }; assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/data/assets/skyTarget.asset b/data/assets/skyTarget.asset index a699553bc2..f758f2cbaf 100644 --- a/data/assets/skyTarget.asset +++ b/data/assets/skyTarget.asset @@ -5,7 +5,9 @@ local assetHelper = asset.require('util/asset_helper') Identifier = "SkyTarget1", Name = "Target", FaceCamera = false, - BrowserID = "SkyBrowser1" + BrowserID = "SkyBrowser1", + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome }; assetHelper.registerScreenSpaceRenderables(asset, { spec }) From 984012ac3401f6c1d7d321642d856e013eb88f07 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 12 May 2021 16:34:33 +0200 Subject: [PATCH 100/251] Remove special characters and white spaces when matchin WWT image names with speck images --- modules/skybrowser/include/wwtdatahandler.h | 1 + modules/skybrowser/src/wwtdatahandler.cpp | 22 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 0847026e46..196e12f3b0 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -88,6 +88,7 @@ namespace openspace { const std::vector& getAllImageCollectionUrls() const; std::vector& getLoadedImages(); void loadSpeckData(speck::Dataset& dataset); + std::string createSearchableString(std::string name); private: void loadImagesFromXML(tinyxml2::XMLElement* node, diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 6a58a60269..333f4e8b37 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // For loading the speck files #include @@ -284,7 +285,9 @@ namespace openspace { img.creditsUrl = creditsUrl; img.imageUrl = imageUrl; // Look for 3D position in the data loaded from speck files - auto it = _3dPositions.find(img.name); + std::string str = createSearchableString(img.name); + // Look for 3D coordinate + auto it = _3dPositions.find(str); if (it != _3dPositions.end()) { img.position3d = it->second; nImagesWith3dPositions++; @@ -298,11 +301,26 @@ namespace openspace { void WWTDataHandler::loadSpeckData(speck::Dataset& dataset) { for (speck::Dataset::Entry entry : dataset.entries) { if (entry.comment.has_value()) { - _3dPositions[entry.comment.value()] = std::move(entry.position); + std::string name = createSearchableString(entry.comment.value()); + _3dPositions[name] = std::move(entry.position); } } LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + " entries!"); } + + std::string WWTDataHandler::createSearchableString(std::string str) { + // Remove white spaces and all special characters + str.erase(std::remove_if(str.begin(), str.end(), [](char c) { + bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); + return !isNumberOrLetter; + }), + str.end()); + // Make the word lower case + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::tolower(c); }); + return str; + } + } // Loading of speck files From d2871392d725e44a7f00b5bb628719a4384aa55a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 18 May 2021 11:19:31 +0200 Subject: [PATCH 101/251] Add functionality to render a browser in renderable sky browser and add it in module --- data/assets/renderableBrowser.asset | 33 ++++ .../skybrowser/include/renderableskybrowser.h | 63 ++++++++ modules/skybrowser/skybrowsermodule.cpp | 6 +- modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 1 + .../skybrowser/src/renderableskybrowser.cpp | 153 ++++++++++++++++-- 6 files changed, 247 insertions(+), 10 deletions(-) create mode 100644 data/assets/renderableBrowser.asset diff --git a/data/assets/renderableBrowser.asset b/data/assets/renderableBrowser.asset new file mode 100644 index 0000000000..7f04a9101f --- /dev/null +++ b/data/assets/renderableBrowser.asset @@ -0,0 +1,33 @@ +local assetHelper = asset.require("util/asset_helper") +local transforms = asset.require("scene/solarsystem/sun/transforms") + +local PARSEC_CONSTANT = 3.0856776E16; + +local spec = { + Identifier = "RenderableSkyBrowser1", + Parent = transforms.SolarSystemBarycenter.Identifier, + Transform = { + Translation = { + Type = "StaticTranslation", + Position = { + -3.915 * PARSEC_CONSTANT, + -150.153 * PARSEC_CONSTANT, + -120.706 * PARSEC_CONSTANT + } + }, + }, + Renderable = { + Type = "RenderableSkyBrowser", + Size = 10.0E11, + Origin = "Center", + Billboard = true, + Url = "http://localhost:8000" + }, + GUI = { + Name = "Renderable Sky Browser", + Path = "/SkyBrowser", + } +} + +local objects = { spec } +assetHelper.registerSceneGraphNodesAndExport(asset, objects) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 3eabb6115c..a98693820a 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -3,18 +3,81 @@ #include #include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4100) +#endif // _MSC_VER + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + +#include + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#ifdef _MSC_VER +#pragma warning (pop) +#endif // _MSC_VER + +namespace ghoul::opengl { class Texture; } namespace openspace::documentation { struct Documentation; } namespace openspace { + class BrowserInstance; + class RenderHandler; + class WebKeyboardHandler; + class RenderableSkyBrowser : public RenderablePlane { public: + static constexpr const char* KeyIdentifier = "Identifier"; + RenderableSkyBrowser(const ghoul::Dictionary& dictionary); virtual ~RenderableSkyBrowser() = default; + void initializeGL() override; + void deinitializeGL() override; + + void update(const UpdateData& data) override; + + protected: + + properties::Vec2Property _dimensions; + std::unique_ptr _browserInstance; + std::unique_ptr _texture; + private: + class ScreenSpaceRenderHandler : public WebRenderHandler { + public: + void draw() override; + void render() override; + + void setTexture(GLuint t); + }; + + CefRefPtr _renderHandler; + + void bindTexture() override; + + properties::StringProperty _url; + + properties::TriggerProperty _reload; + + CefRefPtr _keyboardHandler; + + glm::ivec2 _objectSize = glm::ivec2(0); + bool _isUrlDirty = false; + bool _isDimensionsDirty = false; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 03baf99093..3d5e463443 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -360,8 +360,12 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); // register ScreenSpaceTarget - ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); + + // Register Renderable Skybrowser + auto fRenderable = FactoryManager::ref().factory(); + ghoul_assert(fRenderable, "Renderable factory was not created"); + fRenderable->registerClass("RenderableSkyBrowser"); // Create data handler dynamically to avoid the linking error that // came up when including the include file in the module header file dataHandler = new WWTDataHandler(); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index c4fb200214..9ef6d61ba4 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -41,6 +41,7 @@ namespace openspace { class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; +class RenderableSkyBrowser; class ScreenSpaceRenderable; class WWTDataHandler; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b42fc9aa8a..6bb76ebae2 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 6fb2c27fd7..302111d3b6 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,19 +1,42 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace { + constexpr const char* _loggerCat = "RenderableSkyBrowser"; - constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = - { - "BrowserDimensions", - "Browser Dimensions Info", - "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " + const openspace::properties::Property::PropertyInfo DimensionsInfo = { + "Dimensions", + "Browser Dimensions", + "Set the dimensions of the web browser windows." + }; + const openspace::properties::Property::PropertyInfo UrlInfo = { + "Url", + "URL", + "The URL to load" }; + const openspace::properties::Property::PropertyInfo ReloadInfo = { + "Reload", + "Reload", + "Reload the web browser" + }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - // [[codegen::verbatim(BrowserDimensionInfo.description)]] + // [[codegen::verbatim(DimensionsInfo.description)]] std::optional browserDimensions; }; @@ -22,9 +45,121 @@ namespace { namespace openspace { - RenderableSkyBrowser::RenderableSkyBrowser(const ghoul::Dictionary& dictionary) - : RenderablePlane(dictionary) - { + void RenderableSkyBrowser::ScreenSpaceRenderHandler::draw() {} + + void RenderableSkyBrowser::ScreenSpaceRenderHandler::render() {} + + void RenderableSkyBrowser::ScreenSpaceRenderHandler::setTexture(GLuint t) { + _texture = t; } + + RenderableSkyBrowser::RenderableSkyBrowser(const ghoul::Dictionary& dictionary) + : RenderablePlane(dictionary) + , _url(UrlInfo) + , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) + , _reload(ReloadInfo) + { + + std::string identifier; + if (dictionary.hasValue(KeyIdentifier)) { + identifier = dictionary.value(KeyIdentifier); + } + else { + identifier = "RenderableSkyBrowser"; + } + setIdentifier(identifier); + + if (dictionary.hasValue(UrlInfo.identifier)) { + _url = dictionary.value(UrlInfo.identifier); + } + + // Ensure the texture is a square for now + // Maybe change later + glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); + float maxDimension = std::max(windowDimensions.x, windowDimensions.y); + _dimensions = { maxDimension, maxDimension }; + + // Create browser and render handler + _renderHandler = new ScreenSpaceRenderHandler(); + _keyboardHandler = new WebKeyboardHandler(); + _browserInstance = std::make_unique( + _renderHandler, + _keyboardHandler + ); + + _url.onChange([this]() { _isUrlDirty = true; }); + _dimensions.onChange([this]() { _isDimensionsDirty = true; }); + _reload.onChange([this]() { _browserInstance->reloadBrowser(); }); + + addProperty(_url); + addProperty(_dimensions); + addProperty(_reload); + + WebBrowserModule* webBrowser = global::moduleEngine->module(); + if (webBrowser) { + webBrowser->addBrowser(_browserInstance.get()); + } + } + + void RenderableSkyBrowser::initializeGL() { + RenderablePlane::initializeGL(); + _texture = std::make_unique( + glm::uvec3(_dimensions.value(), 1.0f) + ); + + _renderHandler->setTexture(*_texture); + + _browserInstance->initialize(); + _browserInstance->loadUrl(_url); + } + + void RenderableSkyBrowser::deinitializeGL() { + RenderablePlane::deinitializeGL(); + _renderHandler->setTexture(0); + _texture = nullptr; + + std::string urlString; + _url.getStringValue(urlString); + LDEBUG(fmt::format("Deinitializing RenderableSkyBrowser: {}", urlString)); + + _browserInstance->close(true); + + WebBrowserModule* webBrowser = global::moduleEngine->module(); + if (webBrowser) { + webBrowser->removeBrowser(_browserInstance.get()); + _browserInstance.reset(); + } + else { + LWARNING("Could not find WebBrowserModule"); + } + + RenderablePlane::deinitializeGL(); + } + + void RenderableSkyBrowser::update(const UpdateData& data) { + RenderablePlane::update(data); + _renderHandler->updateTexture(); + _objectSize = _texture->dimensions(); + + if (_isUrlDirty) { + _browserInstance->loadUrl(_url); + _isUrlDirty = false; + } + + if (_isDimensionsDirty) { + _browserInstance->reshape(_dimensions.value()); + _isDimensionsDirty = false; + } + } + + + void RenderableSkyBrowser::bindTexture() { + if (_texture) { + _texture->bind(); + } + else { + glBindTexture(GL_TEXTURE_2D, 0); + } + } } // namespace From 19d24e90d728fe395317c55f2997495f6895cf8a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 19 May 2021 12:01:20 +0200 Subject: [PATCH 102/251] Add functionality for 3D browser: wwt messages and function to create an instance in lua api --- .../skybrowser/include/renderableskybrowser.h | 4 + .../include/screenspaceskybrowser.h | 11 +- modules/skybrowser/include/utility.h | 68 ++++-- modules/skybrowser/include/wwtdatahandler.h | 5 +- modules/skybrowser/skybrowsermodule.cpp | 16 +- modules/skybrowser/skybrowsermodule.h | 3 + modules/skybrowser/skybrowsermodule_lua.inl | 203 +++++++++++----- .../skybrowser/src/renderableskybrowser.cpp | 22 +- .../skybrowser/src/screenspaceskybrowser.cpp | 109 +-------- modules/skybrowser/src/utility.cpp | 219 +++++++++++++----- modules/skybrowser/src/wwtdatahandler.cpp | 8 +- 11 files changed, 400 insertions(+), 268 deletions(-) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index a98693820a..3e53aee0de 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -50,6 +50,10 @@ namespace openspace { void update(const UpdateData& data) override; + void executeJavascript(std::string script) const; + bool sendMessageToWWT(const ghoul::Dictionary& msg); + + protected: properties::Vec2Property _dimensions; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 89be3644e0..1f26d67467 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -20,17 +20,7 @@ namespace openspace { // Communication with the webpage and WWT void executeJavascript(std::string script) const; - ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly = true) const; - ghoul::Dictionary createMessageForPausingWWTTime() const; - ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const; - ghoul::Dictionary createMessageForSettingForegroundWWT(const std::string& name) const; - ghoul::Dictionary createMessageForSettingForegroundOpacityWWT(double val) const; - ghoul::Dictionary createMessageForAddingImageLayerWWT(ImageData& url); - ghoul::Dictionary createMessageForRemovingImageLayerWWT(const std::string& id) const; - ghoul::Dictionary createMessageForSettingOpacityLayerWWT(const ImageData& id, double opacity) const; - bool sendMessageToWWT(const ghoul::Dictionary& msg); - void sendMouseEvent(CefStructBase event, int x, int y) const; void WWTfollowCamera(); float fieldOfView() const; void setVerticalFieldOfView(float fov); @@ -38,6 +28,7 @@ namespace openspace { ScreenSpaceSkyTarget* getSkyTarget(); bool hasLoadedCollections(); void setHasLoadedCollections(bool isLoaded); + void addImage(ImageData& image); // Translation //void translate(glm::vec2 translation); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 92cbe93b76..3490aba153 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,34 +8,51 @@ #include -namespace openspace::skybrowser { - const double SCREENSPACE_Z = -2.1; - const double RAD_TO_DEG = 180.0 / M_PI; - const double DEG_TO_RAD = M_PI / 180.0; - const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 }; - constexpr double infinity = std::numeric_limits::max(); +namespace openspace { + namespace skybrowser { + const double SCREENSPACE_Z = -2.1; + const double RAD_TO_DEG = 180.0 / M_PI; + const double DEG_TO_RAD = M_PI / 180.0; + const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 }; + constexpr double infinity = std::numeric_limits::max(); - // Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.054875539390, 0.494109453633, -0.867666135681, // col 0 - -0.873437104725, -0.444829594298, -0.198076389622, // col 1 - -0.483834991775, 0.746982248696, 0.455983794523 // col 2 - }); + // Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1 + const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.054875539390, 0.494109453633, -0.867666135681, // col 0 + -0.873437104725, -0.444829594298, -0.198076389622, // col 1 + -0.483834991775, 0.746982248696, 0.455983794523 // col 2 + }); - // J2000 to galactic conversion and vice versa - glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); - glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); - glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal); - glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal); - glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords); - glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance = infinity); - glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance = infinity); - // Convert J2000, spherical or Cartesian, to screen space - glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords); - glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); - - glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord); + // J2000 to galactic conversion and vice versa + glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); + glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); + glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal); + glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal); + glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords); + glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, + double distance = infinity); + glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, + double distance = infinity); + // Convert J2000, spherical or Cartesian, to screen space + glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords); + glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); + glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord); + } + namespace wwtmessage { + // WWT messages + ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, + const double fov, const bool moveInstantly = true); + ghoul::Dictionary loadCollection(const std::string& url); + ghoul::Dictionary setForeground(const std::string& name); + ghoul::Dictionary createImageLayer(ImageData& image, int id = 0); + ghoul::Dictionary removeImageLayer(const std::string& id); + ghoul::Dictionary setLayerOpacity(const ImageData& image, + double opacity); + ghoul::Dictionary setForegroundOpacity(double val); + } } + + diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 196e12f3b0..90cc02e2cc 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -62,8 +62,9 @@ namespace openspace { std::string creditsUrl; glm::dvec2 celestCoords; std::string collection; - float zoomLevel; - bool hasCoords; + float fov; + bool hasCelestCoords{ false }; + bool has3dCoords{ false }; glm::dvec3 position3d; int id{ NO_ID }; }; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 3d5e463443..980d6c64c7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,14 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "create3dSkyBrowser", + &skybrowser::luascriptfunctions::create3dSkyBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, }; return res; @@ -391,6 +400,10 @@ void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { } } +void SkyBrowserModule::add3dBrowser(SceneGraphNode* node) { + browsers3d.push_back(node); +} + ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } @@ -468,9 +481,10 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir dataHandler->loadSpeckData(speckOpenClusters); int nLoadedImages; + // Read from disc - bool loadedImages = dataHandler->loadWTMLCollectionsFromDirectory(directory); + // Reading from url if there is no directory if (loadedImages) { LINFO("Loading images from directory"); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 9ef6d61ba4..164c273f8e 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -44,6 +44,7 @@ class ScreenSpaceSkyTarget; class RenderableSkyBrowser; class ScreenSpaceRenderable; class WWTDataHandler; +class SceneGraphNode; class SkyBrowserModule : public OpenSpaceModule { @@ -64,6 +65,7 @@ public: void setSelectedBrowser(int i); int getSelectedBrowserIndex(); int loadImages(const std::string& root, const std::string& directory); + void add3dBrowser(SceneGraphNode* node); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -81,6 +83,7 @@ protected: // Renderable vector and ptr to where mouse is std::vector renderables; std::vector browsers; + std::vector browsers3d; ScreenSpaceRenderable* _mouseOnObject; // Dragging glm::vec2 startDragMousePos; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 6bb76ebae2..e6bee6bc33 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -2,28 +2,29 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include #include namespace { @@ -39,36 +40,39 @@ namespace openspace::skybrowser::luascriptfunctions { const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; - ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); - - ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + if (selectedBrowser) { + ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); - // Load image, if the image has not been loaded yet - if (resultImage.id == ImageData::NO_ID) { - LINFO("Loading image " + resultImage.name); - selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForAddingImageLayerWWT(resultImage)); - selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForSettingOpacityLayerWWT(resultImage, 1.0)); - } - - // If the image has coordinates, move the target - if (resultImage.hasCoords) { - // Animate the target to the image coord position - // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 - if (selectedTarget) { - selectedTarget->unlock(); - selectedTarget->startAnimation(resultImage.celestCoords, resultImage.zoomLevel / 6); - glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - float r = windowRatio.x / windowRatio.y; - // Check if image coordinate is within current FOV - bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); - bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; - // If the coordinate is not in view, rotate camera - if (!coordIsWithinView || coordIsBehindCamera) { - module->startRotation(resultImage.celestCoords); + ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + + // Load image, if the image has not been loaded yet + if (resultImage.id == ImageData::NO_ID) { + LINFO("Loading image " + resultImage.name); + selectedBrowser->addImage(resultImage); + } + + // If the image has coordinates, move the target + if (resultImage.hasCelestCoords) { + // Animate the target to the image coord position + if (selectedTarget) { + selectedTarget->unlock(); + selectedTarget->startAnimation(resultImage.celestCoords, resultImage.fov); + glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + float r = windowRatio.x / windowRatio.y; + // Check if image coordinate is within current FOV + bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); + bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; + // If the coordinate is not in view, rotate camera + if (!coordIsWithinView || coordIsBehindCamera) { + module->startRotation(resultImage.celestCoords); + } } } - } + } + else { + LINFO("No browser selected!"); + } return 0; } @@ -81,7 +85,7 @@ namespace openspace::skybrowser::luascriptfunctions { const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Only move and show circle if the image has coordinates - if (resultImage.hasCoords) { + if (resultImage.hasCelestCoords) { // Make circle visible ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(true); @@ -139,7 +143,7 @@ namespace openspace::skybrowser::luascriptfunctions { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { if (!browser->hasLoadedCollections()) { - browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root)); + browser->sendMessageToWWT(wwtmessage::loadCollection(root)); browser->setHasLoadedCollections(true); } } @@ -167,36 +171,42 @@ namespace openspace::skybrowser::luascriptfunctions { for (int i = 0; i < images.size(); i++) { std::string name = images[i].name != "" ? images[i].name : "undefined"; - std::string url = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; + std::string thumbnail = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestCoords); std::vector cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z }; + glm::dvec3 position = images[i].position3d; + std::vector position3d = { position.x, position.y, position.z }; // Index for current ImageData ghoul::lua::push(L, i + 1); lua_newtable(L); // Push ("Key", value) - ghoul::lua::push(L, "Name", name); + ghoul::lua::push(L, "name", name); lua_settable(L, -3); - ghoul::lua::push(L, "Thumbnail", url); + ghoul::lua::push(L, "thumbnail", thumbnail); lua_settable(L, -3); - ghoul::lua::push(L, "RA", images[i].celestCoords.x); + ghoul::lua::push(L, "ra", images[i].celestCoords.x); lua_settable(L, -3); - ghoul::lua::push(L, "Dec", images[i].celestCoords.y); + ghoul::lua::push(L, "dec", images[i].celestCoords.y); lua_settable(L, -3); - ghoul::lua::push(L, "CartesianDirection", cartCoordsVec); + ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); lua_settable(L, -3); - ghoul::lua::push(L, "HasCoords", images[i].hasCoords); + ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestCoords); lua_settable(L, -3); - ghoul::lua::push(L, "Credits", images[i].credits); + ghoul::lua::push(L, "credits", images[i].credits); lua_settable(L, -3); - ghoul::lua::push(L, "CreditsUrl", images[i].creditsUrl); + ghoul::lua::push(L, "creditsUrl", images[i].creditsUrl); lua_settable(L, -3); - ghoul::lua::push(L, "Index", i); + ghoul::lua::push(L, "identifier", std::to_string(i)); + lua_settable(L, -3); + ghoul::lua::push(L, "has3dCoords", images[i].has3dCoords); + lua_settable(L, -3); + ghoul::lua::push(L, "position3d", position3d); lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); } - + return 1; } @@ -229,15 +239,15 @@ namespace openspace::skybrowser::luascriptfunctions { float VFOV = HFOV * (windowRatio.y / windowRatio.x); double FOV = std::min(HFOV, VFOV); // Push window data - ghoul::lua::push(L, "WindowHFOV", FOV); + ghoul::lua::push(L, "windowHFOV", FOV); lua_settable(L, -3); - ghoul::lua::push(L, "CartesianDirection", viewDirCelestVec); + ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); lua_settable(L, -3); - ghoul::lua::push(L, "RA", sphericalJ2000.x); + ghoul::lua::push(L, "ra", sphericalJ2000.x); lua_settable(L, -3); - ghoul::lua::push(L, "Dec", sphericalJ2000.y); + ghoul::lua::push(L, "dec", sphericalJ2000.y); lua_settable(L, -3); - ghoul::lua::push(L, "SelectedBrowserIndex", module->getSelectedBrowserIndex()); + ghoul::lua::push(L, "selectedBrowserIndex", module->getSelectedBrowserIndex()); lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); @@ -262,13 +272,13 @@ namespace openspace::skybrowser::luascriptfunctions { // Push ("Key", value) ghoul::lua::push(L, "FOV", browser->fieldOfView()); lua_settable(L, -3); - ghoul::lua::push(L, "CartesianDirection", celestialCartVec); + ghoul::lua::push(L, "cartesianDirection", celestialCartVec); lua_settable(L, -3); - ghoul::lua::push(L, "RA", celestialSpherical.x); + ghoul::lua::push(L, "ra", celestialSpherical.x); lua_settable(L, -3); - ghoul::lua::push(L, "Dec", celestialSpherical.y); + ghoul::lua::push(L, "dec", celestialSpherical.y); lua_settable(L, -3); - ghoul::lua::push(L, "Color", colorVec); + ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); // Set table for the current target @@ -299,6 +309,81 @@ namespace openspace::skybrowser::luascriptfunctions { } return 0; } + + int create3dSkyBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::create3dSkyBrowser"); + // Image index to place in 3D + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + ImageData image = module->getWWTDataHandler()->getLoadedImages()[i]; + + // If the image has a 3D position, add it to the scene graph + if (image.has3dCoords) { + std::string id = "SkyBrowser" + std::to_string(i); + glm::dvec3 position = image.position3d * distanceconstants::Parsec; + std::string translation = ghoul::to_string(position); + std::string guiPath = "/SkyBrowser"; + + // Calculate the size of the plane with trigonometry + // Calculate in equatorial coordinate system since the FOV is from Earth + // /| + // /_| Adjacent is the horizontal line, opposite the vertical + // \ | Calculate for half the triangle first, then multiply with 2 + // \| + glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); + double adjacent = glm::length(j2000); + double opposite = 2 * adjacent * glm::tan(image.fov * 0.5); + + // Calculate rotation to make the plane face the solar system barycenter + glm::dvec3 normal = glm::normalize(-position); + glm::dvec3 newRight = glm::normalize( + glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) + ); + glm::dvec3 newUp = glm::cross(normal, newRight); + + glm::dmat3 originOrientedRotation = glm::dmat3(1.0); + originOrientedRotation[0] = newRight; + originOrientedRotation[1] = newUp; + originOrientedRotation[2] = normal; + + + const std::string browser = "{" + "Identifier = '" + id + "'," + "Parent = 'SolarSystemBarycenter'," + "Renderable = {" + "Type = 'RenderableSkyBrowser'," + "Size = " + std::to_string(opposite) +"," + "Origin = 'Center'," + "Billboard = false," + "Url = 'http://localhost:8000'" + "}," + "Transform = {" + "Translation = {" + "Type = 'StaticTranslation'," + "Position = " + translation + "" + "}," + "Rotation = {" + "Type = 'StaticRotation'," + "Rotation = " + ghoul::to_string(originOrientedRotation) + "" + "}" + "}," + "GUI = {" + "Name = '" + image.name + "'," + "Path = '" + guiPath + "'" + "}" + "}"; + LINFO(browser); + openspace::global::scriptEngine->queueScript( + "openspace.addSceneGraphNode(" + browser + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + else { + LINFO("Image has no 3D coordinate!"); + } + + return 0; + } } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 302111d3b6..2dd630d3b9 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -6,12 +6,14 @@ #include #include #include +#include // formatJson +#include #include #include -#include +#include #include #include -#include + namespace { @@ -112,6 +114,7 @@ namespace openspace { _browserInstance->initialize(); _browserInstance->loadUrl(_url); + _dimensions = _texture->dimensions(); } void RenderableSkyBrowser::deinitializeGL() { @@ -153,7 +156,6 @@ namespace openspace { } } - void RenderableSkyBrowser::bindTexture() { if (_texture) { _texture->bind(); @@ -162,4 +164,18 @@ namespace openspace { glBindTexture(GL_TEXTURE_2D, 0); } } + + void RenderableSkyBrowser::executeJavascript(std::string script) const { + //LINFOC(_loggerCat, "Executing javascript " + script); + if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) { + CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); + frame->ExecuteJavaScript(script, frame->GetURL(), 0); + } + } + + bool RenderableSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) { + std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; + executeJavascript(script); + return true; + } } // namespace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 63bf9c9809..2ede8d52e1 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -230,113 +230,14 @@ namespace openspace { return true; } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - - glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(global::navigationHandler->camera()->lookUpVectorWorldSpace()); - glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(global::navigationHandler->camera()->viewDirectionWorldSpace()); - double angle = glm::degrees(atan2(glm::dot(glm::cross(camUpJ2000, skybrowser::NORTH_POLE), camForwardJ2000), glm::dot(skybrowser::NORTH_POLE, camUpJ2000))); - - msg.setValue("event", "center_on_coordinates"s); - msg.setValue("ra", celestCoords.x); - msg.setValue("dec", celestCoords.y); - msg.setValue("fov", fov); - msg.setValue("roll", angle); - msg.setValue("instant", moveInstantly); - - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForLoadingWWTImgColl(const std::string& url) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "load_image_collection"s); - msg.setValue("url", url); - msg.setValue("loadChildFolders", true); - - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundWWT(const std::string& name) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_by_name"s); - msg.setValue("name", name); - - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForAddingImageLayerWWT(ImageData& image) { - std::string idString = std::to_string(_imageId); - using namespace std::string_literals; - ghoul::Dictionary msg; - image.id = _imageId; - msg.setValue("event", "image_layer_create"s); - msg.setValue("id", idString); - msg.setValue("url", image.imageUrl); - _imageId++; - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForRemovingImageLayerWWT(const std::string& id) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_remove"s); - msg.setValue("id", id); - - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingOpacityLayerWWT(const ImageData& image, double opacity) const { - std::string idString = std::to_string(image.id); - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_set"s); - msg.setValue("id", idString); - msg.setValue("setting", "opacity"s); - msg.setValue("value", opacity); - - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundOpacityWWT(double val) const { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_opacity"s); - msg.setValue("value", val); - - return msg; - } - - ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForPausingWWTTime() const { - - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "pause_time"s); - - return msg; - } - - void ScreenSpaceSkyBrowser::sendMouseEvent(CefStructBase event, int x, int y) const { - //LINFOC(_loggerCat, "Executing javascript " + script); - LINFO(std::to_string(_objectSize.x) + " " + std::to_string(_objectSize.y)); - if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetHost()) { - - //_browserInstance->getBrowser()->GetHost()->SendMouseWheelEvent(event, x, y); - //LINFOC(_loggerCat, "Sending scroll"); - - } - } - void ScreenSpaceSkyBrowser::WWTfollowCamera() { // Start a thread to enable user interaction while sending the calls to WWT _threadWWTMessages = std::thread([&] { while (_camIsSyncedWWT) { if (_skyTarget) { - ghoul::Dictionary message = createMessageForMovingWWTCamera(_skyTarget->getTargetDirectionCelestial(), _vfieldOfView); + glm::dvec2 aim = _skyTarget->getTargetDirectionCelestial(); + ghoul::Dictionary message = wwtmessage::moveCamera(aim, _vfieldOfView); sendMessageToWWT(message); } @@ -414,4 +315,10 @@ namespace openspace { glm::vec2 ScreenSpaceSkyBrowser::getBrowserPixelDimensions() { return _browserDimensions.value(); } + + void ScreenSpaceSkyBrowser::addImage(ImageData& image) { + sendMessageToWWT(wwtmessage::createImageLayer(image, _imageId)); + sendMessageToWWT(wwtmessage::setLayerOpacity(image, 1.0)); + _imageId++; + } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index d6a358fc8a..2cd298d0ee 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -12,86 +12,177 @@ namespace openspace::skybrowser { - glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) { + glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) { - glm::dvec3 cartesian = glm::dvec3( - cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), - sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), - sin(sphericalCoords.y * DEG_TO_RAD) - ); + glm::dvec3 cartesian = glm::dvec3( + cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), + sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), + sin(sphericalCoords.y * DEG_TO_RAD) + ); - return cartesian; - } + return cartesian; + } - glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) { + glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) { - double ra = atan2(cartesianCoords[1], cartesianCoords[0]); - double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1]))); + double ra = atan2(cartesianCoords[1], cartesianCoords[0]); + double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1]))); - ra = ra > 0 ? ra : ra + (2 * M_PI); + ra = ra > 0 ? ra : ra + (2 * M_PI); - return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec); - } + return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec); + } - glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) { - return glm::transpose(conversionMatrix) * rGal; - } + glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) { + return glm::transpose(conversionMatrix) * rGal; + } - glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) { - return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal)); - } + glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) { + return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal)); + } - glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) { - glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere - return distance * rGalactic; - } + glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) { + glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere + return distance * rGalactic; + } - glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) { - glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere - return distance * rGalactic; - } + glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) { + glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere + return distance * rGalactic; + } - glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { + glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { - glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian); - // Ensure that if the coord is behind the camera, the converted coord will be there too - double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z; + glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian); + // Ensure that if the coord is behind the camera, the converted coord will be there too + double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z; - // Calculate screen space coords x and y - long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z; - long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z; + // Calculate screen space coords x and y + long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z; + long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z; - glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y)); - glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast(std::tanl(angleCoordsLocal.x)), zCoord * static_cast(std::tanl(angleCoordsLocal.y)), zCoord); + glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y)); + glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast(std::tanl(angleCoordsLocal.x)), zCoord * static_cast(std::tanl(angleCoordsLocal.y)), zCoord); - return imageCoordsScreenSpace; - } - - glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) { - // Transform vector to camera's local coordinate system - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos); - glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); - viewDirectionLocal = glm::normalize(viewDirectionLocal); - return viewDirectionLocal; - } - - glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) { - // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity); - // Transform galactic coord to screen space - return galacticToScreenSpace(imageCoordsGalacticCartesian); - } - - glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) { - // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity); - // Transform galactic coord to screen space - return galacticToScreenSpace(imageCoordsGalacticCartesian); - } - + return imageCoordsScreenSpace; } + glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) { + // Transform vector to camera's local coordinate system + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos); + glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); + viewDirectionLocal = glm::normalize(viewDirectionLocal); + return viewDirectionLocal; + } + + glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) { + // Transform equatorial J2000 to galactic coord with infinite radius + glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity); + // Transform galactic coord to screen space + return galacticToScreenSpace(imageCoordsGalacticCartesian); + } + + glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) { + // Transform equatorial J2000 to galactic coord with infinite radius + glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity); + // Transform galactic coord to screen space + return galacticToScreenSpace(imageCoordsGalacticCartesian); + } +} + +// WWT messages +namespace openspace::wwtmessage { + // WWT messages + ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly) { + using namespace std::string_literals; + ghoul::Dictionary msg; + + // Calculate roll between up vector of camera and J2000 equatorial north + glm::dvec3 upVector = global::navigationHandler->camera()->lookUpVectorWorldSpace(); + glm::dvec3 viewVector = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(upVector); + glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(viewVector); + + glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NORTH_POLE); + double dotNorthUp = glm::dot(skybrowser::NORTH_POLE, camUpJ2000); + double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000); + double roll = glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); + + // Create message + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("ra", celestCoords.x); + msg.setValue("dec", celestCoords.y); + msg.setValue("fov", fov); + msg.setValue("roll", roll); + msg.setValue("instant", moveInstantly); + + return msg; + } + + ghoul::Dictionary loadCollection(const std::string& url) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "load_image_collection"s); + msg.setValue("url", url); + msg.setValue("loadChildFolders", true); + + return msg; + } + + ghoul::Dictionary setForeground(const std::string& name) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_by_name"s); + msg.setValue("name", name); + + return msg; + } + + ghoul::Dictionary createImageLayer(ImageData& image, int id) { + std::string idString = std::to_string(id); + image.id = id; + + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_create"s); + msg.setValue("id", idString); + msg.setValue("url", image.imageUrl); + return msg; + } + + ghoul::Dictionary removeImageLayer(const std::string& id) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_remove"s); + msg.setValue("id", id); + + return msg; + } + + ghoul::Dictionary setLayerOpacity(const ImageData& image, double opacity) { + std::string idString = std::to_string(image.id); + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_set"s); + msg.setValue("id", idString); + msg.setValue("setting", "opacity"s); + msg.setValue("value", opacity); + + return msg; + } + + ghoul::Dictionary setForegroundOpacity(double val) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_opacity"s); + msg.setValue("value", val); + + return msg; + } +} + + diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 333f4e8b37..57abb11be4 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -272,15 +272,16 @@ namespace openspace { ImageData& img) { // Get attributes for the image img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; - img.hasCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); - if (img.hasCoords) { + img.hasCelestCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); + if (img.hasCelestCoords) { // The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h) = 15 img.celestCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value()); img.celestCoords.y = std::stof(node->FindAttribute("Dec")->Value()); } img.collection = collectionName; img.thumbnailUrl = thumbnail; - img.zoomLevel = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) : 0.f; + // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 + img.fov = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) / 6: 0.f; img.credits = credits; img.creditsUrl = creditsUrl; img.imageUrl = imageUrl; @@ -290,6 +291,7 @@ namespace openspace { auto it = _3dPositions.find(str); if (it != _3dPositions.end()) { img.position3d = it->second; + img.has3dCoords = true; nImagesWith3dPositions++; } } From 28db33f199a6ebd1a2b0abe5e2c9e44b4f8c7273 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 19 May 2021 14:34:32 +0200 Subject: [PATCH 103/251] Fix bug with calculating image size: use radians instead of degrees --- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index e6bee6bc33..54fc4eeb5d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -332,7 +332,7 @@ namespace openspace::skybrowser::luascriptfunctions { // \| glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); double adjacent = glm::length(j2000); - double opposite = 2 * adjacent * glm::tan(image.fov * 0.5); + double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); // Calculate rotation to make the plane face the solar system barycenter glm::dvec3 normal = glm::normalize(-position); From 1380c7a2c4b729ac0842c770bb14c3a136747dcc Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 19 May 2021 17:16:17 +0200 Subject: [PATCH 104/251] Fade in and out browser and target when going outside of the solar system --- .../include/screenspaceskybrowser.h | 2 + .../skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/shaders/target_fs.glsl | 13 ++-- modules/skybrowser/skybrowsermodule.cpp | 74 ++++++++++++++++++- modules/skybrowser/skybrowsermodule.h | 5 +- .../skybrowser/src/screenspaceskybrowser.cpp | 4 + .../skybrowser/src/screenspaceskytarget.cpp | 7 +- 7 files changed, 93 insertions(+), 13 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 1f26d67467..6ff6a63d2d 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace openspace { @@ -29,6 +30,7 @@ namespace openspace { bool hasLoadedCollections(); void setHasLoadedCollections(bool isLoaded); void addImage(ImageData& image); + properties::FloatProperty& getOpacity(); // Translation //void translate(glm::vec2 translation); diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index e2d4b01bec..2b26b667d5 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -38,6 +38,7 @@ namespace openspace { void setConnectedBrowser(); void setBorderColor(glm::ivec3 color); glm::ivec3 getColor(); + properties::FloatProperty& getOpacity(); glm::dvec2 getScreenSpaceDimensions(); glm::dvec2 getUpperRightCornerScreenSpace(); diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 047eaf847a..797bbee5f4 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -2,7 +2,7 @@ uniform sampler2D texture1; uniform float borderWidth; uniform vec2 targetDimensions; uniform bool showCrosshair; -uniform vec3 borderColor; +uniform vec4 borderColor; in vec2 vs_st; @@ -11,8 +11,8 @@ in vec4 vs_position; float crossLine(in float _width, in float _coord) { float center = 0.5f; - float line = smoothstep(center, center+(_width/2) , _coord) - - smoothstep(center-(_width/2), center, _coord); + float line = smoothstep(center, center+(_width/2) , _coord) - + smoothstep(center-(_width/2), center, _coord); return line; } @@ -32,12 +32,12 @@ Fragment getFragment() { float borderTopRight = step(borderWidth, vs_st.y) * step(borderWidth, (1.0)-vs_st.y); vec3 border = vec3(borderBottomLeft*borderTopRight); - // show crosshair or border + // show crosshair or border frag.color = vec4(1,1,1,1); - frag.color.rgb = vec3(borderColor / 255); + frag.color.rgba = vec4(borderColor); if(showCrosshair) { - frag.color.rgb = vec3(borderColor / 255); + frag.color.rgba = vec4(borderColor); if(crosshair == vec3(0.0)) { frag.color.a = 0.0; } @@ -50,4 +50,3 @@ Fragment getFragment() { return frag; } - diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 980d6c64c7..67019622a3 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "skybrowsermodule_lua.inl" #include @@ -290,6 +291,7 @@ SkyBrowserModule::SkyBrowserModule() if (button == MouseButton::Left) { + isRotating = false; startDragMousePos = _mousePosition; startDragObjectPos = _mouseOnObject->getScreenSpacePosition(); @@ -344,13 +346,39 @@ SkyBrowserModule::SkyBrowserModule() ); global::callback::preSync->emplace_back([this]() { + // Disable browser and targets when camera is outside of solar system + double solarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; + double cameraSSBDistance = glm::length( + global::navigationHandler->camera()->positionVec3()); + bool _cameraInSolarSystem = cameraSSBDistance < solarSystemRadius; + double fadingTime = 2.0; + double deltaTime = global::windowDelegate->deltaTime(); + + // Fade out or in browser & target for (ScreenSpaceSkyBrowser* browser : browsers) { - if (browser->getSkyTarget()) { - browser->getSkyTarget()->animateToCoord(global::windowDelegate->deltaTime()); + // If outside solar system and browser is visible + if (!_cameraInSolarSystem && browser->isEnabled()) { + bool fadingIsFinished = fadeBrowserAndTarget(true, fadingTime, deltaTime); + + if (fadingIsFinished) { + browser->property("Enabled")->set(false); + } + } + // If within solar system and browser is not visible + else if (_cameraInSolarSystem && !browser->isEnabled()) { + browser->property("Enabled")->set(true); + } + // If within solar system and browser is visible + if (_cameraInSolarSystem && browser->isEnabled()) { + fadeBrowserAndTarget(false, fadingTime, deltaTime); + + if (browser->getSkyTarget()) { + browser->getSkyTarget()->animateToCoord(deltaTime); + } } } if (isRotating) { - rotateCamera(global::windowDelegate->deltaTime()); + rotateCamera(deltaTime); } }); } @@ -453,6 +481,42 @@ void SkyBrowserModule::rotateCamera(double deltaTime) { } } +bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime) { + float opacityDelta = static_cast(deltaTime / fadeTime); + float highTreshold = 0.99f; + float lowThreshold = 0.01f; + float transparent = 0.0; + float opaque = 1.0; + if (makeTransparent) { + opacityDelta *= -1.f; + } + bool finished = true; + for (ScreenSpaceSkyBrowser* browser : browsers) { + // If there is a target, fade it as well. Otherwise, skip + ScreenSpaceSkyTarget* target = browser->getSkyTarget(); + bool targetFinished = true; + if (target) { + target->getOpacity() = target->getOpacity().value() + opacityDelta; + float opacityTarget = abs(target->getOpacity().value()); + targetFinished = makeTransparent ? opacityTarget < lowThreshold : opacityTarget > highTreshold; + if (targetFinished) { + target->getOpacity() = makeTransparent ? transparent : opaque; + } + } + // Keep fading the browsers until all are finished + browser->getOpacity() = browser->getOpacity().value() + opacityDelta; + float opacityBrowser = abs(browser->getOpacity().value()); + bool browserFinished = makeTransparent ? opacityBrowser < lowThreshold : opacityBrowser > highTreshold; + if (browserFinished && targetFinished) { + browser->getOpacity() = makeTransparent ? transparent : opaque; + } + else { + finished = false; + } + } + return finished; +} + void SkyBrowserModule::setSelectedBrowser(ScreenSpaceRenderable* ptr) { ScreenSpaceSkyBrowser* browser = to_browser(ptr) ? to_browser(ptr) : to_target(ptr)->getSkyBrowser(); auto it = std::find(browsers.begin(), browsers.end(), browser); @@ -499,6 +563,10 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir return nLoadedImages; } + +bool SkyBrowserModule::cameraInSolarSystem() { + return _cameraInSolarSystem; +} /* std::vector SkyBrowserModule::documentations() const { return { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 164c273f8e..da09f81aac 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -61,11 +61,13 @@ public: std::vector& getSkyBrowsers(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); + bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); void setSelectedBrowser(ScreenSpaceRenderable* ptr); void setSelectedBrowser(int i); int getSelectedBrowserIndex(); int loadImages(const std::string& root, const std::string& directory); void add3dBrowser(SceneGraphNode* node); + bool cameraInSolarSystem(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -99,7 +101,6 @@ protected: bool currentlyDraggingObject; // Data handler WWTDataHandler* dataHandler; - // For animating rotation of camera to look at coordinate glm::dvec3 _coordsToAnimateTo; glm::dvec3 _coordsStartAnimation; @@ -107,6 +108,8 @@ protected: // For tracking the currently selected browser int selectedBrowser{ -1 }; glm::ivec3 highlightAddition{ 35, 35, 35 }; + // Mode of browsing + bool _cameraInSolarSystem{ -1 }; }; } // namespace openspace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 2ede8d52e1..62520f00d9 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -321,4 +321,8 @@ namespace openspace { sendMessageToWWT(wwtmessage::setLayerOpacity(image, 1.0)); _imageId++; } + + properties::FloatProperty& ScreenSpaceSkyBrowser::getOpacity() { + return _opacity; + } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 7f1918269e..40889faaf1 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -233,7 +233,8 @@ namespace openspace { _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetDimensions, targetDim); _shader->setUniform(_uniformCache.modelTransform, modelTransform); - _shader->setUniform(_uniformCache.borderColor, glm::vec3(_borderColor)); + glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; + _shader->setUniform(_uniformCache.borderColor, color); _shader->setUniform( _uniformCache.viewProj, @@ -396,5 +397,7 @@ namespace openspace { FOVToAnimateTo = FOVEnd; isAnimated = true; } - + properties::FloatProperty& ScreenSpaceSkyTarget::getOpacity() { + return _opacity; + } } From 27ac366782f3a8c7a4dd93f0767b18e9b6a6683a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 20 May 2021 09:08:05 +0200 Subject: [PATCH 105/251] Send if camera is within solar system to gui and clean up lua functions --- modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 33 ++++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index da09f81aac..f1a82ca656 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -109,7 +109,7 @@ protected: int selectedBrowser{ -1 }; glm::ivec3 highlightAddition{ 35, 35, 35 }; // Mode of browsing - bool _cameraInSolarSystem{ -1 }; + bool _cameraInSolarSystem{ true }; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 54fc4eeb5d..f22f603bb1 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -41,8 +41,6 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; if (selectedBrowser) { - ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); - ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Load image, if the image has not been loaded yet @@ -51,23 +49,22 @@ namespace openspace::skybrowser::luascriptfunctions { selectedBrowser->addImage(resultImage); } + ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); // If the image has coordinates, move the target - if (resultImage.hasCelestCoords) { + if (resultImage.hasCelestCoords && selectedTarget) { // Animate the target to the image coord position - if (selectedTarget) { - selectedTarget->unlock(); - selectedTarget->startAnimation(resultImage.celestCoords, resultImage.fov); - glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - float r = windowRatio.x / windowRatio.y; - // Check if image coordinate is within current FOV - bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); - bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; - // If the coordinate is not in view, rotate camera - if (!coordIsWithinView || coordIsBehindCamera) { - module->startRotation(resultImage.celestCoords); - } - } + selectedTarget->unlock(); + selectedTarget->startAnimation(resultImage.celestCoords, resultImage.fov); + // Check if image coordinate is within current FOV + glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + float r = windowRatio.x / windowRatio.y; + bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); + bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; + // If the coordinate is not in view, rotate camera + if (!coordIsWithinView || coordIsBehindCamera) { + module->startRotation(resultImage.celestCoords); + } } } else { @@ -249,6 +246,8 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "selectedBrowserIndex", module->getSelectedBrowserIndex()); lua_settable(L, -3); + ghoul::lua::push(L, "cameraInSolarSystem", module->cameraInSolarSystem()); + lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); From 37c7737c5533a7acd2c21ce5953cc4dbedba4b95 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 20 May 2021 11:41:25 +0200 Subject: [PATCH 106/251] Fix bug of stretched texture of the renderable sky browser --- modules/skybrowser/include/renderableskybrowser.h | 2 -- modules/skybrowser/src/renderableskybrowser.cpp | 9 +++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 3e53aee0de..d9c5eabc46 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -53,7 +53,6 @@ namespace openspace { void executeJavascript(std::string script) const; bool sendMessageToWWT(const ghoul::Dictionary& msg); - protected: properties::Vec2Property _dimensions; @@ -79,7 +78,6 @@ namespace openspace { CefRefPtr _keyboardHandler; - glm::ivec2 _objectSize = glm::ivec2(0); bool _isUrlDirty = false; bool _isDimensionsDirty = false; diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 2dd630d3b9..82b73a742e 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -109,12 +109,14 @@ namespace openspace { _texture = std::make_unique( glm::uvec3(_dimensions.value(), 1.0f) ); - + _texture->setDimensions(glm::ivec3(_dimensions.value(), 1)); + _renderHandler->setTexture(*_texture); - + // The browser gets by default the size of the OpenSpace window, so it needs to + // be resized _browserInstance->initialize(); _browserInstance->loadUrl(_url); - _dimensions = _texture->dimensions(); + _browserInstance->reshape(_dimensions.value()); } void RenderableSkyBrowser::deinitializeGL() { @@ -143,7 +145,6 @@ namespace openspace { void RenderableSkyBrowser::update(const UpdateData& data) { RenderablePlane::update(data); _renderHandler->updateTexture(); - _objectSize = _texture->dimensions(); if (_isUrlDirty) { _browserInstance->loadUrl(_url); From ee33d1df24fcf60ea2df54710f2319ffafeb0990 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 21 May 2021 10:00:04 +0200 Subject: [PATCH 107/251] Add lua functions for communication with GUI: add and remove target browser pairs and 3D browsers, change opacity of layer, use ID:s for the browser --- .../include/screenspaceskybrowser.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 220 ++++++++++++++++-- modules/skybrowser/skybrowsermodule.h | 27 ++- modules/skybrowser/skybrowsermodule_lua.inl | 147 ++++++------ .../skybrowser/src/renderableskybrowser.cpp | 4 + .../skybrowser/src/screenspaceskybrowser.cpp | 9 + 6 files changed, 307 insertions(+), 102 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 6ff6a63d2d..6fb3c91d04 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -13,7 +13,7 @@ namespace openspace { { public: ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); - virtual ~ScreenSpaceSkyBrowser() = default; + virtual ~ScreenSpaceSkyBrowser(); bool initializeGL() override; bool deinitializeGL() override; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 67019622a3..1addcc882b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -44,7 +44,7 @@ #include #include // For atan2 #include // For printing glm data - +#include #include @@ -146,6 +146,22 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "createTargetBrowserPair", + &skybrowser::luascriptfunctions::createTargetBrowserPair, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "removeTargetBrowserPair", + &skybrowser::luascriptfunctions::removeTargetBrowserPair, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, { "create3dSkyBrowser", &skybrowser::luascriptfunctions::create3dSkyBrowser, @@ -153,6 +169,22 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "remove3dSkyBrowser", + &skybrowser::luascriptfunctions::remove3dSkyBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "setOpacityOfImageLayer", + &skybrowser::luascriptfunctions::setOpacityOfImageLayer, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, }; @@ -238,7 +270,7 @@ SkyBrowserModule::SkyBrowserModule() // Find and save what mouse is currently hovering on auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { - return obj->coordIsInsideCornersScreenSpace(_mousePosition); + return (obj->coordIsInsideCornersScreenSpace(_mousePosition) && obj->isEnabled()); }); _mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr; @@ -355,7 +387,8 @@ SkyBrowserModule::SkyBrowserModule() double deltaTime = global::windowDelegate->deltaTime(); // Fade out or in browser & target - for (ScreenSpaceSkyBrowser* browser : browsers) { + for (std::pair pair : browsers) { + ScreenSpaceSkyBrowser* browser = pair.second; // If outside solar system and browser is visible if (!_cameraInSolarSystem && browser->isEnabled()) { bool fadingIsFinished = fadeBrowserAndTarget(true, fadingTime, deltaTime); @@ -423,15 +456,175 @@ void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { renderables.push_back(object); // Sort on z coordinate, objects closer to camera are in beginning of list std::sort(renderables.begin(), renderables.end()); - if (to_browser(object)) { - browsers.push_back(to_browser(object)); + ScreenSpaceSkyBrowser* browser = to_browser(object); + if (browser) { + browsers[browser->identifier()] = browser; } } -void SkyBrowserModule::add3dBrowser(SceneGraphNode* node) { +bool SkyBrowserModule::browserIdExists(std::string id) { + // If the id doesn't exist, return false + if (browsers.find(id) == browsers.end()) { + return false; + } + return true; +} + +void SkyBrowserModule::createTargetBrowserPair() { + int noOfPairs = getSkyBrowsers().size() + 1; + std::string nameBrowser = "Sky Browser " + std::to_string(noOfPairs); + std::string nameTarget = "Sky Target " + std::to_string(noOfPairs); + std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); + std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); + glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; + std::string guiPath = "/SkyBrowser"; + + const std::string browser = "{" + "Identifier = '" + idBrowser + "'," + "Type = 'ScreenSpaceSkyBrowser'," + "Name = '" + nameBrowser + "'," + "Url = 'http://localhost:8000/'," + "FaceCamera = false," + "TargetID = '" + idTarget + "'," + "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," + "}"; + const std::string target = "{" + "Identifier = '" + idTarget + "'," + "Type = 'ScreenSpaceSkyTarget'," + "Name = '" + nameTarget + "'," + "FaceCamera = false," + "BrowserID = '" + idBrowser + "'," + "}"; + + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + browser + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + target + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + +void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { + if (!browserIdExists(browserId)) return; + + ScreenSpaceSkyBrowser* browser = browsers[browserId]; + + // Find corresponding target + std::string targetId{ "" }; + bool hasTarget = browser->getSkyTarget(); + if (hasTarget) { + std::string targetId = browser->getSkyTarget()->identifier(); + + openspace::global::scriptEngine->queueScript( + "openspace.removeScreenSpaceRenderable('" + targetId + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + // Remove pointer to the renderable from browsers vector + browsers.erase(browserId); + + // Remove pointer to the renderable from screenspace renderable vector + renderables.erase(std::remove_if(std::begin(renderables), std::end(renderables), + [&](ScreenSpaceRenderable* renderable) { + bool foundBrowser = renderable->identifier() == browserId; + if (hasTarget) { + bool foundTarget = renderable->identifier() == targetId; + return foundBrowser || foundTarget; + } + else { + return foundBrowser; + } + })); + // Remove from engine + openspace::global::scriptEngine->queueScript( + "openspace.removeScreenSpaceRenderable('" + browserId + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + + +} + +void SkyBrowserModule::create3dBrowser(ImageData& image) { + std::string id = "SkyBrowser3d" + std::to_string(browsers3d.size()+1); + glm::dvec3 position = image.position3d * distanceconstants::Parsec; + std::string translation = ghoul::to_string(position); + std::string guiPath = "/SkyBrowser"; + + // Calculate the size of the plane with trigonometry + // Calculate in equatorial coordinate system since the FOV is from Earth + // /| + // /_| Adjacent is the horizontal line, opposite the vertical + // \ | Calculate for half the triangle first, then multiply with 2 + // \| + glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); + double adjacent = glm::length(j2000); + double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); + + // Calculate rotation to make the plane face the solar system barycenter + glm::dvec3 normal = glm::normalize(-position); + glm::dvec3 newRight = glm::normalize( + glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) + ); + glm::dvec3 newUp = glm::cross(normal, newRight); + + glm::dmat3 originOrientedRotation = glm::dmat3(1.0); + originOrientedRotation[0] = newRight; + originOrientedRotation[1] = newUp; + originOrientedRotation[2] = normal; + + + const std::string browser = "{" + "Identifier = '" + id + "'," + "Parent = 'SolarSystemBarycenter'," + "Renderable = {" + "Type = 'RenderableSkyBrowser'," + "Size = " + std::to_string(opposite) + "," + "Origin = 'Center'," + "Billboard = false," + "Url = 'http://localhost:8000'" + "}," + "Transform = {" + "Translation = {" + "Type = 'StaticTranslation'," + "Position = " + translation + "" + "}," + "Rotation = {" + "Type = 'StaticRotation'," + "Rotation = " + ghoul::to_string(originOrientedRotation) + "" + "}" + "}," + "GUI = {" + "Name = '" + image.name + "'," + "Path = '" + guiPath + "'" + "}" + "}"; + LINFO(browser); + openspace::global::scriptEngine->queueScript( + "openspace.addSceneGraphNode(" + browser + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + +void SkyBrowserModule::add3dBrowser(RenderableSkyBrowser* node) { browsers3d.push_back(node); } +void SkyBrowserModule::remove3dBrowser(std::string& id) { + // Remove pointer to the renderable from module vector + browsers3d.erase(std::remove_if(std::begin(browsers3d), std::end(browsers3d), + [&](RenderableSkyBrowser* browser) { + return browser->identifier() == id; + })); + + openspace::global::scriptEngine->queueScript( + "openspace.removeSceneGraphNode(" + id + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } @@ -443,7 +636,7 @@ WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { return dataHandler; } -std::vector& SkyBrowserModule::getSkyBrowsers() { +std::map& SkyBrowserModule::getSkyBrowsers() { return browsers; } @@ -491,7 +684,8 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim opacityDelta *= -1.f; } bool finished = true; - for (ScreenSpaceSkyBrowser* browser : browsers) { + for (std::pair idAndBrowser : browsers) { + ScreenSpaceSkyBrowser* browser = idAndBrowser.second; // If there is a target, fade it as well. Otherwise, skip ScreenSpaceSkyTarget* target = browser->getSkyTarget(); bool targetFinished = true; @@ -519,16 +713,14 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim void SkyBrowserModule::setSelectedBrowser(ScreenSpaceRenderable* ptr) { ScreenSpaceSkyBrowser* browser = to_browser(ptr) ? to_browser(ptr) : to_target(ptr)->getSkyBrowser(); - auto it = std::find(browsers.begin(), browsers.end(), browser); - // Get index - selectedBrowser = std::distance(browsers.begin(), it); + selectedBrowser = browser->identifier(); } -void SkyBrowserModule::setSelectedBrowser(int i) { - selectedBrowser = i; +void SkyBrowserModule::setSelectedBrowser(std::string id) { + selectedBrowser = id; } -int SkyBrowserModule::getSelectedBrowserIndex() { +std::string SkyBrowserModule::selectedBrowserId() { return selectedBrowser; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index f1a82ca656..14966237de 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -32,7 +32,7 @@ #include #include #include - +#include #include #include @@ -45,6 +45,7 @@ class RenderableSkyBrowser; class ScreenSpaceRenderable; class WWTDataHandler; class SceneGraphNode; +class ImageData; class SkyBrowserModule : public OpenSpaceModule { @@ -58,16 +59,21 @@ public: glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); - std::vector& getSkyBrowsers(); + std::map& getSkyBrowsers(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); void setSelectedBrowser(ScreenSpaceRenderable* ptr); - void setSelectedBrowser(int i); - int getSelectedBrowserIndex(); + void setSelectedBrowser(std::string id); + bool browserIdExists(std::string id); + std::string selectedBrowserId(); int loadImages(const std::string& root, const std::string& directory); - void add3dBrowser(SceneGraphNode* node); + void add3dBrowser(RenderableSkyBrowser* node); + void remove3dBrowser(std::string& id); bool cameraInSolarSystem(); + void createTargetBrowserPair(); + void removeTargetBrowserPair(std::string& browserId); + void create3dBrowser(ImageData& image); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -82,10 +88,13 @@ protected: bool shouldInitialize; - // Renderable vector and ptr to where mouse is + // The browsers and targets std::vector renderables; - std::vector browsers; - std::vector browsers3d; + // Only the browsers + std::map browsers; + // 3D browsers + std::vector browsers3d; + // Pointer to what mouse is currently on ScreenSpaceRenderable* _mouseOnObject; // Dragging glm::vec2 startDragMousePos; @@ -106,7 +115,7 @@ protected: glm::dvec3 _coordsStartAnimation; bool isRotating = false; // For tracking the currently selected browser - int selectedBrowser{ -1 }; + std::string selectedBrowser; glm::ivec3 highlightAddition{ 35, 35, 35 }; // Mode of browsing bool _cameraInSolarSystem{ true }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index f22f603bb1..b8f1db706b 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -39,7 +39,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; + ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->selectedBrowserId()]; if (selectedBrowser) { ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; @@ -104,12 +104,10 @@ namespace openspace::skybrowser::luascriptfunctions { int lockTarget(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); - const int i = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector browsers = module->getSkyBrowsers(); - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); - if (i < browsers.size()) { - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (module->browserIdExists(id)) { + ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); if (target) { target->lock(); } @@ -119,11 +117,10 @@ namespace openspace::skybrowser::luascriptfunctions { int unlockTarget(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); - const int i = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::vector browsers = module->getSkyBrowsers(); - if (i < browsers.size()) { - ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); + if (module->browserIdExists(id)) { + ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); if (target) { target->unlock(); } @@ -138,7 +135,8 @@ namespace openspace::skybrowser::luascriptfunctions { // Load the collections here because here we know that the browser can execute javascript std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { + for (std::pair pair : module->getSkyBrowsers()) { + ScreenSpaceSkyBrowser* browser = pair.second; if (!browser->hasLoadedCollections()) { browser->sendMessageToWWT(wwtmessage::loadCollection(root)); browser->setHasLoadedCollections(true); @@ -244,7 +242,7 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "dec", sphericalJ2000.y); lua_settable(L, -3); - ghoul::lua::push(L, "selectedBrowserIndex", module->getSelectedBrowserIndex()); + ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); lua_settable(L, -3); ghoul::lua::push(L, "cameraInSolarSystem", module->cameraInSolarSystem()); lua_settable(L, -3); @@ -252,9 +250,11 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); // Pass data for all the browsers and the corresponding targets - std::vector browsers = module->getSkyBrowsers(); + std::map browsers = module->getSkyBrowsers(); - for (ScreenSpaceSkyBrowser* browser : browsers) { + for (std::pair pair : browsers) { + ScreenSpaceSkyBrowser* browser = pair.second; + std::string id = pair.first; // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { @@ -269,6 +269,10 @@ namespace openspace::skybrowser::luascriptfunctions { index++; lua_newtable(L); // Push ("Key", value) + ghoul::lua::push(L, "id", id); + lua_settable(L, -3); + ghoul::lua::push(L, "name", browser->guiName()); + lua_settable(L, -3); ghoul::lua::push(L, "FOV", browser->fieldOfView()); lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", celestialCartVec); @@ -290,25 +294,59 @@ namespace openspace::skybrowser::luascriptfunctions { } int adjustCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); - const int i = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getSkyBrowsers().size() > i) { - module->startRotation(module->getSkyBrowsers()[i]->getSkyTarget()->getTargetDirectionCelestial()); + if (module->browserIdExists(id)) { + ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); + if (target) { + module->startRotation(target->getTargetDirectionCelestial()); + } } return 0; } + int setOpacityOfImageLayer(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); + const std::string browserId = ghoul::lua::value(L, 1); + const int i = ghoul::lua::value(L, 2); + double opacity = ghoul::lua::value(L, 3); + SkyBrowserModule* module = global::moduleEngine->module(); + + if (module->browserIdExists(browserId)) { + ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; + ghoul::Dictionary message = wwtmessage::setLayerOpacity(image, opacity); + module->getSkyBrowsers()[browserId]->sendMessageToWWT(message); + } + return 0; + } int setSelectedBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); - const int i = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getSkyBrowsers().size() < i) { - module->setSelectedBrowser(i); + if (module->browserIdExists(id)) { + module->setSelectedBrowser(id); } return 0; } + int createTargetBrowserPair(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createTargetBrowserPair"); + SkyBrowserModule* module = global::moduleEngine->module(); + module->createTargetBrowserPair(); + + return 0; + } + + int removeTargetBrowserPair(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeTargetBrowserPair"); + std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + module->removeTargetBrowserPair(id); + + return 0; + } + int create3dSkyBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::create3dSkyBrowser"); // Image index to place in 3D @@ -318,64 +356,7 @@ namespace openspace::skybrowser::luascriptfunctions { // If the image has a 3D position, add it to the scene graph if (image.has3dCoords) { - std::string id = "SkyBrowser" + std::to_string(i); - glm::dvec3 position = image.position3d * distanceconstants::Parsec; - std::string translation = ghoul::to_string(position); - std::string guiPath = "/SkyBrowser"; - - // Calculate the size of the plane with trigonometry - // Calculate in equatorial coordinate system since the FOV is from Earth - // /| - // /_| Adjacent is the horizontal line, opposite the vertical - // \ | Calculate for half the triangle first, then multiply with 2 - // \| - glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); - double adjacent = glm::length(j2000); - double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); - - // Calculate rotation to make the plane face the solar system barycenter - glm::dvec3 normal = glm::normalize(-position); - glm::dvec3 newRight = glm::normalize( - glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) - ); - glm::dvec3 newUp = glm::cross(normal, newRight); - - glm::dmat3 originOrientedRotation = glm::dmat3(1.0); - originOrientedRotation[0] = newRight; - originOrientedRotation[1] = newUp; - originOrientedRotation[2] = normal; - - - const std::string browser = "{" - "Identifier = '" + id + "'," - "Parent = 'SolarSystemBarycenter'," - "Renderable = {" - "Type = 'RenderableSkyBrowser'," - "Size = " + std::to_string(opposite) +"," - "Origin = 'Center'," - "Billboard = false," - "Url = 'http://localhost:8000'" - "}," - "Transform = {" - "Translation = {" - "Type = 'StaticTranslation'," - "Position = " + translation + "" - "}," - "Rotation = {" - "Type = 'StaticRotation'," - "Rotation = " + ghoul::to_string(originOrientedRotation) + "" - "}" - "}," - "GUI = {" - "Name = '" + image.name + "'," - "Path = '" + guiPath + "'" - "}" - "}"; - LINFO(browser); - openspace::global::scriptEngine->queueScript( - "openspace.addSceneGraphNode(" + browser + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); + module->create3dBrowser(image); } else { LINFO("Image has no 3D coordinate!"); @@ -383,6 +364,16 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } + + int remove3dSkyBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::remove3dSkyBrowser"); + // Image index to place in 3D + std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + module->remove3dBrowser(id); + + return 0; + } } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 82b73a742e..39a51878e3 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -117,6 +118,9 @@ namespace openspace { _browserInstance->initialize(); _browserInstance->loadUrl(_url); _browserInstance->reshape(_dimensions.value()); + // Add pointer to module + SkyBrowserModule* module = global::moduleEngine->module(); + module->add3dBrowser(this); } void RenderableSkyBrowser::deinitializeGL() { diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 62520f00d9..8d2ec66c37 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -139,6 +139,15 @@ namespace openspace { }); } + ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { + // Set flag to false so the thread can exit + _camIsSyncedWWT = false; + if (_threadWWTMessages.joinable()) { + _threadWWTMessages.join(); + LINFO("Joined thread"); + } + } + bool ScreenSpaceSkyBrowser::initializeGL() { global::moduleEngine->module()->addRenderable(this); From 3c2bbd134f06f73bad2a675e04e2880264a83b0c Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Fri, 21 May 2021 11:31:24 +0200 Subject: [PATCH 108/251] Send ID of targets to GUI --- modules/skybrowser/skybrowsermodule_lua.inl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b8f1db706b..29db05a9bc 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -212,11 +212,9 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); lua_newtable(L); - int index = 1; // Add the window data for OpenSpace - ghoul::lua::push(L, index); - index++; + ghoul::lua::push(L, "OpenSpace"); lua_newtable(L); // Get the view direction of the screen in cartesian J2000 coordinates glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); @@ -265,8 +263,7 @@ namespace openspace::skybrowser::luascriptfunctions { glm::ivec3 color = browser->_borderColor.value(); std::vector colorVec = { color.r, color.g, color.b }; - ghoul::lua::push(L, index); - index++; + ghoul::lua::push(L, id); lua_newtable(L); // Push ("Key", value) ghoul::lua::push(L, "id", id); From bf283dce0be4ed44f08bbb0be8699aef4dea7b7d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 24 May 2021 11:49:31 +0200 Subject: [PATCH 109/251] Store selected images in C++ backend and send to GUI. Add lua function to remove selected images from browser --- .../include/screenspaceskybrowser.h | 6 +++- modules/skybrowser/include/utility.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 8 +++++ modules/skybrowser/skybrowsermodule_lua.inl | 28 +++++++++++++++-- .../skybrowser/src/screenspaceskybrowser.cpp | 31 +++++++++++++++---- modules/skybrowser/src/utility.cpp | 5 +-- 6 files changed, 68 insertions(+), 12 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 6fb3c91d04..d0f568cae4 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace openspace { class ScreenSpaceSkyTarget; @@ -29,8 +30,10 @@ namespace openspace { ScreenSpaceSkyTarget* getSkyTarget(); bool hasLoadedCollections(); void setHasLoadedCollections(bool isLoaded); - void addImage(ImageData& image); properties::FloatProperty& getOpacity(); + std::deque& selectedImages(); + void addSelectedImage(ImageData& image, int i); + void removeSelectedImage(ImageData& image, int i); // Translation //void translate(glm::vec2 translation); @@ -64,6 +67,7 @@ namespace openspace { std::chrono::system_clock::time_point _lastUpdateTime; int _imageId{ 0 }; bool _hasLoadedCollections{ false }; + std::deque _selectedImages; }; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 3490aba153..e76564f1ad 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -45,7 +45,7 @@ namespace openspace { ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); ghoul::Dictionary createImageLayer(ImageData& image, int id = 0); - ghoul::Dictionary removeImageLayer(const std::string& id); + ghoul::Dictionary removeImageLayer(ImageData& image); ghoul::Dictionary setLayerOpacity(const ImageData& image, double opacity); ghoul::Dictionary setForegroundOpacity(double val); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1addcc882b..f089378cbe 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -105,6 +105,14 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "removeSelectedImageInBrowser", + &skybrowser::luascriptfunctions::removeSelectedImageInBrowser, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, { "adjustCamera", diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 29db05a9bc..2376dcbdf5 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -46,7 +46,7 @@ namespace openspace::skybrowser::luascriptfunctions { // Load image, if the image has not been loaded yet if (resultImage.id == ImageData::NO_ID) { LINFO("Loading image " + resultImage.name); - selectedBrowser->addImage(resultImage); + selectedBrowser->addSelectedImage(resultImage, i); } ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); @@ -224,6 +224,7 @@ namespace openspace::skybrowser::luascriptfunctions { glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000); // Convert to vector so ghoul can read it std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; + // Calculate the smallest FOV of vertical and horizontal @@ -253,6 +254,12 @@ namespace openspace::skybrowser::luascriptfunctions { for (std::pair pair : browsers) { ScreenSpaceSkyBrowser* browser = pair.second; std::string id = pair.first; + // Convert deque to vector so ghoul can read it + std::vector selectedImagesVector; + std::deque selectedImages = browser->selectedImages(); + std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { + selectedImagesVector.push_back(index); + }); // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { @@ -272,6 +279,8 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "FOV", browser->fieldOfView()); lua_settable(L, -3); + ghoul::lua::push(L, "selectedImages", selectedImagesVector); + lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", celestialCartVec); lua_settable(L, -3); ghoul::lua::push(L, "ra", celestialSpherical.x); @@ -280,7 +289,7 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); - + // Set table for the current target lua_settable(L, -3); } @@ -371,6 +380,21 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } + + int removeSelectedImageInBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); + // Image index + const int i = ghoul::lua::value(L, 1); + const std::string browserId = ghoul::lua::value(L, 2); + // Get browser + SkyBrowserModule* module = global::moduleEngine->module(); + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; + ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + // Remove image + browser->removeSelectedImage(resultImage, i); + + return 0; + } } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 8d2ec66c37..84dbe36ae7 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -325,13 +325,32 @@ namespace openspace { return _browserDimensions.value(); } - void ScreenSpaceSkyBrowser::addImage(ImageData& image) { - sendMessageToWWT(wwtmessage::createImageLayer(image, _imageId)); - sendMessageToWWT(wwtmessage::setLayerOpacity(image, 1.0)); - _imageId++; - } - properties::FloatProperty& ScreenSpaceSkyBrowser::getOpacity() { return _opacity; } + + std::deque& ScreenSpaceSkyBrowser::selectedImages() { + return _selectedImages; + } + + void ScreenSpaceSkyBrowser::addSelectedImage(ImageData& image, int i) { + sendMessageToWWT(wwtmessage::createImageLayer(image, _imageId)); + sendMessageToWWT(wwtmessage::setLayerOpacity(image, 1.0)); + _imageId++; + // Ensure there are no duplicates + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it == std::end(_selectedImages)) { + // Push newly selected image to front + _selectedImages.push_front(i); + } + } + + void ScreenSpaceSkyBrowser::removeSelectedImage(ImageData& image, int i) { + sendMessageToWWT(wwtmessage::removeImageLayer(image)); + // Remove from selected list + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it != std::end(_selectedImages)) { + _selectedImages.erase(it); + } + } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 2cd298d0ee..fa3fd27a34 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -152,11 +152,12 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary removeImageLayer(const std::string& id) { + ghoul::Dictionary removeImageLayer(ImageData& image) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_remove"s); - msg.setValue("id", id); + msg.setValue("id", std::to_string(image.id)); + image.id = ImageData::NO_ID; return msg; } From b2d5eb4e55059e93d5075e27e8843d169d1a2874 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 24 May 2021 12:24:16 +0200 Subject: [PATCH 110/251] Make asset general by setting texture path relative to base --- data/assets/hoverCircle.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index f943b13beb..8165a129ad 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -9,7 +9,7 @@ local assetHelper = asset.require('util/asset_helper') RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome Scale= 0.015, Enabled = false, - TexturePath = "D:/Ylvas/OpenSpace/data/assets/circle.png", + TexturePath = "${BASE}/data/assets/circle.png", CartesianPosition = { 0, 0, -2.1 }, }; assetHelper.registerScreenSpaceRenderables(asset, { spec }) From eeb1ac57374ecf46c805fc05a5981c59f7632b87 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 24 May 2021 14:15:09 +0200 Subject: [PATCH 111/251] Make hover circle more general by loading it in relation to asset folder --- data/assets/hoverCircle.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index 8165a129ad..c43db9634c 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -9,7 +9,7 @@ local assetHelper = asset.require('util/asset_helper') RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome Scale= 0.015, Enabled = false, - TexturePath = "${BASE}/data/assets/circle.png", + TexturePath = "${ASSETS}/circle.png", CartesianPosition = { 0, 0, -2.1 }, }; assetHelper.registerScreenSpaceRenderables(asset, { spec }) From 6cf7dd8d45bfd6ac0016c4f9782e4e19fe2599d4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 26 May 2021 16:23:49 +0200 Subject: [PATCH 112/251] Load, connect and set up connection to WWT app properly with the help of OpenSpace Lua api --- data/assets/skyBrowser.asset | 15 ---- data/assets/skyBrowserTargetPair.asset | 42 +++++++++ data/assets/skyTarget.asset | 13 --- .../include/screenspaceskybrowser.h | 2 + .../skybrowser/include/screenspaceskytarget.h | 4 +- modules/skybrowser/skybrowsermodule.cpp | 88 +++++++++++++++---- modules/skybrowser/skybrowsermodule.h | 5 +- modules/skybrowser/skybrowsermodule_lua.inl | 75 +++++++++++++++- .../skybrowser/src/screenspaceskybrowser.cpp | 36 ++++---- .../skybrowser/src/screenspaceskytarget.cpp | 11 +-- 10 files changed, 212 insertions(+), 79 deletions(-) delete mode 100644 data/assets/skyBrowser.asset create mode 100644 data/assets/skyBrowserTargetPair.asset delete mode 100644 data/assets/skyTarget.asset diff --git a/data/assets/skyBrowser.asset b/data/assets/skyBrowser.asset deleted file mode 100644 index 93315772fb..0000000000 --- a/data/assets/skyBrowser.asset +++ /dev/null @@ -1,15 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - - local spec = { - Type = "ScreenSpaceSkyBrowser", - Identifier = "SkyBrowser1", - Name = "SkyBrowser", - Url = "http://localhost:8000/", - FaceCamera = false, - TargetID = "SkyTarget1", - CartesianPosition = {-1.0, -0.5, -2.1}, - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome - }; - -assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset new file mode 100644 index 0000000000..5bc6656e43 --- /dev/null +++ b/data/assets/skyBrowserTargetPair.asset @@ -0,0 +1,42 @@ +local assetHelper = asset.require('util/asset_helper') + +local targetId= "SkyTarget0" +local browserId = "SkyBrowser0" + +local browser = { + Type = "ScreenSpaceSkyBrowser", + Identifier = browserId, + Name = "SkyBrowser", + Url = "http://localhost:8000/", + FaceCamera = false, + TargetID = targetId, + CartesianPosition = {-1.0, -0.5, -2.1}, + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome +}; + +local target = { + Type = "ScreenSpaceSkyTarget", + Identifier = targetId, + Name = "Target", + FaceCamera = false, + BrowserID = browserId, + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome +}; + +asset.onInitialize(function () + openspace.addScreenSpaceRenderable(browser) + openspace.addScreenSpaceRenderable(target) + openspace.skybrowser.addToSkyBrowserModule(browserId) + openspace.skybrowser.addToSkyBrowserModule(targetId) + openspace.skybrowser.connectBrowserTarget(browserId) + openspace.skybrowser.connectBrowserTarget(targetId) +end) + +asset.onDeinitialize(function () + openspace.removeScreenSpaceRenderable(browserId) + openspace.removeScreenSpaceRenderable(targetId) +end) + +asset.export("browser", {browser, target}) diff --git a/data/assets/skyTarget.asset b/data/assets/skyTarget.asset deleted file mode 100644 index f758f2cbaf..0000000000 --- a/data/assets/skyTarget.asset +++ /dev/null @@ -1,13 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - - local spec = { - Type = "ScreenSpaceSkyTarget", - Identifier = "SkyTarget1", - Name = "Target", - FaceCamera = false, - BrowserID = "SkyBrowser1", - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome - }; - -assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index d0f568cae4..09c2158ec6 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -19,6 +19,8 @@ namespace openspace { bool initializeGL() override; bool deinitializeGL() override; bool setConnectedTarget(); + void initializeBrowser(); + void setIdInBrowser(); // Communication with the webpage and WWT void executeJavascript(std::string script) const; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 2b26b667d5..6edb7af03d 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -27,6 +27,8 @@ namespace openspace { void render() override; void createShaders(); + void initializeWithBrowser(); + void setBrowser(ScreenSpaceSkyBrowser* browser); ScreenSpaceSkyBrowser* getSkyBrowser(); @@ -35,7 +37,7 @@ namespace openspace { glm::dvec3 getTargetDirectionGalactic(); glm::dvec2 getScreenSpacePosition(); - void setConnectedBrowser(); + bool setConnectedBrowser(); void setBorderColor(glm::ivec3 color); glm::ivec3 getColor(); properties::FloatProperty& getOpacity(); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f089378cbe..082bf6455b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -193,6 +193,38 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "sendOutIdsToBrowsers", + &skybrowser::luascriptfunctions::sendOutIdsToBrowsers, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "initializeBrowserAndTarget", + &skybrowser::luascriptfunctions::initializeBrowserAndTarget, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "connectBrowserTarget", + &skybrowser::luascriptfunctions::connectBrowserTarget, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "addToSkyBrowserModule", + &skybrowser::luascriptfunctions::addToSkyBrowserModule, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, }; @@ -206,23 +238,10 @@ SkyBrowserModule::SkyBrowserModule() , currentlyResizingBrowser(false) , currentlyDraggingObject(false) , resizeVector(0.f, 0.f) - , shouldInitialize(true) , changeViewWithinBrowser(false) { global::callback::mousePosition->emplace_back( [&](double x, double y) { - // Quick fix to make all renderables find its corresponding partner - if (shouldInitialize) { - std::for_each(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { - if (to_target(obj)) { - to_target(obj)->setConnectedBrowser(); - } - else if (to_browser(obj)) { - to_browser(obj)->setConnectedTarget(); - } - }); - shouldInitialize = false; - } glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); _mousePosition = getMousePositionInScreenSpaceCoords(pos); @@ -278,7 +297,7 @@ SkyBrowserModule::SkyBrowserModule() // Find and save what mouse is currently hovering on auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { - return (obj->coordIsInsideCornersScreenSpace(_mousePosition) && obj->isEnabled()); + return obj && (obj->coordIsInsideCornersScreenSpace(_mousePosition) && obj->isEnabled()); }); _mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr; @@ -327,8 +346,14 @@ SkyBrowserModule::SkyBrowserModule() if (_mouseOnObject && action == MouseAction::Press) { // Get the currently selected browser - setSelectedBrowser(_mouseOnObject); + if (to_browser(_mouseOnObject)) { + setSelectedBrowser(to_browser(_mouseOnObject)); + } + else if (to_target(_mouseOnObject) && + to_target(_mouseOnObject)->getSkyBrowser()) { + setSelectedBrowser(to_target(_mouseOnObject)->getSkyBrowser()); + } if (button == MouseButton::Left) { isRotating = false; @@ -513,6 +538,26 @@ void SkyBrowserModule::createTargetBrowserPair() { "openspace.addScreenSpaceRenderable(" + target + ");", scripting::ScriptEngine::RemoteScripting::Yes ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.addToSkyBrowserModule(" + idTarget + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.addToSkyBrowserModule(" + idBrowser + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.connectBrowserTarget(" + idBrowser + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.connectBrowserTarget(" + idTarget + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); } void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { @@ -524,7 +569,7 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { std::string targetId{ "" }; bool hasTarget = browser->getSkyTarget(); if (hasTarget) { - std::string targetId = browser->getSkyTarget()->identifier(); + targetId = browser->getSkyTarget()->identifier(); openspace::global::scriptEngine->queueScript( "openspace.removeScreenSpaceRenderable('" + targetId + "');", @@ -648,6 +693,10 @@ std::map& SkyBrowserModule::getSkyBrowsers( return browsers; } +std::vector& SkyBrowserModule::getBrowsersAndTargets() { + return renderables; +} + void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { // Save coordinates to rotate to in galactic world coordinates @@ -719,9 +768,10 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim return finished; } -void SkyBrowserModule::setSelectedBrowser(ScreenSpaceRenderable* ptr) { - ScreenSpaceSkyBrowser* browser = to_browser(ptr) ? to_browser(ptr) : to_target(ptr)->getSkyBrowser(); - selectedBrowser = browser->identifier(); +void SkyBrowserModule::setSelectedBrowser(ScreenSpaceSkyBrowser* browser) { + if (browser) { + selectedBrowser = browser->identifier(); + } } void SkyBrowserModule::setSelectedBrowser(std::string id) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 14966237de..8d6f8261c6 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -60,10 +60,11 @@ public: void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); std::map& getSkyBrowsers(); + std::vector& getBrowsersAndTargets(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); - void setSelectedBrowser(ScreenSpaceRenderable* ptr); + void setSelectedBrowser(ScreenSpaceSkyBrowser* ptr); void setSelectedBrowser(std::string id); bool browserIdExists(std::string id); std::string selectedBrowserId(); @@ -86,8 +87,6 @@ protected: ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr); ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr); - bool shouldInitialize; - // The browsers and targets std::vector renderables; // Only the browsers diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 2376dcbdf5..64874570e6 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -130,13 +130,16 @@ namespace openspace::skybrowser::luascriptfunctions { int loadImagesToWWT(lua_State* L) { // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::loadImagesToWWT"); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT"); + const std::string id = ghoul::lua::value(L, 1); + LINFO("Connection established to WorldWide Telescope application in " + id); + LINFO("Loading image collections to " + id); SkyBrowserModule* module = global::moduleEngine->module(); // Load the collections here because here we know that the browser can execute javascript std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - for (std::pair pair : module->getSkyBrowsers()) { - ScreenSpaceSkyBrowser* browser = pair.second; + if (module->browserIdExists(id)) { + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[id]; if (!browser->hasLoadedCollections()) { browser->sendMessageToWWT(wwtmessage::loadCollection(root)); browser->setHasLoadedCollections(true); @@ -146,6 +149,72 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } + int sendOutIdsToBrowsers(lua_State* L) { + // This is called when the sky_browser website is connected to OpenSpace + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers"); + + // Send out ID's to the browsers + SkyBrowserModule* module = global::moduleEngine->module(); + std::map browsers = module->getSkyBrowsers(); + for (std::pair pair : browsers) { + pair.second->setIdInBrowser(); + } + + return 0; + } + + int connectBrowserTarget(lua_State* L) { + // In order to connect, the target and browsers must have been loaded into the + // module. This is to ensure that the renderables have been found + + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::connectBrowserTarget"); + const std::string id = ghoul::lua::value(L, 1); + + // Find the screenspace renderable that has the id + SkyBrowserModule* module = global::moduleEngine->module(); + std::vector renderables = module->getBrowsersAndTargets(); + auto found = std::find_if(std::begin(renderables), std::end(renderables), + [&](ScreenSpaceRenderable* renderable) { + return renderable && id == renderable->identifier(); + }); + if (dynamic_cast(*found)) { + ScreenSpaceSkyBrowser* browser = dynamic_cast(*found); + browser->setConnectedTarget(); + } + else if (dynamic_cast(*found)) { + ScreenSpaceSkyTarget* target = dynamic_cast(*found); + target->setConnectedBrowser(); + } + return 0; + } + + int initializeBrowserAndTarget(lua_State* L) { + // Initialize browser with ID and its corresponding target + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowserAndTarget"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->browserIdExists(id)) { + module->getSkyBrowsers()[id]->initializeBrowser(); + ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); + if (target) { + target->initializeWithBrowser(); + } + } + + return 0; + } + + int addToSkyBrowserModule(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addToSkyBrowserModule"); + const std::string id = ghoul::lua::value(L, 1); + LINFO("Add to sky browser module id " + id); + ScreenSpaceRenderable* object = global::renderEngine->screenSpaceRenderable(id); + SkyBrowserModule* module = global::moduleEngine->module(); + module->addRenderable(object); + + return 0; + } + int getListOfImages(lua_State* L) { // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 84dbe36ae7..4a20c26d6a 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -93,10 +93,7 @@ namespace openspace { const Parameters p = codegen::bake(dictionary); _browserDimensions = p.browserDimensions.value_or(_browserDimensions); _browserDimensions.onChange([&]() { - if (!_skyTarget) { - setConnectedTarget(); - } - else { + if(_skyTarget) { glm::vec2 dim = getBrowserPixelDimensions(); _skyTarget->setDimensions(dim); } @@ -149,18 +146,23 @@ namespace openspace { } bool ScreenSpaceSkyBrowser::initializeGL() { - - global::moduleEngine->module()->addRenderable(this); - setConnectedTarget(); - if (_skyTarget) { - _skyTarget->setDimensions(getBrowserPixelDimensions()); - } - - WWTfollowCamera(); - return ScreenSpaceBrowser::initializeGL(); } + void ScreenSpaceSkyBrowser::setIdInBrowser() { + // Send ID to it's browser + executeJavascript("setId('" + identifier() + "')"); + } + + void ScreenSpaceSkyBrowser::initializeBrowser() { + // Set border color + setBorderColor(_borderColor.value()); + // Connect to target + setConnectedTarget(); + // Track target + WWTfollowCamera(); + } + bool ScreenSpaceSkyBrowser::deinitializeGL() { // Set flag to false so the thread can exit _camIsSyncedWWT = false; @@ -172,14 +174,8 @@ namespace openspace { } bool ScreenSpaceSkyBrowser::setConnectedTarget() { - setBorderColor(_borderColor.value()); _skyTarget = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyTargetID.value())); - if (_skyTarget) { - _skyTarget->setBorderColor(_borderColor.value()); - _skyTarget->updateFOV(_vfieldOfView.value()); - _skyTarget->setDimensions(getBrowserPixelDimensions()); - } - return _skyTarget != nullptr; + return _skyTarget; } ScreenSpaceSkyTarget* ScreenSpaceSkyBrowser::getSkyTarget() { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 40889faaf1..e5457045a4 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -79,6 +79,7 @@ namespace openspace { , _skyBrowserID(BrowserIDInfo) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.f, 1.f, 70.f) , _borderColor(220, 220, 220) + , _skyBrowser(nullptr) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -129,10 +130,13 @@ namespace openspace { } } - void ScreenSpaceSkyTarget::setConnectedBrowser() { + bool ScreenSpaceSkyTarget::setConnectedBrowser() { _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + return _skyBrowser; + } + + void ScreenSpaceSkyTarget::initializeWithBrowser() { if (_skyBrowser) { - _skyBrowser->setBorderColor(_skyBrowser->getColor()); _borderColor = _skyBrowser->getColor(); updateFOV(_skyBrowser->_vfieldOfView.value()); _targetDimensions = _skyBrowser->getBrowserPixelDimensions(); @@ -144,9 +148,6 @@ namespace openspace { } bool ScreenSpaceSkyTarget::initializeGL() { - global::moduleEngine->module()->addRenderable(this); - - setConnectedBrowser(); glGenVertexArrays(1, &_vertexArray); glGenBuffers(1, &_vertexBuffer); From 3411662b74f67977c447d1dbaf8eff133efc2a9d Mon Sep 17 00:00:00 2001 From: Ester Lindgren Date: Thu, 27 May 2021 17:32:19 +0200 Subject: [PATCH 113/251] Change target when zooming to be crosshair and border with crosshair --- .../skybrowser/include/screenspaceskytarget.h | 2 +- modules/skybrowser/shaders/target_fs.glsl | 38 ++++++++++++++----- .../skybrowser/src/screenspaceskytarget.cpp | 12 ++++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 2b26b667d5..e0964b267f 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -62,7 +62,7 @@ namespace openspace { properties::FloatProperty _showCrosshairThreshold; std::unique_ptr _texture; - UniformCache(modelTransform, viewProj, texture, showCrosshair, borderWidth, targetDimensions, borderColor) _uniformCache; + UniformCache(modelTransform, viewProj, texture, showCrosshair, showCrosshairInTarget, borderWidth, targetDimensions, borderColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; float _fieldOfView = 100.f; diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 797bbee5f4..10e66f13f7 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -2,6 +2,7 @@ uniform sampler2D texture1; uniform float borderWidth; uniform vec2 targetDimensions; uniform bool showCrosshair; +uniform bool showCrosshairInTarget; uniform vec4 borderColor; @@ -11,8 +12,8 @@ in vec4 vs_position; float crossLine(in float _width, in float _coord) { float center = 0.5f; - float line = smoothstep(center, center+(_width/2) , _coord) - - smoothstep(center-(_width/2), center, _coord); + float line = smoothstep(center, center+(_width/2), _coord) + - smoothstep(center-(_width/2), center, _coord); return line; } @@ -23,16 +24,26 @@ Fragment getFragment() { float ratio = targetDimensions.y / targetDimensions.x; - // draw crosshair - float crossWidth = 0.1f; - vec3 crosshair = vec3(crossLine(crossWidth*ratio, (vs_st).x) + crossLine(crossWidth, (vs_st).y)); - // draw square border - float borderBottomLeft = step(borderWidth*ratio, vs_st.x) * step(borderWidth*ratio, (1.0)-vs_st.x); - float borderTopRight = step(borderWidth, vs_st.y) * step(borderWidth, (1.0)-vs_st.y); - vec3 border = vec3(borderBottomLeft*borderTopRight); + float border_bl = step(borderWidth*ratio, vs_st.x) * step(borderWidth*ratio, (1.0)-vs_st.x); + float border_tr = step(borderWidth, vs_st.y) * step(borderWidth, (1.0)-vs_st.y); + vec3 border = vec3(border_bl*border_tr); - // show crosshair or border + // draw crosshair inside square border + float crosshair_border_linewidth = 0.06f; + float border_crosshair_bl = step(borderWidth*ratio*4, vs_st.x) * step(borderWidth*ratio*4, (1.0)-vs_st.x); + float border_crosshair_tr = step(borderWidth*4, vs_st.y) * step(borderWidth*4, (1.0)-vs_st.y); + vec3 crosshair_small = vec3(border_crosshair_bl*border_crosshair_tr); + + vec3 crosshair_inside_border = vec3(crossLine(crosshair_small.x * crosshair_border_linewidth, (vs_st).x) + + crossLine(crosshair_small.y * crosshair_border_linewidth, (vs_st).y)); + vec3 crosshair_and_border = (1.0 - border) + crosshair_inside_border; + + // draw crosshair + float crosshair_linewidth = 0.14f; + vec3 crosshair = vec3(crossLine(crosshair_linewidth*ratio*1.1, vs_st.x) + crossLine(crosshair_linewidth, vs_st.y)); + + // show crosshair or border or both frag.color = vec4(1,1,1,1); frag.color.rgba = vec4(borderColor); @@ -42,6 +53,13 @@ Fragment getFragment() { frag.color.a = 0.0; } } + else if(showCrosshairInTarget) { + frag.color.rgba = vec4(borderColor); + if(crosshair_and_border == vec3(0.0)) { + frag.color.a = 0.0; + } + + } else { if(border == vec3(1.0)) { frag.color.a = 0.0; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 40889faaf1..bbf4819158 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -38,8 +38,8 @@ namespace { "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " }; - constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture1", "showCrosshair", "borderWidth", "targetDimensions", "borderColor" + constexpr const std::array UniformNames = { + "ModelTransform", "ViewProjectionMatrix", "texture1", "showCrosshair", "showCrosshairInTarget", "borderWidth", "targetDimensions", "borderColor" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = @@ -77,7 +77,7 @@ namespace openspace { : ScreenSpaceRenderable(dictionary) , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) - , _showCrosshairThreshold(CrosshairThresholdInfo, 2.f, 1.f, 70.f) + , _showCrosshairThreshold(CrosshairThresholdInfo, 0.6f, 0.1f, 70.f) , _borderColor(220, 220, 220) { // Handle target dimension property @@ -221,15 +221,19 @@ namespace openspace { glDisable(GL_CULL_FACE); glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float borderWidth = 0.002f/_scale.value(); + float borderWidth = 0.0016f/_scale.value(); + float showCrosshairInTargetThreshold = 2.f; // show crosshair and target when browser FOV < 2 degrees glm::vec2 targetDim; bool showCrosshair; + bool showCrosshairInTarget; _targetDimensions.value() == glm::vec2(0) ? targetDim = glm::vec2(1) : targetDim = _targetDimensions.value(); _shader->activate(); + _fieldOfView < showCrosshairInTargetThreshold && _fieldOfView > _showCrosshairThreshold ? showCrosshairInTarget = true : showCrosshairInTarget = false; _fieldOfView < _showCrosshairThreshold ? showCrosshair = true : showCrosshair = false; _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); + _shader->setUniform(_uniformCache.showCrosshairInTarget, showCrosshairInTarget); _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetDimensions, targetDim); _shader->setUniform(_uniformCache.modelTransform, modelTransform); From 8e8ac4e90e3ef5f28f2d2e559566751f46aebc13 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 2 Jun 2021 15:35:07 +0200 Subject: [PATCH 114/251] Initialize browsers with lua api and load image collections upon startup. Add 3D browser functionality --- data/assets/renderableBrowser.asset | 32 +- .../skybrowser/include/renderableskybrowser.h | 15 + .../include/screenspaceskybrowser.h | 1 - modules/skybrowser/include/utility.h | 10 +- modules/skybrowser/include/wwtdatahandler.h | 2 - modules/skybrowser/skybrowsermodule.cpp | 174 ++++----- modules/skybrowser/skybrowsermodule.h | 10 +- modules/skybrowser/skybrowsermodule_lua.inl | 332 ++++++++++++------ .../skybrowser/src/renderableskybrowser.cpp | 84 ++++- .../skybrowser/src/screenspaceskybrowser.cpp | 15 +- modules/skybrowser/src/utility.cpp | 46 ++- 11 files changed, 476 insertions(+), 245 deletions(-) diff --git a/data/assets/renderableBrowser.asset b/data/assets/renderableBrowser.asset index 7f04a9101f..2748b32081 100644 --- a/data/assets/renderableBrowser.asset +++ b/data/assets/renderableBrowser.asset @@ -2,9 +2,10 @@ local assetHelper = asset.require("util/asset_helper") local transforms = asset.require("scene/solarsystem/sun/transforms") local PARSEC_CONSTANT = 3.0856776E16; +local browserId = "SkyBrowser3D"; -local spec = { - Identifier = "RenderableSkyBrowser1", +local browser = { + Identifier = browserId, Parent = transforms.SolarSystemBarycenter.Identifier, Transform = { Translation = { @@ -13,21 +14,36 @@ local spec = { -3.915 * PARSEC_CONSTANT, -150.153 * PARSEC_CONSTANT, -120.706 * PARSEC_CONSTANT - } + }, }, + Rotation = { + Type = "StaticRotation", + Rotation = {0.0, 0.0, 0.0} + } }, Renderable = { + Identifier = "SkyBrowser3DRenderable", Type = "RenderableSkyBrowser", Size = 10.0E11, Origin = "Center", - Billboard = true, - Url = "http://localhost:8000" + Billboard = false, + Url = "http://localhost:8000", + Opacity = 0.99 }, GUI = { - Name = "Renderable Sky Browser", + Name = "Sky Browser 3D", Path = "/SkyBrowser", } } -local objects = { spec } -assetHelper.registerSceneGraphNodesAndExport(asset, objects) +asset.onInitialize(function () + openspace.addSceneGraphNode(browser) + openspace.skybrowser.addToSkyBrowserModule(browserId) +end) + +asset.onDeinitialize(function () + openspace.removeScreenSpaceRenderable(browserId) + openspace.removeScreenSpaceRenderable(targetId) +end) + +asset.export("browser", {browser}) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index d9c5eabc46..10c545b34b 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma warning (push) @@ -36,6 +37,7 @@ namespace openspace { class BrowserInstance; class RenderHandler; class WebKeyboardHandler; + class ImageData; class RenderableSkyBrowser : public RenderablePlane { @@ -52,12 +54,20 @@ namespace openspace { void executeJavascript(std::string script) const; bool sendMessageToWWT(const ghoul::Dictionary& msg); + void connectToWwt(); + void stopConnectingToWwt(); + void displayImage(ImageData& image, int i); + void removeSelectedImage(ImageData& image, int i); + void setIdInBrowser(std::string id); + float fieldOfView() const; + std::deque& selectedImages(); protected: properties::Vec2Property _dimensions; std::unique_ptr _browserInstance; std::unique_ptr _texture; + private: class ScreenSpaceRenderHandler : public WebRenderHandler { @@ -80,7 +90,12 @@ namespace openspace { bool _isUrlDirty = false; bool _isDimensionsDirty = false; + + float _fov; + bool _connectToWwt; + std::thread _threadWwtMessages; + std::deque _selectedImages; }; } diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 09c2158ec6..92a311bff8 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -67,7 +67,6 @@ namespace openspace { // For capping the calls to change the zoom from scrolling constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; std::chrono::system_clock::time_point _lastUpdateTime; - int _imageId{ 0 }; bool _hasLoadedCollections{ false }; std::deque _selectedImages; }; diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index e76564f1ad..da5355124d 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -37,17 +37,17 @@ namespace openspace { glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords); glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord); + double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld); } namespace wwtmessage { // WWT messages ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, - const double fov, const bool moveInstantly = true); + const double fov, const double roll, const bool moveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); - ghoul::Dictionary createImageLayer(ImageData& image, int id = 0); - ghoul::Dictionary removeImageLayer(ImageData& image); - ghoul::Dictionary setLayerOpacity(const ImageData& image, - double opacity); + ghoul::Dictionary createImageLayer(const std::string& imageUrl, const std::string& id); + ghoul::Dictionary removeImageLayer(const std::string& imageId); + ghoul::Dictionary setLayerOpacity(const std::string& imageId, double opacity); ghoul::Dictionary setForegroundOpacity(double val); } } diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 90cc02e2cc..8d078cd804 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -54,7 +54,6 @@ namespace openspace::speck { namespace openspace { struct ImageData { - static constexpr int NO_ID = -1; std::string name; std::string thumbnailUrl; std::string imageUrl; @@ -66,7 +65,6 @@ namespace openspace { bool hasCelestCoords{ false }; bool has3dCoords{ false }; glm::dvec3 position3d; - int id{ NO_ID }; }; struct ImageCollection { diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 082bf6455b..832c492188 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -37,7 +37,7 @@ #include #include #include -#include + #include #include "skybrowsermodule_lua.inl" #include @@ -178,14 +178,6 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, - { - "remove3dSkyBrowser", - &skybrowser::luascriptfunctions::remove3dSkyBrowser, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, { "setOpacityOfImageLayer", &skybrowser::luascriptfunctions::setOpacityOfImageLayer, @@ -203,8 +195,8 @@ namespace openspace { "input. An input string should be the name of the system host star" }, { - "initializeBrowserAndTarget", - &skybrowser::luascriptfunctions::initializeBrowserAndTarget, + "initializeBrowser", + &skybrowser::luascriptfunctions::initializeBrowser, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " @@ -225,6 +217,14 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "set3dSelectedImagesAs2dSelection", + &skybrowser::luascriptfunctions::set3dSelectedImagesAs2dSelection, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, }; @@ -239,6 +239,7 @@ SkyBrowserModule::SkyBrowserModule() , currentlyDraggingObject(false) , resizeVector(0.f, 0.f) , changeViewWithinBrowser(false) + , _browser3d(nullptr) { global::callback::mousePosition->emplace_back( [&](double x, double y) { @@ -415,7 +416,7 @@ SkyBrowserModule::SkyBrowserModule() double solarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; double cameraSSBDistance = glm::length( global::navigationHandler->camera()->positionVec3()); - bool _cameraInSolarSystem = cameraSSBDistance < solarSystemRadius; + _cameraInSolarSystem = cameraSSBDistance < solarSystemRadius; double fadingTime = 2.0; double deltaTime = global::windowDelegate->deltaTime(); @@ -428,11 +429,19 @@ SkyBrowserModule::SkyBrowserModule() if (fadingIsFinished) { browser->property("Enabled")->set(false); + // Select the 3D browser when moving out of the solar system + if (_browser3d != nullptr) { + selectedBrowser = _browser3d->renderable()->identifier(); + } } } // If within solar system and browser is not visible else if (_cameraInSolarSystem && !browser->isEnabled()) { browser->property("Enabled")->set(true); + // Select the first 2D browser when moving into the solar system + if (browsers.size() != 0) { + selectedBrowser = std::begin(browsers)->second->identifier(); + } } // If within solar system and browser is visible if (_cameraInSolarSystem && browser->isEnabled()) { @@ -540,22 +549,22 @@ void SkyBrowserModule::createTargetBrowserPair() { ); openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.addToSkyBrowserModule(" + idTarget + ");", + "openspace.skybrowser.addToSkyBrowserModule('" + idTarget + "');", scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.addToSkyBrowserModule(" + idBrowser + ");", + "openspace.skybrowser.addToSkyBrowserModule('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.connectBrowserTarget(" + idBrowser + ");", + "openspace.skybrowser.connectBrowserTarget('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.connectBrowserTarget(" + idTarget + ");", + "openspace.skybrowser.connectBrowserTarget('" + idTarget + "');", scripting::ScriptEngine::RemoteScripting::Yes ); } @@ -600,82 +609,69 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { } -void SkyBrowserModule::create3dBrowser(ImageData& image) { - std::string id = "SkyBrowser3d" + std::to_string(browsers3d.size()+1); - glm::dvec3 position = image.position3d * distanceconstants::Parsec; - std::string translation = ghoul::to_string(position); - std::string guiPath = "/SkyBrowser"; +void SkyBrowserModule::place3dBrowser(ImageData& image) { + if (_browser3d) { + std::string id = _browser3d->identifier(); + std::string renderableId = _browser3d->renderable()->identifier(); + // Uris for properties + std::string sizeUri = "Scene." + id + "." + renderableId + ".Size"; + std::string positionUri = "Scene." + id + ".Translation.Position"; + std::string rotationUri = "Scene." + id + ".Rotation.Rotation"; + std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; + glm::dvec3 position = image.position3d * distanceconstants::Parsec; + // Calculate the size of the plane with trigonometry + // Calculate in equatorial coordinate system since the FOV is from Earth + // /| + // /_| Adjacent is the horizontal line, opposite the vertical + // \ | Calculate for half the triangle first, then multiply with 2 + // \| + glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); + double adjacent = glm::length(j2000); + double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); - // Calculate the size of the plane with trigonometry - // Calculate in equatorial coordinate system since the FOV is from Earth - // /| - // /_| Adjacent is the horizontal line, opposite the vertical - // \ | Calculate for half the triangle first, then multiply with 2 - // \| - glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); - double adjacent = glm::length(j2000); - double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); + // Calculate rotation to make the plane face the solar system barycenter + glm::dvec3 normal = glm::normalize(-position); + glm::dvec3 newRight = glm::normalize( + glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) + ); + glm::dvec3 newUp = glm::cross(normal, newRight); + // Face the Solar System Barycenter + glm::dmat3 rotation = glm::dmat3(1.0); + rotation[0] = newRight; + rotation[1] = newUp; + rotation[2] = normal; - // Calculate rotation to make the plane face the solar system barycenter - glm::dvec3 normal = glm::normalize(-position); - glm::dvec3 newRight = glm::normalize( - glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) - ); - glm::dvec3 newUp = glm::cross(normal, newRight); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle('" + sizeUri + "', " + std::to_string(opposite) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle('" + positionUri + "', " + ghoul::to_string(position) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle('" + rotationUri + "', " + ghoul::to_string(rotation) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); - glm::dmat3 originOrientedRotation = glm::dmat3(1.0); - originOrientedRotation[0] = newRight; - originOrientedRotation[1] = newUp; - originOrientedRotation[2] = normal; - - - const std::string browser = "{" - "Identifier = '" + id + "'," - "Parent = 'SolarSystemBarycenter'," - "Renderable = {" - "Type = 'RenderableSkyBrowser'," - "Size = " + std::to_string(opposite) + "," - "Origin = 'Center'," - "Billboard = false," - "Url = 'http://localhost:8000'" - "}," - "Transform = {" - "Translation = {" - "Type = 'StaticTranslation'," - "Position = " + translation + "" - "}," - "Rotation = {" - "Type = 'StaticRotation'," - "Rotation = " + ghoul::to_string(originOrientedRotation) + "" - "}" - "}," - "GUI = {" - "Name = '" + image.name + "'," - "Path = '" + guiPath + "'" - "}" - "}"; - LINFO(browser); - openspace::global::scriptEngine->queueScript( - "openspace.addSceneGraphNode(" + browser + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); + // Target camera on the 3D sky browser + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil)", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", '" + id + "')", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '')", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } } -void SkyBrowserModule::add3dBrowser(RenderableSkyBrowser* node) { - browsers3d.push_back(node); -} - -void SkyBrowserModule::remove3dBrowser(std::string& id) { - // Remove pointer to the renderable from module vector - browsers3d.erase(std::remove_if(std::begin(browsers3d), std::end(browsers3d), - [&](RenderableSkyBrowser* browser) { - return browser->identifier() == id; - })); - - openspace::global::scriptEngine->queueScript( - "openspace.removeSceneGraphNode(" + id + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); +void SkyBrowserModule::add3dBrowser(SceneGraphNode* node) { + _browser3d = node; } ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { @@ -697,6 +693,10 @@ std::vector& SkyBrowserModule::getBrowsersAndTargets() { return renderables; } +SceneGraphNode* SkyBrowserModule::get3dBrowser() { + return _browser3d; +} + void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { // Save coordinates to rotate to in galactic world coordinates diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 8d6f8261c6..aea1eb69d5 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -61,6 +61,7 @@ public: WWTDataHandler* getWWTDataHandler(); std::map& getSkyBrowsers(); std::vector& getBrowsersAndTargets(); + SceneGraphNode* get3dBrowser(); void startRotation(glm::dvec2 coordsEnd); void rotateCamera(double deltaTime); bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); @@ -69,12 +70,11 @@ public: bool browserIdExists(std::string id); std::string selectedBrowserId(); int loadImages(const std::string& root, const std::string& directory); - void add3dBrowser(RenderableSkyBrowser* node); - void remove3dBrowser(std::string& id); + void add3dBrowser(SceneGraphNode* node); bool cameraInSolarSystem(); void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); - void create3dBrowser(ImageData& image); + void place3dBrowser(ImageData& image); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -91,8 +91,8 @@ protected: std::vector renderables; // Only the browsers std::map browsers; - // 3D browsers - std::vector browsers3d; + // 3D browser + SceneGraphNode* _browser3d; // Pointer to what mouse is currently on ScreenSpaceRenderable* _mouseOnObject; // Dragging diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 64874570e6..7fa46e68a4 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -39,15 +39,17 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->selectedBrowserId()]; - if (selectedBrowser) { - ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + // TO DO: Make this prettier with 3D browsers... + ScreenSpaceSkyBrowser* selectedBrowser = nullptr; + if (module->browserIdExists(module->selectedBrowserId())) { + selectedBrowser = module->getSkyBrowsers()[module->selectedBrowserId()]; + } + ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; - // Load image, if the image has not been loaded yet - if (resultImage.id == ImageData::NO_ID) { - LINFO("Loading image " + resultImage.name); - selectedBrowser->addSelectedImage(resultImage, i); - } + if (selectedBrowser) { + // Load image into browser + LINFO("Loading image " + resultImage.name); + selectedBrowser->addSelectedImage(resultImage, i); ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); // If the image has coordinates, move the target @@ -59,7 +61,8 @@ namespace openspace::skybrowser::luascriptfunctions { glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); float r = windowRatio.x / windowRatio.y; - bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); + bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && + abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; // If the coordinate is not in view, rotate camera if (!coordIsWithinView || coordIsBehindCamera) { @@ -68,7 +71,17 @@ namespace openspace::skybrowser::luascriptfunctions { } } else { - LINFO("No browser selected!"); + SceneGraphNode* node = module->get3dBrowser(); + if (node) { + RenderableSkyBrowser* browser3d = dynamic_cast( + node->renderable()); + if (browser3d) { + browser3d->displayImage(resultImage, i); + } + else { + LINFO("No browser selected!"); + } + } } return 0; @@ -134,17 +147,30 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string id = ghoul::lua::value(L, 1); LINFO("Connection established to WorldWide Telescope application in " + id); LINFO("Loading image collections to " + id); - SkyBrowserModule* module = global::moduleEngine->module(); // Load the collections here because here we know that the browser can execute javascript - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - if (module->browserIdExists(id)) { - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[id]; - if (!browser->hasLoadedCollections()) { - browser->sendMessageToWWT(wwtmessage::loadCollection(root)); - browser->setHasLoadedCollections(true); - } - } + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + + ScreenSpaceSkyBrowser* browser = dynamic_cast( + global::renderEngine->screenSpaceRenderable(id)); + if (browser && !browser->hasLoadedCollections()) { + browser->sendMessageToWWT(wwtmessage::loadCollection(root)); + browser->setHasLoadedCollections(true); + } + else { + SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); + if (node) { + RenderableSkyBrowser* browser3d = dynamic_cast( + node->renderable()); + if (browser3d) { + // Load Image collections + browser3d->stopConnectingToWwt(); + LINFO("Load images to " + browser3d->identifier()); + browser3d->sendMessageToWWT(wwtmessage::loadCollection(root)); + LINFO("Image collection loaded in " + browser3d->identifier()); + } + } + } return 0; } @@ -159,47 +185,61 @@ namespace openspace::skybrowser::luascriptfunctions { for (std::pair pair : browsers) { pair.second->setIdInBrowser(); } - + SceneGraphNode* node = module->get3dBrowser(); + if(node) { + std::string id = node->identifier(); + RenderableSkyBrowser* browsers3d = dynamic_cast( + node->renderable()); + browsers3d->setIdInBrowser(id); + } return 0; } int connectBrowserTarget(lua_State* L) { - // In order to connect, the target and browsers must have been loaded into the - // module. This is to ensure that the renderables have been found - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::connectBrowserTarget"); const std::string id = ghoul::lua::value(L, 1); - // Find the screenspace renderable that has the id - SkyBrowserModule* module = global::moduleEngine->module(); - std::vector renderables = module->getBrowsersAndTargets(); - auto found = std::find_if(std::begin(renderables), std::end(renderables), - [&](ScreenSpaceRenderable* renderable) { - return renderable && id == renderable->identifier(); - }); - if (dynamic_cast(*found)) { - ScreenSpaceSkyBrowser* browser = dynamic_cast(*found); + // Find the ScreenSpaceRenderable that has the id + ScreenSpaceRenderable* found = global::renderEngine->screenSpaceRenderable(id); + + // Connect it to its corresponding target / browser + if (dynamic_cast(found)) { + ScreenSpaceSkyBrowser* browser = dynamic_cast(found); browser->setConnectedTarget(); } - else if (dynamic_cast(*found)) { - ScreenSpaceSkyTarget* target = dynamic_cast(*found); + else if (dynamic_cast(found)) { + ScreenSpaceSkyTarget* target = dynamic_cast(found); target->setConnectedBrowser(); } return 0; } - int initializeBrowserAndTarget(lua_State* L) { + int initializeBrowser(lua_State* L) { // Initialize browser with ID and its corresponding target - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowserAndTarget"); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowser"); const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->browserIdExists(id)) { - module->getSkyBrowsers()[id]->initializeBrowser(); - ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); + ScreenSpaceSkyBrowser* browser = dynamic_cast( + global::renderEngine->screenSpaceRenderable(id)); + LINFO("Initializing sky browsers"); + if (browser) { + browser->initializeBrowser(); + ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { target->initializeWithBrowser(); } } + else { + SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); + if (node) { + RenderableSkyBrowser* browser3d = dynamic_cast( + node->renderable()); + if (browser3d && id == node->identifier()) { + // Initialize + LINFO("Initializing 3D sky browsers"); + browser3d->connectToWwt(); + } + } + } return 0; } @@ -207,10 +247,22 @@ namespace openspace::skybrowser::luascriptfunctions { int addToSkyBrowserModule(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addToSkyBrowserModule"); const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + LINFO("Add to sky browser module id " + id); ScreenSpaceRenderable* object = global::renderEngine->screenSpaceRenderable(id); - SkyBrowserModule* module = global::moduleEngine->module(); - module->addRenderable(object); + if (object) { + // Add to module + module->addRenderable(object); + } + else { + SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); + if (node) { + // Add to module + module->add3dBrowser(node); + } + } + return 0; } @@ -295,7 +347,6 @@ namespace openspace::skybrowser::luascriptfunctions { std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; - // Calculate the smallest FOV of vertical and horizontal float HFOV = global::windowDelegate->getHorizFieldOfView(); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); @@ -318,50 +369,93 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); // Pass data for all the browsers and the corresponding targets - std::map browsers = module->getSkyBrowsers(); + if (module->cameraInSolarSystem()) { + std::map browsers = module->getSkyBrowsers(); - for (std::pair pair : browsers) { - ScreenSpaceSkyBrowser* browser = pair.second; - std::string id = pair.first; + for (std::pair pair : browsers) { + ScreenSpaceSkyBrowser* browser = pair.second; + std::string id = pair.first; + // Convert deque to vector so ghoul can read it + std::vector selectedImagesVector; + std::deque selectedImages = browser->selectedImages(); + std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { + selectedImagesVector.push_back(index); + }); + // Only add browsers that have an initialized target + ScreenSpaceSkyTarget* target = browser->getSkyTarget(); + if (target) { + glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial(); + glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical); + std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; + // Convert color to vector so ghoul can read it + glm::ivec3 color = browser->_borderColor.value(); + std::vector colorVec = { color.r, color.g, color.b }; + + ghoul::lua::push(L, id); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "id", id); + lua_settable(L, -3); + ghoul::lua::push(L, "name", browser->guiName()); + lua_settable(L, -3); + ghoul::lua::push(L, "FOV", browser->fieldOfView()); + lua_settable(L, -3); + ghoul::lua::push(L, "selectedImages", selectedImagesVector); + lua_settable(L, -3); + ghoul::lua::push(L, "cartesianDirection", celestialCartVec); + lua_settable(L, -3); + ghoul::lua::push(L, "ra", celestialSpherical.x); + lua_settable(L, -3); + ghoul::lua::push(L, "dec", celestialSpherical.y); + lua_settable(L, -3); + ghoul::lua::push(L, "color", colorVec); + lua_settable(L, -3); + + // Set table for the current target + lua_settable(L, -3); + } + } + } + else { + SceneGraphNode* node = module->get3dBrowser(); + RenderableSkyBrowser* browser3d = dynamic_cast( + node->renderable()); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - std::deque selectedImages = browser->selectedImages(); + std::deque selectedImages = browser3d->selectedImages(); std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { selectedImagesVector.push_back(index); }); - // Only add browsers that have an initialized target - ScreenSpaceSkyTarget* target = browser->getSkyTarget(); - if (target) { - glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial(); - glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical); - std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; - // Convert color to vector so ghoul can read it - glm::ivec3 color = browser->_borderColor.value(); - std::vector colorVec = { color.r, color.g, color.b }; + glm::dvec3 worldPosition = node->position(); + glm::dvec3 celestialCart = skybrowser::galacticCartesianToJ2000Cartesian(worldPosition); + glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); + std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; + // Convert color to vector so ghoul can read it + //glm::ivec3 color = browser->_borderColor.value(); + std::vector colorVec = { 200, 200, 200 }; - ghoul::lua::push(L, id); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "id", id); - lua_settable(L, -3); - ghoul::lua::push(L, "name", browser->guiName()); - lua_settable(L, -3); - ghoul::lua::push(L, "FOV", browser->fieldOfView()); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedImages", selectedImagesVector); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", celestialCartVec); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", celestialSpherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", celestialSpherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "color", colorVec); - lua_settable(L, -3); - - // Set table for the current target - lua_settable(L, -3); - } + ghoul::lua::push(L, browser3d->identifier()); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "id", browser3d->identifier()); + lua_settable(L, -3); + ghoul::lua::push(L, "name", node->guiName()); + lua_settable(L, -3); + ghoul::lua::push(L, "FOV", browser3d->fieldOfView()); + lua_settable(L, -3); + ghoul::lua::push(L, "selectedImages", selectedImagesVector); + lua_settable(L, -3); + ghoul::lua::push(L, "cartesianDirection", celestialCartVec); + lua_settable(L, -3); + ghoul::lua::push(L, "ra", celestialSpherical.x); + lua_settable(L, -3); + ghoul::lua::push(L, "dec", celestialSpherical.y); + lua_settable(L, -3); + ghoul::lua::push(L, "color", colorVec); + lua_settable(L, -3); + + // Set table for the current target + lua_settable(L, -3); } @@ -371,27 +465,68 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->browserIdExists(id)) { + std::string idNode3dBrowser = module->get3dBrowser()->identifier(); + std::string id3dBrowser = module->get3dBrowser()->renderable()->identifier(); + + if(module->cameraInSolarSystem() && module->browserIdExists(id)) { ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); if (target) { module->startRotation(target->getTargetDirectionCelestial()); } } + else if (!module->cameraInSolarSystem() && id3dBrowser == id) { + std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', Nil)" + "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', '" + idNode3dBrowser + "')" + "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '')", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } return 0; } + + int set3dSelectedImagesAs2dSelection(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + + if (module->browserIdExists(id) && module->get3dBrowser() != nullptr) { + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[id]; + RenderableSkyBrowser* browser3d = dynamic_cast( + module->get3dBrowser()->renderable()); + // Empty 3D browser selection + browser3d->selectedImages().clear(); + // Copy 2D selection of images to 3D browser + std::deque images = browser->selectedImages(); + std::for_each(std::begin(images), std::end(images), [&](int index) { + ImageData& image = module->getWWTDataHandler()->getLoadedImages()[index]; + browser3d->displayImage(image, index); + }); + } + + return 0; + } + int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); const std::string browserId = ghoul::lua::value(L, 1); const int i = ghoul::lua::value(L, 2); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); + ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; + ghoul::Dictionary message = wwtmessage::setLayerOpacity(std::to_string(i), opacity); - if (module->browserIdExists(browserId)) { - ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; - ghoul::Dictionary message = wwtmessage::setLayerOpacity(image, opacity); + if (module->browserIdExists(browserId)) { module->getSkyBrowsers()[browserId]->sendMessageToWWT(message); } + else if (module->get3dBrowser() != nullptr) { + RenderableSkyBrowser* browser3d = dynamic_cast( + module->get3dBrowser()->renderable()); + browser3d->sendMessageToWWT(message); + } + return 0; } @@ -431,7 +566,10 @@ namespace openspace::skybrowser::luascriptfunctions { // If the image has a 3D position, add it to the scene graph if (image.has3dCoords) { - module->create3dBrowser(image); + RenderableSkyBrowser* browser = dynamic_cast( + module->get3dBrowser()->renderable()); + browser->displayImage(image, i); + module->place3dBrowser(image); } else { LINFO("Image has no 3D coordinate!"); @@ -440,16 +578,6 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } - int remove3dSkyBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::remove3dSkyBrowser"); - // Image index to place in 3D - std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - module->remove3dBrowser(id); - - return 0; - } - int removeSelectedImageInBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); // Image index @@ -457,11 +585,19 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string browserId = ghoul::lua::value(L, 2); // Get browser SkyBrowserModule* module = global::moduleEngine->module(); - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; - // Remove image - browser->removeSelectedImage(resultImage, i); + + if (module->browserIdExists(browserId)) { + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; + // Remove image + browser->removeSelectedImage(resultImage, i); + } + else if (module->get3dBrowser() != nullptr) { + RenderableSkyBrowser* browser3d = dynamic_cast( + module->get3dBrowser()->renderable()); + browser3d->removeSelectedImage(resultImage, i); + } return 0; } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 39a51878e3..13d34f170a 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,8 +1,10 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -14,7 +16,7 @@ #include #include #include - +#include namespace { @@ -37,10 +39,14 @@ namespace { "Reload the web browser" }; - struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { + + struct [[codegen::Dictionary(RenderableSkyBrowser)]] Parameters { // [[codegen::verbatim(DimensionsInfo.description)]] std::optional browserDimensions; + + // [[codegen::verbatim(UrlInfo.description)]] + std::optional url; }; #include "renderableskybrowser_codegen.cpp" @@ -62,7 +68,12 @@ namespace openspace { , _url(UrlInfo) , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) , _reload(ReloadInfo) + , _fov(70.f) + , _connectToWwt(true) { + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _url = p.url.value_or(_url); std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { @@ -73,10 +84,6 @@ namespace openspace { } setIdentifier(identifier); - if (dictionary.hasValue(UrlInfo.identifier)) { - _url = dictionary.value(UrlInfo.identifier); - } - // Ensure the texture is a square for now // Maybe change later glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); @@ -118,9 +125,6 @@ namespace openspace { _browserInstance->initialize(); _browserInstance->loadUrl(_url); _browserInstance->reshape(_dimensions.value()); - // Add pointer to module - SkyBrowserModule* module = global::moduleEngine->module(); - module->add3dBrowser(this); } void RenderableSkyBrowser::deinitializeGL() { @@ -183,4 +187,66 @@ namespace openspace { executeJavascript(script); return true; } + + void RenderableSkyBrowser::displayImage(ImageData& image, int i) { + sendMessageToWWT(wwtmessage::moveCamera(image.celestCoords, image.fov, 0.0)); + _fov = image.fov; + // Add to selected images if there are no duplicates + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it == std::end(_selectedImages)) { + // Push newly selected image to front + _selectedImages.push_front(i); + // Create image layer and center WWT app on the image + sendMessageToWWT(wwtmessage::createImageLayer(image.imageUrl, std::to_string(i))); + LINFO("Image has been loaded to " + identifier()); + } + } + + void RenderableSkyBrowser::removeSelectedImage(ImageData& image, int i) { + // Remove from selected list + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it != std::end(_selectedImages)) { + _selectedImages.erase(it); + sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i))); + } + } + + void RenderableSkyBrowser::setIdInBrowser(std::string id) { + // Send ID to it's browser + executeJavascript("setId('" + id + "')"); + } + + float RenderableSkyBrowser::fieldOfView() const { + return _fov; + } + + void RenderableSkyBrowser::connectToWwt() { + + // Start a thread to enable user interaction while sending the calls to WWT + _threadWwtMessages = std::thread([&] { + while (_connectToWwt) { + + glm::dvec2 aim { 0.0 }; + // Send a message just to establish contact + ghoul::Dictionary message = wwtmessage::moveCamera(aim, _fov, 0.0); + sendMessageToWWT(message); + + // Sleep so we don't bombard WWT with too many messages + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + }); + } + + void RenderableSkyBrowser::stopConnectingToWwt() { + _connectToWwt = false; + + if (_threadWwtMessages.joinable()) { + _threadWwtMessages.join(); + } + } + + std::deque& RenderableSkyBrowser::selectedImages() { + return _selectedImages; + } + } // namespace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 4a20c26d6a..3c0b8c03cd 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -89,6 +89,7 @@ namespace openspace { while (glm::length(_borderColor.value()) < 222) { _borderColor = glm::ivec3(rand() % 256, rand() % 256, rand() % 256); } + // Handle target dimension property const Parameters p = codegen::bake(dictionary); _browserDimensions = p.browserDimensions.value_or(_browserDimensions); @@ -242,7 +243,11 @@ namespace openspace { while (_camIsSyncedWWT) { if (_skyTarget) { glm::dvec2 aim = _skyTarget->getTargetDirectionCelestial(); - ghoul::Dictionary message = wwtmessage::moveCamera(aim, _vfieldOfView); + // Calculate roll between up vector of camera and J2000 equatorial north + glm::dvec3 upVector = global::navigationHandler->camera()->lookUpVectorWorldSpace(); + glm::dvec3 viewVector = global::navigationHandler->camera()->viewDirectionWorldSpace(); + double roll = skybrowser::calculateRoll(upVector, viewVector); + ghoul::Dictionary message = wwtmessage::moveCamera(aim, _vfieldOfView, roll); sendMessageToWWT(message); } @@ -330,23 +335,23 @@ namespace openspace { } void ScreenSpaceSkyBrowser::addSelectedImage(ImageData& image, int i) { - sendMessageToWWT(wwtmessage::createImageLayer(image, _imageId)); - sendMessageToWWT(wwtmessage::setLayerOpacity(image, 1.0)); - _imageId++; // Ensure there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it == std::end(_selectedImages)) { // Push newly selected image to front _selectedImages.push_front(i); + // Index of image is used as layer ID as it is unique in the image data set + sendMessageToWWT(wwtmessage::createImageLayer(image.imageUrl, std::to_string(i))); + sendMessageToWWT(wwtmessage::setLayerOpacity(std::to_string(i), 1.0)); } } void ScreenSpaceSkyBrowser::removeSelectedImage(ImageData& image, int i) { - sendMessageToWWT(wwtmessage::removeImageLayer(image)); // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it != std::end(_selectedImages)) { _selectedImages.erase(it); + sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i))); } } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index fa3fd27a34..41cee753d4 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -90,25 +90,26 @@ namespace openspace::skybrowser { // Transform galactic coord to screen space return galacticToScreenSpace(imageCoordsGalacticCartesian); } -} -// WWT messages -namespace openspace::wwtmessage { - // WWT messages - ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly) { - using namespace std::string_literals; - ghoul::Dictionary msg; - - // Calculate roll between up vector of camera and J2000 equatorial north - glm::dvec3 upVector = global::navigationHandler->camera()->lookUpVectorWorldSpace(); - glm::dvec3 viewVector = global::navigationHandler->camera()->viewDirectionWorldSpace(); - glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(upVector); - glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(viewVector); + double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld) { + glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(upWorld); + glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(forwardWorld); glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NORTH_POLE); double dotNorthUp = glm::dot(skybrowser::NORTH_POLE, camUpJ2000); double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000); double roll = glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); + return roll; + } +} + +// WWT messages +namespace openspace::wwtmessage { + // WWT messages + ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, + const double roll, const bool moveInstantly) { + using namespace std::string_literals; + ghoul::Dictionary msg; // Create message msg.setValue("event", "center_on_coordinates"s); @@ -140,34 +141,29 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary createImageLayer(ImageData& image, int id) { - std::string idString = std::to_string(id); - image.id = id; - + ghoul::Dictionary createImageLayer(const std::string& imageUrl, const std::string& id) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_create"s); - msg.setValue("id", idString); - msg.setValue("url", image.imageUrl); + msg.setValue("id", id); + msg.setValue("url", imageUrl); return msg; } - ghoul::Dictionary removeImageLayer(ImageData& image) { + ghoul::Dictionary removeImageLayer(const std::string& imageId) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_remove"s); - msg.setValue("id", std::to_string(image.id)); - image.id = ImageData::NO_ID; + msg.setValue("id", imageId); return msg; } - ghoul::Dictionary setLayerOpacity(const ImageData& image, double opacity) { - std::string idString = std::to_string(image.id); + ghoul::Dictionary setLayerOpacity(const std::string& imageId, double opacity) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_set"s); - msg.setValue("id", idString); + msg.setValue("id", imageId); msg.setValue("setting", "opacity"s); msg.setValue("value", opacity); From d840d342d384a21851da9092c66f0220ed102e7a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 2 Jun 2021 15:35:30 +0200 Subject: [PATCH 115/251] Set better name to browser and target in GUI --- data/assets/skyBrowserTargetPair.asset | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 5bc6656e43..1657e5289c 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -6,7 +6,7 @@ local browserId = "SkyBrowser0" local browser = { Type = "ScreenSpaceSkyBrowser", Identifier = browserId, - Name = "SkyBrowser", + Name = "Sky Browser", Url = "http://localhost:8000/", FaceCamera = false, TargetID = targetId, @@ -18,7 +18,7 @@ local browser = { local target = { Type = "ScreenSpaceSkyTarget", Identifier = targetId, - Name = "Target", + Name = "Sky Target", FaceCamera = false, BrowserID = browserId, UseRadiusAzimuthElevation = false, From 111c719ed77595d720c2a3b71c72d4b6917ea6d9 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 2 Jun 2021 15:47:07 +0200 Subject: [PATCH 116/251] Cleanup: Rename function to better name and remove duplicates of code --- modules/skybrowser/skybrowsermodule.cpp | 35 ++++++++++++--------- modules/skybrowser/skybrowsermodule.h | 3 +- modules/skybrowser/skybrowsermodule_lua.inl | 10 ++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 832c492188..fe4e740e2c 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -653,24 +653,12 @@ void SkyBrowserModule::place3dBrowser(ImageData& image) { "openspace.setPropertyValueSingle('" + rotationUri + "', " + ghoul::to_string(rotation) + ");", scripting::ScriptEngine::RemoteScripting::Yes ); - - // Target camera on the 3D sky browser - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil)", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", '" + id + "')", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '')", - scripting::ScriptEngine::RemoteScripting::Yes - ); + lookAt3dBrowser(); + } } -void SkyBrowserModule::add3dBrowser(SceneGraphNode* node) { +void SkyBrowserModule::set3dBrowser(SceneGraphNode* node) { _browser3d = node; } @@ -697,6 +685,23 @@ SceneGraphNode* SkyBrowserModule::get3dBrowser() { return _browser3d; } +void SkyBrowserModule::lookAt3dBrowser() { + std::string id = _browser3d->identifier(); + // Target camera on the 3D sky browser + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil)", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", '" + id + "')", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '')", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { // Save coordinates to rotate to in galactic world coordinates diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index aea1eb69d5..a71be0b5ae 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -70,11 +70,12 @@ public: bool browserIdExists(std::string id); std::string selectedBrowserId(); int loadImages(const std::string& root, const std::string& directory); - void add3dBrowser(SceneGraphNode* node); + void set3dBrowser(SceneGraphNode* node); bool cameraInSolarSystem(); void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); void place3dBrowser(ImageData& image); + void lookAt3dBrowser(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 7fa46e68a4..802f03d100 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -259,7 +259,7 @@ namespace openspace::skybrowser::luascriptfunctions { SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); if (node) { // Add to module - module->add3dBrowser(node); + module->set3dBrowser(node); } } @@ -475,13 +475,7 @@ namespace openspace::skybrowser::luascriptfunctions { } } else if (!module->cameraInSolarSystem() && id3dBrowser == id) { - std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', Nil)" - "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', '" + idNode3dBrowser + "')" - "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '')", - scripting::ScriptEngine::RemoteScripting::Yes - ); + module->lookAt3dBrowser(); } return 0; From 0221ca1c20a14d9995cf2ccd7f41be1db805a949 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 3 Jun 2021 09:22:31 +0200 Subject: [PATCH 117/251] Set browser to selected upon startup --- data/assets/skyBrowserTargetPair.asset | 1 + modules/skybrowser/include/screenspaceskytarget.h | 3 ++- modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 2 ++ modules/skybrowser/src/screenspaceskytarget.cpp | 14 +++++++++----- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 1657e5289c..970af7c6ea 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -32,6 +32,7 @@ asset.onInitialize(function () openspace.skybrowser.addToSkyBrowserModule(targetId) openspace.skybrowser.connectBrowserTarget(browserId) openspace.skybrowser.connectBrowserTarget(targetId) + openspace.skybrowser.setSelectedBrowser(browserId) end) asset.onDeinitialize(function () diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 5eba77f5a4..17446f9e88 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -49,6 +49,7 @@ namespace openspace { glm::dvec2 getTargetDirectionCelestial(); void unlock(); void lock(); + bool isLocked(); void animateToCoord(double deltaTime); void startAnimation(glm::dvec2 coordsEnd, float FOVEnd); bool animateFOV(float endFOV, float deltaTime); @@ -71,7 +72,7 @@ namespace openspace { ScreenSpaceSkyBrowser* _skyBrowser; glm::ivec3 _borderColor; // Locking target to a coordinate on the sky - bool isLocked; + bool _isLocked; glm::dvec2 lockedCelestialCoords; std::thread _lockTargetThread; // Animating the target diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index fe4e740e2c..4fff48375e 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -499,7 +499,7 @@ void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { // Sort on z coordinate, objects closer to camera are in beginning of list std::sort(renderables.begin(), renderables.end()); ScreenSpaceSkyBrowser* browser = to_browser(object); - if (browser) { + if (browser) { browsers[browser->identifier()] = browser; } } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 802f03d100..713ee43be2 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -410,6 +410,8 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); + ghoul::lua::push(L, "isLocked", target->isLocked()); + lua_settable(L, -3); // Set table for the current target lua_settable(L, -3); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index f992eef572..e17c3c7f34 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -308,28 +308,32 @@ namespace openspace { } void ScreenSpaceSkyTarget::unlock() { - isLocked = false; + _isLocked = false; if (_lockTargetThread.joinable()) { _lockTargetThread.join(); } } void ScreenSpaceSkyTarget::lock() { - if (isLocked) { + if (_isLocked) { unlock(); } - isLocked = true; + _isLocked = true; lockedCelestialCoords = getTargetDirectionCelestial(); // Start a thread to enable user interactions while locking target _lockTargetThread = std::thread([&] { - while (isLocked) { + while (_isLocked) { glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(lockedCelestialCoords); _cartesianPosition = imageCoordsScreenSpace; } }); } + bool ScreenSpaceSkyTarget::isLocked() { + return _isLocked; + } + glm::dvec2 ScreenSpaceSkyTarget::getTargetDirectionCelestial() { // Calculate the galactic coordinate of the target direction // with infinite radius @@ -360,7 +364,7 @@ namespace openspace { else { // Set the exact target position and lock target when it first arrives // to the position - if (!isLocked) { + if (!_isLocked) { _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsToAnimateTo); lock(); } From e3c0e286fec96e3d0aa49c2f897c45cbcfee95bc Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 3 Jun 2021 10:03:27 +0200 Subject: [PATCH 118/251] Add functionality to center target on screen, when it has been lost locked somewhere for example --- .../skybrowser/include/screenspaceskytarget.h | 4 +-- modules/skybrowser/include/utility.h | 1 + modules/skybrowser/skybrowsermodule.cpp | 8 ++++++ modules/skybrowser/skybrowsermodule_lua.inl | 28 +++++++++++++++---- .../skybrowser/src/screenspaceskytarget.cpp | 18 +++++++----- modules/skybrowser/src/utility.cpp | 9 ++++++ 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 17446f9e88..54bc91d1a0 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -51,7 +51,7 @@ namespace openspace { void lock(); bool isLocked(); void animateToCoord(double deltaTime); - void startAnimation(glm::dvec2 coordsEnd, float FOVEnd); + void startAnimation(glm::dvec2 coordsEnd, float FOVEnd, bool lockAfterwards = true); bool animateFOV(float endFOV, float deltaTime); glm::mat4 scaleMatrix() override; @@ -82,7 +82,7 @@ namespace openspace { glm::dvec3 _coordsStartAnimation; double animationTime = 1.0; float FOVToAnimateTo; - float currentFOV; + bool _lockAfterwards; }; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index da5355124d..f76c618bde 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -38,6 +38,7 @@ namespace openspace { glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord); double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld); + glm::dvec3 cameraDirectionJ2000Cartesian(); } namespace wwtmessage { // WWT messages diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 4fff48375e..31408a2045 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -225,6 +225,14 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "centerTargetOnScreen", + &skybrowser::luascriptfunctions::centerTargetOnScreen, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 713ee43be2..3d491c381e 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -337,11 +337,7 @@ namespace openspace::skybrowser::luascriptfunctions { // Add the window data for OpenSpace ghoul::lua::push(L, "OpenSpace"); lua_newtable(L); - // Get the view direction of the screen in cartesian J2000 coordinates - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - constexpr double infinity = std::numeric_limits::max(); - glm::dvec3 galCoord = camPos + (infinity * global::navigationHandler->camera()->viewDirectionWorldSpace()); - glm::dvec3 cartesianJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(galCoord); + glm::dvec3 cartesianJ2000 = skybrowser::cameraDirectionJ2000Cartesian(); glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000); // Convert to vector so ghoul can read it std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; @@ -526,6 +522,28 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } + int centerTargetOnScreen(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->browserIdExists(id)) { + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[id]; + if (browser && browser->getSkyTarget()) { + // Animate the target to the center of the screen + browser->getSkyTarget()->unlock(); + // Get camera direction in celestial spherical coordinates + glm::dvec3 viewDirection = skybrowser::cameraDirectionJ2000Cartesian(); + glm::dvec2 centerOfScreen = skybrowser::cartesianToSpherical( + viewDirection); + // Keep the current fov + float fov = browser->fieldOfView(); + browser->getSkyTarget()->startAnimation(centerOfScreen, fov, false); + browser->getSkyTarget()->unlock(); + } + } + return 0; + } + int setSelectedBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); const std::string id = ghoul::lua::value(L, 1); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index e17c3c7f34..74043e378a 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -362,10 +362,10 @@ namespace openspace { _coordsStartAnimation = glm::normalize(newDir); } else { - // Set the exact target position and lock target when it first arrives - // to the position - if (!_isLocked) { - _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsToAnimateTo); + // Set the exact target position + _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsToAnimateTo); + // Lock target when it first arrives to the position + if (!_isLocked && _lockAfterwards) { lock(); } // When target is in position, animate the FOV until it has finished @@ -378,7 +378,8 @@ namespace openspace { bool ScreenSpaceSkyTarget::animateFOV(float endFOV, float deltaTime) { if (!_skyBrowser) { - ScreenSpaceSkyBrowser* browser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + ScreenSpaceSkyBrowser* browser = dynamic_cast( + global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); setBrowser(browser); } if (_skyBrowser) { @@ -398,13 +399,16 @@ namespace openspace { return true; } - void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd) { + void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd, + bool lockAfterwards) { // Save the Cartesian celestial coordinates for animation // to make sure wrap around works _coordsToAnimateTo = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd)); - _coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian(getTargetDirectionCelestial())); + _coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian( + getTargetDirectionCelestial())); FOVToAnimateTo = FOVEnd; isAnimated = true; + _lockAfterwards = lockAfterwards; } properties::FloatProperty& ScreenSpaceSkyTarget::getOpacity() { return _opacity; diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 41cee753d4..c297de4280 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -101,6 +101,15 @@ namespace openspace::skybrowser { double roll = glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); return roll; } + + glm::dvec3 cameraDirectionJ2000Cartesian() { + // Get the view direction of the screen in cartesian J2000 coordinates + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + constexpr double infinity = std::numeric_limits::max(); + glm::dvec3 galCoord = camPos + (infinity * global::navigationHandler->camera()->viewDirectionWorldSpace()); + glm::dvec3 cartesianJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(galCoord); + return cartesianJ2000; + } } // WWT messages From 6d0efc99df5aabb648c239f21bd86fca342bcb7b Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 3 Jun 2021 10:46:55 +0200 Subject: [PATCH 119/251] Disable hover circle outside of solar system --- modules/skybrowser/skybrowsermodule_lua.inl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 3d491c381e..0cacc92280 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -95,7 +95,7 @@ namespace openspace::skybrowser::luascriptfunctions { const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Only move and show circle if the image has coordinates - if (resultImage.hasCelestCoords) { + if (resultImage.hasCelestCoords && module->cameraInSolarSystem()) { // Make circle visible ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(true); @@ -110,7 +110,9 @@ namespace openspace::skybrowser::luascriptfunctions { int disableHoverCircle(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); - hoverCircle->property("Enabled")->set(false); + if (hoverCircle->isEnabled()) { + hoverCircle->property("Enabled")->set(false); + } return 0; } From 2df2e45f851415d7260e3131227d4c6e032585b2 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 3 Jun 2021 11:27:40 +0200 Subject: [PATCH 120/251] Change name of function to move 3D browser to a better suited name for lua function --- modules/skybrowser/skybrowsermodule.cpp | 4 ++-- modules/skybrowser/skybrowsermodule_lua.inl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 31408a2045..1656d1b2a7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -171,8 +171,8 @@ namespace openspace { "input. An input string should be the name of the system host star" }, { - "create3dSkyBrowser", - &skybrowser::luascriptfunctions::create3dSkyBrowser, + "place3dSkyBrowser", + &skybrowser::luascriptfunctions::place3dSkyBrowser, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 0cacc92280..c4c5fa8dd8 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -573,8 +573,8 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } - int create3dSkyBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::create3dSkyBrowser"); + int place3dSkyBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::place3dSkyBrowser"); // Image index to place in 3D const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); From d3736aeb8291e118dee9f1a5eb7927a13658e222 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 8 Jun 2021 19:12:44 +0200 Subject: [PATCH 121/251] Change to use server instead of localhost for browsers, and fix some bugs --- data/assets/renderableBrowser.asset | 3 +- data/assets/skyBrowserTargetPair.asset | 2 +- .../skybrowser/include/renderableskybrowser.h | 1 + .../include/screenspaceskybrowser.h | 1 + modules/skybrowser/include/utility.h | 1 + modules/skybrowser/skybrowsermodule.cpp | 48 ++++++++++++------- modules/skybrowser/skybrowsermodule_lua.inl | 31 ++++++++++-- .../skybrowser/src/renderableskybrowser.cpp | 9 ++++ .../skybrowser/src/screenspaceskybrowser.cpp | 10 ++++ modules/skybrowser/src/utility.cpp | 15 ++++++ 10 files changed, 97 insertions(+), 24 deletions(-) diff --git a/data/assets/renderableBrowser.asset b/data/assets/renderableBrowser.asset index 2748b32081..57ae2c63ad 100644 --- a/data/assets/renderableBrowser.asset +++ b/data/assets/renderableBrowser.asset @@ -3,6 +3,7 @@ local transforms = asset.require("scene/solarsystem/sun/transforms") local PARSEC_CONSTANT = 3.0856776E16; local browserId = "SkyBrowser3D"; +local url = "https://data.openspaceproject.com/dist/skybrowser/page/"; local browser = { Identifier = browserId, @@ -27,7 +28,7 @@ local browser = { Size = 10.0E11, Origin = "Center", Billboard = false, - Url = "http://localhost:8000", + Url = url, Opacity = 0.99 }, GUI = { diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 970af7c6ea..5791e33d1c 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -7,7 +7,7 @@ local browser = { Type = "ScreenSpaceSkyBrowser", Identifier = browserId, Name = "Sky Browser", - Url = "http://localhost:8000/", + Url = "https://data.openspaceproject.com/dist/skybrowser/page/", FaceCamera = false, TargetID = targetId, CartesianPosition = {-1.0, -0.5, -2.1}, diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 10c545b34b..e6ce191015 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -61,6 +61,7 @@ namespace openspace { void setIdInBrowser(std::string id); float fieldOfView() const; std::deque& selectedImages(); + void setImageLayerOrder(int i, int order); protected: diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 92a311bff8..d0a26d7eda 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -36,6 +36,7 @@ namespace openspace { std::deque& selectedImages(); void addSelectedImage(ImageData& image, int i); void removeSelectedImage(ImageData& image, int i); + void setImageLayerOrder(int i, int order); // Translation //void translate(glm::vec2 translation); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index f76c618bde..6055d4a135 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -50,6 +50,7 @@ namespace openspace { ghoul::Dictionary removeImageLayer(const std::string& imageId); ghoul::Dictionary setLayerOpacity(const std::string& imageId, double opacity); ghoul::Dictionary setForegroundOpacity(double val); + ghoul::Dictionary setLayerOrder(const std::string& id, int order); } } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1656d1b2a7..8d9a9b2516 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -233,6 +233,14 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "setImageLayerOrder", + &skybrowser::luascriptfunctions::setImageLayerOrder, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, }; @@ -338,11 +346,11 @@ SkyBrowserModule::SkyBrowserModule() // If mouse is on browser or target, apply zoom if (to_browser(_mouseOnObject)) { - to_browser(_mouseOnObject)->scrollZoom(scroll); + to_browser(_mouseOnObject)->scrollZoom(static_cast(scroll)); return true; } else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { - to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); + to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(static_cast(scroll)); } return false; @@ -521,19 +529,20 @@ bool SkyBrowserModule::browserIdExists(std::string id) { } void SkyBrowserModule::createTargetBrowserPair() { - int noOfPairs = getSkyBrowsers().size() + 1; + int noOfPairs = static_cast(getSkyBrowsers().size()) + 1; std::string nameBrowser = "Sky Browser " + std::to_string(noOfPairs); std::string nameTarget = "Sky Target " + std::to_string(noOfPairs); std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; + std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; const std::string browser = "{" "Identifier = '" + idBrowser + "'," "Type = 'ScreenSpaceSkyBrowser'," "Name = '" + nameBrowser + "'," - "Url = 'http://localhost:8000/'," + "Url = '"+ url +"'," "FaceCamera = false," "TargetID = '" + idTarget + "'," "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," @@ -587,11 +596,6 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { bool hasTarget = browser->getSkyTarget(); if (hasTarget) { targetId = browser->getSkyTarget()->identifier(); - - openspace::global::scriptEngine->queueScript( - "openspace.removeScreenSpaceRenderable('" + targetId + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); } // Remove pointer to the renderable from browsers vector browsers.erase(browserId); @@ -599,22 +603,30 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { // Remove pointer to the renderable from screenspace renderable vector renderables.erase(std::remove_if(std::begin(renderables), std::end(renderables), [&](ScreenSpaceRenderable* renderable) { - bool foundBrowser = renderable->identifier() == browserId; - if (hasTarget) { - bool foundTarget = renderable->identifier() == targetId; - return foundBrowser || foundTarget; + if (renderable->identifier() == browserId) { + return true; + } + else if (renderable->identifier() == targetId) { + return true; } else { - return foundBrowser; - } - })); + return false; + } + }), std::end(renderables)); // Remove from engine openspace::global::scriptEngine->queueScript( "openspace.removeScreenSpaceRenderable('" + browserId + "');", scripting::ScriptEngine::RemoteScripting::Yes ); - - + + if (hasTarget) { + openspace::global::scriptEngine->queueScript( + "openspace.removeScreenSpaceRenderable('" + targetId + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + + _mouseOnObject = nullptr; } void SkyBrowserModule::place3dBrowser(ImageData& image) { diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index c4c5fa8dd8..f85b98afde 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -142,6 +142,30 @@ namespace openspace::skybrowser::luascriptfunctions { } return 0; } + + + int setImageLayerOrder(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); + const std::string browserId = ghoul::lua::value(L, 1); + const int i = ghoul::lua::value(L, 2); + int order = ghoul::lua::value(L, 3); + SkyBrowserModule* module = global::moduleEngine->module(); + ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), order); + + if (module->browserIdExists(browserId)) { + ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; + browser->sendMessageToWWT(message); + browser->setImageLayerOrder(i, order); + } + else if (module->get3dBrowser() != nullptr) { + RenderableSkyBrowser* browser3d = dynamic_cast( + module->get3dBrowser()->renderable()); + browser3d->sendMessageToWWT(message); + browser3d->setImageLayerOrder(i, order); + } + + return 0; + } int loadImagesToWWT(lua_State* L) { // Load images from url @@ -346,9 +370,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Calculate the smallest FOV of vertical and horizontal - float HFOV = global::windowDelegate->getHorizFieldOfView(); - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - float VFOV = HFOV * (windowRatio.y / windowRatio.x); + double HFOV = global::windowDelegate->getHorizFieldOfView(); + glm::dvec2 windowRatio = global::windowDelegate->currentWindowSize(); + double VFOV = HFOV * (windowRatio.y / windowRatio.x); double FOV = std::min(HFOV, VFOV); // Push window data ghoul::lua::push(L, "windowHFOV", FOV); @@ -509,7 +533,6 @@ namespace openspace::skybrowser::luascriptfunctions { const int i = ghoul::lua::value(L, 2); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; ghoul::Dictionary message = wwtmessage::setLayerOpacity(std::to_string(i), opacity); if (module->browserIdExists(browserId)) { diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 13d34f170a..9c1bc9f6f1 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -249,4 +249,13 @@ namespace openspace { return _selectedImages; } + void RenderableSkyBrowser::setImageLayerOrder(int i, int order) { + // Remove from selected list + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it != std::end(_selectedImages)) { + _selectedImages.erase(it); + _selectedImages.insert(std::begin(_selectedImages) + order, i); + } + } + } // namespace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 3c0b8c03cd..abf2aa1016 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -354,4 +354,14 @@ namespace openspace { sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i))); } } + + void ScreenSpaceSkyBrowser::setImageLayerOrder(int i, int order) { + // Remove from selected list + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it != std::end(_selectedImages)) { + _selectedImages.erase(it); + if(_selectedImages.size()) + _selectedImages.insert(std::begin(_selectedImages) + order, i); + } + } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index c297de4280..6dc84bf3e0 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -156,6 +156,9 @@ namespace openspace::wwtmessage { msg.setValue("event", "image_layer_create"s); msg.setValue("id", id); msg.setValue("url", imageUrl); + msg.setValue("mode", "preloaded"s); + msg.setValue("goto", false); + return msg; } @@ -187,6 +190,18 @@ namespace openspace::wwtmessage { return msg; } + + ghoul::Dictionary setLayerOrder(const std::string& id, int order) { + // The lower the layer order, the more towards the back the image is placed + // 0 is the background + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_order"s); + msg.setValue("id", id); + msg.setValue("order", order); + + return msg; + } } From 86fbde2af8f5939155672ca1dad913b7d6508f4c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 9 Jun 2021 09:28:34 +0200 Subject: [PATCH 122/251] Bugfix and better destruction of WWTDataHandler in module --- modules/skybrowser/shaders/target_fs.glsl | 6 +++--- modules/skybrowser/skybrowsermodule.cpp | 5 ++++- modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/src/screenspaceskytarget.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 10e66f13f7..94929fe378 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,4 +1,4 @@ -uniform sampler2D texture1; +uniform sampler2D texture; uniform float borderWidth; uniform vec2 targetDimensions; uniform bool showCrosshair; @@ -34,8 +34,8 @@ Fragment getFragment() { float border_crosshair_bl = step(borderWidth*ratio*4, vs_st.x) * step(borderWidth*ratio*4, (1.0)-vs_st.x); float border_crosshair_tr = step(borderWidth*4, vs_st.y) * step(borderWidth*4, (1.0)-vs_st.y); vec3 crosshair_small = vec3(border_crosshair_bl*border_crosshair_tr); - - vec3 crosshair_inside_border = vec3(crossLine(crosshair_small.x * crosshair_border_linewidth, (vs_st).x) + + vec3 crosshair_inside_border = vec3(crossLine(crosshair_small.x * crosshair_border_linewidth, (vs_st).x) + crossLine(crosshair_small.y * crosshair_border_linewidth, (vs_st).y)); vec3 crosshair_and_border = (1.0 - border) + crosshair_inside_border; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 8d9a9b2516..5a91cfda63 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -474,10 +474,13 @@ SkyBrowserModule::SkyBrowserModule() }); } -void SkyBrowserModule::internalDeinitialize() { +SkyBrowserModule::~SkyBrowserModule() { delete dataHandler; } +void SkyBrowserModule::internalDeinitialize() { +} + void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index a71be0b5ae..756319f7f8 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -55,7 +55,7 @@ public: constexpr static const int FROM_URL = 1; SkyBrowserModule(); - virtual ~SkyBrowserModule() = default; + virtual ~SkyBrowserModule(); glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); void addRenderable(ScreenSpaceRenderable* object); WWTDataHandler* getWWTDataHandler(); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 74043e378a..ec8f0f0841 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -39,7 +39,7 @@ namespace { }; constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture1", "showCrosshair", "showCrosshairInTarget", "borderWidth", "targetDimensions", "borderColor" + "ModelTransform", "ViewProjectionMatrix", "texture", "showCrosshair", "showCrosshairInTarget", "borderWidth", "targetDimensions", "borderColor" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = From 01c393ab8b7e25d97d8d166deee873fef0f08bc9 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 9 Jun 2021 09:56:02 +0200 Subject: [PATCH 123/251] Fix so backend can handle layer ordering --- .../skybrowser/include/renderableskybrowser.h | 2 +- .../include/screenspaceskybrowser.h | 2 +- modules/skybrowser/include/utility.h | 8 +++---- modules/skybrowser/skybrowsermodule.cpp | 7 ++++++ modules/skybrowser/skybrowsermodule.h | 6 +++-- modules/skybrowser/skybrowsermodule_lua.inl | 9 ++++---- .../skybrowser/src/renderableskybrowser.cpp | 22 ++++++++++++++----- .../skybrowser/src/screenspaceskybrowser.cpp | 21 ++++++++++++------ modules/skybrowser/src/utility.cpp | 7 +++--- 9 files changed, 55 insertions(+), 29 deletions(-) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index e6ce191015..d1fabcd9f0 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -61,7 +61,7 @@ namespace openspace { void setIdInBrowser(std::string id); float fieldOfView() const; std::deque& selectedImages(); - void setImageLayerOrder(int i, int order); + void setImageLayerOrder(int i, int order, int version); protected: diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index d0a26d7eda..1d7c54ae98 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -36,7 +36,7 @@ namespace openspace { std::deque& selectedImages(); void addSelectedImage(ImageData& image, int i); void removeSelectedImage(ImageData& image, int i); - void setImageLayerOrder(int i, int order); + void setImageLayerOrder(int i, int order, int version); // Translation //void translate(glm::vec2 translation); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 6055d4a135..f12998a09d 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -46,11 +46,11 @@ namespace openspace { const double fov, const double roll, const bool moveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); - ghoul::Dictionary createImageLayer(const std::string& imageUrl, const std::string& id); - ghoul::Dictionary removeImageLayer(const std::string& imageId); - ghoul::Dictionary setLayerOpacity(const std::string& imageId, double opacity); + ghoul::Dictionary createImageLayer(const std::string& id, const std::string& url); + ghoul::Dictionary removeImageLayer(const std::string& id); + ghoul::Dictionary setLayerOpacity(const std::string& id, double opacity); ghoul::Dictionary setForegroundOpacity(double val); - ghoul::Dictionary setLayerOrder(const std::string& id, int order); + ghoul::Dictionary setLayerOrder(const std::string& id, int order, int version); } } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 5a91cfda63..ecf1160a27 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -256,6 +256,9 @@ SkyBrowserModule::SkyBrowserModule() , resizeVector(0.f, 0.f) , changeViewWithinBrowser(false) , _browser3d(nullptr) + , _layerOrderCounter(0) + , _cameraInSolarSystem(true) + , highlightAddition(35, 35, 35) { global::callback::mousePosition->emplace_back( [&](double x, double y) { @@ -513,6 +516,10 @@ glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mouse return screenSpacePos; } +int SkyBrowserModule::getAndIncrementLayerOrder() { + return _layerOrderCounter++; +} + void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { renderables.push_back(object); // Sort on z coordinate, objects closer to camera are in beginning of list diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 756319f7f8..a193624bf4 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -76,6 +76,7 @@ public: void removeTargetBrowserPair(std::string& browserId); void place3dBrowser(ImageData& image); void lookAt3dBrowser(); + int getAndIncrementLayerOrder(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -116,9 +117,10 @@ protected: bool isRotating = false; // For tracking the currently selected browser std::string selectedBrowser; - glm::ivec3 highlightAddition{ 35, 35, 35 }; + glm::ivec3 highlightAddition; // Mode of browsing - bool _cameraInSolarSystem{ true }; + bool _cameraInSolarSystem; + int _layerOrderCounter; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index f85b98afde..895504eba4 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -150,18 +150,17 @@ namespace openspace::skybrowser::luascriptfunctions { const int i = ghoul::lua::value(L, 2); int order = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), order); + int version = module->getAndIncrementLayerOrder(); if (module->browserIdExists(browserId)) { ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; - browser->sendMessageToWWT(message); - browser->setImageLayerOrder(i, order); + + browser->setImageLayerOrder(i, order, version); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( module->get3dBrowser()->renderable()); - browser3d->sendMessageToWWT(message); - browser3d->setImageLayerOrder(i, order); + browser3d->setImageLayerOrder(i, order, version); } return 0; diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 9c1bc9f6f1..0a8768f9b4 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -197,7 +197,7 @@ namespace openspace { // Push newly selected image to front _selectedImages.push_front(i); // Create image layer and center WWT app on the image - sendMessageToWWT(wwtmessage::createImageLayer(image.imageUrl, std::to_string(i))); + sendMessageToWWT(wwtmessage::createImageLayer(std::to_string(i), image.imageUrl)); LINFO("Image has been loaded to " + identifier()); } } @@ -249,13 +249,23 @@ namespace openspace { return _selectedImages; } - void RenderableSkyBrowser::setImageLayerOrder(int i, int order) { + void RenderableSkyBrowser::setImageLayerOrder(int i, int order, int version) { // Remove from selected list - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it != std::end(_selectedImages)) { - _selectedImages.erase(it); - _selectedImages.insert(std::begin(_selectedImages) + order, i); + auto current = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + auto target = std::begin(_selectedImages) + order; + + // Make sure the image was found in the list + if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { + // Swap the two images + std::iter_swap(current, target); } + + int reverseOrder = _selectedImages.size() - order - 1; + ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), + reverseOrder, version); + sendMessageToWWT(message); } + + } // namespace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index abf2aa1016..89a0fd4ccb 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -341,7 +341,7 @@ namespace openspace { // Push newly selected image to front _selectedImages.push_front(i); // Index of image is used as layer ID as it is unique in the image data set - sendMessageToWWT(wwtmessage::createImageLayer(image.imageUrl, std::to_string(i))); + sendMessageToWWT(wwtmessage::createImageLayer(std::to_string(i), image.imageUrl)); sendMessageToWWT(wwtmessage::setLayerOpacity(std::to_string(i), 1.0)); } } @@ -355,13 +355,20 @@ namespace openspace { } } - void ScreenSpaceSkyBrowser::setImageLayerOrder(int i, int order) { + void ScreenSpaceSkyBrowser::setImageLayerOrder(int i, int order, int version) { // Remove from selected list - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it != std::end(_selectedImages)) { - _selectedImages.erase(it); - if(_selectedImages.size()) - _selectedImages.insert(std::begin(_selectedImages) + order, i); + auto current = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + auto target = std::begin(_selectedImages) + order; + + // Make sure the image was found in the list + if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { + // Swap the two images + std::iter_swap(current, target); } + + int reverseOrder = _selectedImages.size() - order - 1; + ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), + reverseOrder, version); + sendMessageToWWT(message); } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 6dc84bf3e0..6849559b0a 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -150,12 +150,12 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary createImageLayer(const std::string& imageUrl, const std::string& id) { + ghoul::Dictionary createImageLayer(const std::string& id, const std::string& url) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_create"s); msg.setValue("id", id); - msg.setValue("url", imageUrl); + msg.setValue("url", url); msg.setValue("mode", "preloaded"s); msg.setValue("goto", false); @@ -191,7 +191,7 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary setLayerOrder(const std::string& id, int order) { + ghoul::Dictionary setLayerOrder(const std::string& id, int order, int version) { // The lower the layer order, the more towards the back the image is placed // 0 is the background using namespace std::string_literals; @@ -199,6 +199,7 @@ namespace openspace::wwtmessage { msg.setValue("event", "image_layer_order"s); msg.setValue("id", id); msg.setValue("order", order); + msg.setValue("version", version); return msg; } From d85159d2439ad67f437dd3b2ff99bc785973f21e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 9 Jun 2021 16:36:49 +0200 Subject: [PATCH 124/251] Make OpenSpace use the GUI without using the developers GUI --- data/assets/customization/gui.asset | 2 +- data/assets/util/webgui.asset | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/assets/customization/gui.asset b/data/assets/customization/gui.asset index 6a43444b0a..e18cd44a7f 100644 --- a/data/assets/customization/gui.asset +++ b/data/assets/customization/gui.asset @@ -1,4 +1,4 @@ -asset.export("webguiDevelopmentMode", true) +asset.export("webguiDevelopmentMode", false) -- To make changes to the webgui: diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 9be28c5d6f..12b22c1095 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "391f8d3ed74e598a0e8a1b16016324d8f747e18d" +local frontendHash = "55adb23d5f564e407b8778101ab52bf9b1d79149" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ @@ -66,7 +66,7 @@ asset.onDeinitialize(function () end end -- @TODO(maci, 2019-08-23) setting this value on exit was causing the server to restart - -- on macos, which in turn, stopped the application from exiting. + -- on macos, which in turn, stopped the application from exiting. -- need to address in webguimodule.cpp --openspace.setPropertyValueSingle("Modules.WebGui.Directories", newDirectories) end) From c63ee2d4171799b4ceadb47408f4ade75273f83a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 1 Sep 2021 13:57:19 +0200 Subject: [PATCH 125/251] Master thesis work done --- data/assets/skyBrowserTargetPair.asset | 8 ++- modules/skybrowser/skybrowsermodule.cpp | 8 ++- .../skybrowser/src/renderableskybrowser.cpp | 30 ++++++----- .../skybrowser/src/screenspaceskybrowser.cpp | 20 ++++--- .../skybrowser/src/screenspaceskytarget.cpp | 52 ++++++++++++------- 5 files changed, 72 insertions(+), 46 deletions(-) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 5791e33d1c..6c0d6e33eb 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -2,17 +2,17 @@ local assetHelper = asset.require('util/asset_helper') local targetId= "SkyTarget0" local browserId = "SkyBrowser0" +local serverUrl = "https://data.openspaceproject.com/dist/skybrowser/page/" +--local localHostUrl = "http://localhost:8000" local browser = { Type = "ScreenSpaceSkyBrowser", Identifier = browserId, Name = "Sky Browser", - Url = "https://data.openspaceproject.com/dist/skybrowser/page/", + Url = serverUrl, FaceCamera = false, TargetID = targetId, CartesianPosition = {-1.0, -0.5, -2.1}, - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome }; local target = { @@ -21,8 +21,6 @@ local target = { Name = "Sky Target", FaceCamera = false, BrowserID = browserId, - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome }; asset.onInitialize(function () diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index ecf1160a27..1fe951b0a8 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -547,6 +547,7 @@ void SkyBrowserModule::createTargetBrowserPair() { glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; + //std::string localHostUrl = "http://localhost:8000"; const std::string browser = "{" "Identifier = '" + idBrowser + "'," @@ -594,6 +595,11 @@ void SkyBrowserModule::createTargetBrowserPair() { "openspace.skybrowser.connectBrowserTarget('" + idTarget + "');", scripting::ScriptEngine::RemoteScripting::Yes ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); } void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { @@ -751,8 +757,6 @@ void SkyBrowserModule::rotateCamera(double deltaTime) { double rotationAngle = smallestAngle * deltaTime; // Create the rotation matrix for local camera space glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsToAnimateTo)); - glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(rotationAxis, 1.0); glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); // Rotate global::navigationHandler->camera()->rotate(glm::quat_cast(rotmat)); diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 0a8768f9b4..a284c25a43 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -69,7 +69,7 @@ namespace openspace { , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) , _reload(ReloadInfo) , _fov(70.f) - , _connectToWwt(true) + , _connectToWwt(false) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -221,20 +221,24 @@ namespace openspace { } void RenderableSkyBrowser::connectToWwt() { + // If the camera is already synced, the browser is already initialized + if (!_connectToWwt) { + _connectToWwt = true; + // Start a thread to enable user interaction while sending the calls to WWT + _threadWwtMessages = std::thread([&] { + while (_connectToWwt) { - // Start a thread to enable user interaction while sending the calls to WWT - _threadWwtMessages = std::thread([&] { - while (_connectToWwt) { + glm::dvec2 aim{ 0.0 }; + // Send a message just to establish contact + ghoul::Dictionary message = wwtmessage::moveCamera(aim, _fov, 0.0); + sendMessageToWWT(message); - glm::dvec2 aim { 0.0 }; - // Send a message just to establish contact - ghoul::Dictionary message = wwtmessage::moveCamera(aim, _fov, 0.0); - sendMessageToWWT(message); - - // Sleep so we don't bombard WWT with too many messages - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } - }); + // Sleep so we don't bombard WWT with too many messages + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + }); + } + } void RenderableSkyBrowser::stopConnectingToWwt() { diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 89a0fd4ccb..d83e881db3 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -79,7 +79,7 @@ namespace openspace { , _vfieldOfView(ZoomInfo, 10.f, 0.1f, 70.f) , _borderColor(BorderColorInfo, glm::ivec3(rand() % 256, rand() % 256, rand() % 256)) , _skyTargetID(TargetIDInfo) - , _camIsSyncedWWT(true) + , _camIsSyncedWWT(false) , _skyTarget(nullptr) { // Ensure the color of the border is bright enough. @@ -156,12 +156,18 @@ namespace openspace { } void ScreenSpaceSkyBrowser::initializeBrowser() { - // Set border color - setBorderColor(_borderColor.value()); - // Connect to target - setConnectedTarget(); - // Track target - WWTfollowCamera(); + // If the camera is already synced, the browser is already initialized + if (!_camIsSyncedWWT) { + _camIsSyncedWWT = true; + // Set border color + setBorderColor(_borderColor.value()); + // Connect to target if they haven't been connected + if (!_skyTarget) { + setConnectedTarget(); + } + // Track target + WWTfollowCamera(); + } } bool ScreenSpaceSkyBrowser::deinitializeGL() { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index ec8f0f0841..c28679d27a 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -39,7 +39,8 @@ namespace { }; constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture", "showCrosshair", "showCrosshairInTarget", "borderWidth", "targetDimensions", "borderColor" + "ModelTransform", "ViewProjectionMatrix", "texture", "showCrosshair", + "showCrosshairInTarget", "borderWidth", "targetDimensions", "borderColor" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = @@ -75,7 +76,8 @@ namespace { namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) + , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), + glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) , _showCrosshairThreshold(CrosshairThresholdInfo, 0.6f, 0.1f, 70.f) , _borderColor(220, 220, 220) @@ -106,7 +108,10 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - _cartesianPosition.setValue(glm::dvec3(_cartesianPosition.value().x, _cartesianPosition.value().y, skybrowser::SCREENSPACE_Z)); + glm::dvec3 startPos{ _cartesianPosition.value().x, _cartesianPosition.value().y, + skybrowser::SCREENSPACE_Z }; + + _cartesianPosition.setValue(startPos); //_useRadiusAzimuthElevation.setValue(true); // Always make sure that the target and browser are visible together @@ -131,7 +136,9 @@ namespace openspace { } bool ScreenSpaceSkyTarget::setConnectedBrowser() { - _skyBrowser = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + ScreenSpaceRenderable* browser = global::renderEngine->screenSpaceRenderable( + _skyBrowserID.value()); + _skyBrowser = dynamic_cast(browser); return _skyBrowser; } @@ -178,8 +185,7 @@ namespace openspace { // The _scale us how much of the windows height the // browser covers: eg a browser that covers 0.25 of the // height of the window will have scale = 0.25 - float textureRatio = - static_cast(_targetDimensions.value().x) / static_cast(_targetDimensions.value().y); + float textureRatio = _targetDimensions.value().x / _targetDimensions.value().y; glm::mat4 scale = glm::scale( glm::mat4(1.f), @@ -221,19 +227,27 @@ namespace openspace { glDisable(GL_CULL_FACE); - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * + localRotationMatrix() * scaleMatrix(); float borderWidth = 0.0016f/_scale.value(); - float showCrosshairInTargetThreshold = 2.f; // show crosshair and target when browser FOV < 2 degrees + glm::vec2 targetDim; - bool showCrosshair; - bool showCrosshairInTarget; - _targetDimensions.value() == glm::vec2(0) ? targetDim = glm::vec2(1) : targetDim = _targetDimensions.value(); + if(_targetDimensions.value() == glm::vec2(0)) { + targetDim = glm::vec2(1); + } + else { + targetDim = _targetDimensions.value(); + } _shader->activate(); - _fieldOfView < showCrosshairInTargetThreshold && _fieldOfView > _showCrosshairThreshold ? showCrosshairInTarget = true : showCrosshairInTarget = false; - _fieldOfView < _showCrosshairThreshold ? showCrosshair = true : showCrosshair = false; - - _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); + // Show crosshair and target when browser FOV < 2 degrees + float showCrosshairInTargetThreshold = 2.f; + bool showOnlyCrosshair; + bool showCrosshairInTarget; + showOnlyCrosshair = _fieldOfView < _showCrosshairThreshold; + showCrosshairInTarget = _fieldOfView < showCrosshairInTargetThreshold && !showOnlyCrosshair; + + _shader->setUniform(_uniformCache.showCrosshair, showOnlyCrosshair); _shader->setUniform(_uniformCache.showCrosshairInTarget, showCrosshairInTarget); _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetDimensions, targetDim); @@ -291,9 +305,9 @@ namespace openspace { glm::dvec3 ScreenSpaceSkyTarget::getTargetDirectionGalactic() { // Get camera view direction and orthogonal coordinate system of camera view direction glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 targetPosWorldSpace = glm::inverse(global::navigationHandler->camera()->combinedViewMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0); - glm::dvec3 targetDirection = glm::normalize(targetPosWorldSpace - camPos); - + //glm::dvec3 targetPosWorldSpace = glm::inverse(global::navigationHandler->camera()->combinedViewMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0); + //glm::dvec3 targetDirection = glm::normalize(targetPosWorldSpace - camPos); + glm::dvec3 targetDirection = glm::normalize(glm::inverse(global::navigationHandler->camera()->viewRotationMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0)); return targetDirection; } @@ -402,7 +416,7 @@ namespace openspace { void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd, bool lockAfterwards) { // Save the Cartesian celestial coordinates for animation - // to make sure wrap around works + // The coordinates are Cartesian to avoid wrap-around issues _coordsToAnimateTo = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd)); _coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian( getTargetDirectionCelestial())); From 7be40f3bc8b9e6bcae06f13f8610393000bb2bfe Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 6 Sep 2021 09:07:26 +0200 Subject: [PATCH 126/251] Cleaned up shader code --- .../skybrowser/include/screenspaceskytarget.h | 4 +- modules/skybrowser/shaders/target_fs.glsl | 106 ++++++++++-------- .../skybrowser/src/screenspaceskytarget.cpp | 33 ++++-- 3 files changed, 84 insertions(+), 59 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 54bc91d1a0..b3bd0d6ee5 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -63,9 +63,11 @@ namespace openspace { properties::Vec2Property _targetDimensions; properties::FloatProperty _showCrosshairThreshold; + properties::FloatProperty _showRectangleThreshold; + std::unique_ptr _texture; - UniformCache(modelTransform, viewProj, texture, showCrosshair, showCrosshairInTarget, borderWidth, targetDimensions, borderColor) _uniformCache; + UniformCache(modelTransform, viewProj, texture, showCrosshair, showRectangle, borderWidth, targetDimensions, borderColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; float _fieldOfView = 100.f; diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 94929fe378..bc595e4f75 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -2,69 +2,83 @@ uniform sampler2D texture; uniform float borderWidth; uniform vec2 targetDimensions; uniform bool showCrosshair; -uniform bool showCrosshairInTarget; +uniform bool showRectangle; uniform vec4 borderColor; - in vec2 vs_st; in vec4 vs_position; +// A factor which states how much thicker vertical lines are rendered than horizontal +// This compensates for the optical illusion that vertical lines appear thinner +#define VERTICAL_THICKNESS 1.15f -float crossLine(in float _width, in float _coord) { - float center = 0.5f; - float line = smoothstep(center, center+(_width/2), _coord) - - smoothstep(center-(_width/2), center, _coord); - return line; +float line(in float _lineCenter, in float _lineWidth, in float _coord) { + // Calculate edges of line + float start_edge = _lineCenter - (_lineWidth * 0.5f); + float end_edge = _lineCenter + (_lineWidth * 0.5f); + + // Create line + float line = step(start_edge, _coord) - step(end_edge, _coord); + + return line; +} + +float rectangle(in float _linewidth_y, in float _ratio, in vec2 _coord) { + // Calculate the widths and centers for the lines + float linewidth_x = _linewidth_y * _ratio * VERTICAL_THICKNESS; + float linecenter_x = linewidth_x * 0.5f; + float linecenter_y = _linewidth_y * 0.5f; + + // Create the four lines for the rectangle + float l = line(linecenter_x, linewidth_x, _coord.x); + float r = line(1.0f - linecenter_x, linewidth_x, _coord.x); + float b = line(linecenter_y, _linewidth_y, _coord.y); + float t = line(1.0f - linecenter_y, _linewidth_y, _coord.y); + + // Add all lines together + return l + r + b + t; +} + +float crosshair(in float _linewidth, in float _ratio, in vec2 _coord) { + float center = 0.5f; + float crosshair_vertical = line(center, _linewidth * _ratio * VERTICAL_THICKNESS, _coord.x); + float crosshair_horizontal = line(center, _linewidth, _coord.y); + + return crosshair_horizontal + crosshair_vertical; +} + +float filledRectangle(in float _size, in float _ratio, in vec2 _coord) { + float center = 0.5f; + float horizontal = line(center, _size, _coord.y); + float vertical = line(center, _size, _coord.x); + + return horizontal * vertical; } #include "fragment.glsl" Fragment getFragment() { - Fragment frag; - - float ratio = targetDimensions.y / targetDimensions.x; - - // draw square border - float border_bl = step(borderWidth*ratio, vs_st.x) * step(borderWidth*ratio, (1.0)-vs_st.x); - float border_tr = step(borderWidth, vs_st.y) * step(borderWidth, (1.0)-vs_st.y); - vec3 border = vec3(border_bl*border_tr); - - // draw crosshair inside square border - float crosshair_border_linewidth = 0.06f; - float border_crosshair_bl = step(borderWidth*ratio*4, vs_st.x) * step(borderWidth*ratio*4, (1.0)-vs_st.x); - float border_crosshair_tr = step(borderWidth*4, vs_st.y) * step(borderWidth*4, (1.0)-vs_st.y); - vec3 crosshair_small = vec3(border_crosshair_bl*border_crosshair_tr); - - vec3 crosshair_inside_border = vec3(crossLine(crosshair_small.x * crosshair_border_linewidth, (vs_st).x) - + crossLine(crosshair_small.y * crosshair_border_linewidth, (vs_st).y)); - vec3 crosshair_and_border = (1.0 - border) + crosshair_inside_border; - - // draw crosshair - float crosshair_linewidth = 0.14f; - vec3 crosshair = vec3(crossLine(crosshair_linewidth*ratio*1.1, vs_st.x) + crossLine(crosshair_linewidth, vs_st.y)); - - // show crosshair or border or both - frag.color = vec4(1,1,1,1); - frag.color.rgba = vec4(borderColor); + float _ratio = targetDimensions.y / targetDimensions.x; + float _crosshair = 0.0f; + float _rectangle = 0.0f; if(showCrosshair) { - frag.color.rgba = vec4(borderColor); - if(crosshair == vec3(0.0)) { - frag.color.a = 0.0; - } + _crosshair = crosshair(borderWidth, _ratio, vs_st); } - else if(showCrosshairInTarget) { - frag.color.rgba = vec4(borderColor); - if(crosshair_and_border == vec3(0.0)) { - frag.color.a = 0.0; - } + if(showRectangle) { + _rectangle = rectangle(borderWidth, _ratio, vs_st); } - else { - if(border == vec3(1.0)) { - frag.color.a = 0.0; - } + + // If both rectangle and crosshair are displayed, draw crosshair a bit smaller + if(showCrosshair && showRectangle) { + _crosshair *= filledRectangle(borderWidth * 7.0f, _ratio, vs_st); } + float result = clamp(_crosshair + _rectangle, 0.0, 1.0); + + Fragment frag; + frag.color = vec4(vec3(borderColor), result); + return frag; } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index c28679d27a..38251796ad 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -40,7 +40,7 @@ namespace { constexpr const std::array UniformNames = { "ModelTransform", "ViewProjectionMatrix", "texture", "showCrosshair", - "showCrosshairInTarget", "borderWidth", "targetDimensions", "borderColor" + "showRectangle", "borderWidth", "targetDimensions", "borderColor" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = @@ -55,6 +55,13 @@ namespace { "CrosshairThreshold", "Crosshair Threshold Info", "tjobidabidobidabidopp plupp" + }; + + constexpr const openspace::properties::Property::PropertyInfo RectangleThresholdInfo = + { + "RectangleThreshold", + "Rectangle Threshold Info", + "tjobidabidobidabidopp plupp" }; struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { @@ -67,6 +74,9 @@ namespace { // [[codegen::verbatim(CrosshairThresholdInfo.description)]] std::optional crosshairThreshold; + + // [[codegen::verbatim(RectangleThresholdInfo.description)]] + std::optional rectangleThreshold; }; #include "screenspaceskytarget_codegen.cpp" @@ -79,7 +89,8 @@ namespace openspace { , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) - , _showCrosshairThreshold(CrosshairThresholdInfo, 0.6f, 0.1f, 70.f) + , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) + , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) , _borderColor(220, 220, 220) , _skyBrowser(nullptr) { @@ -88,10 +99,12 @@ namespace openspace { _targetDimensions = p.targetDimensions.value_or(_targetDimensions); _skyBrowserID = p.browserID.value_or(_skyBrowserID); _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); + _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); addProperty(_targetDimensions); addProperty(_skyBrowserID); addProperty(_showCrosshairThreshold); + addProperty(_showRectangleThreshold); _skyBrowserID.onChange([&]() { setConnectedBrowser(); @@ -240,15 +253,11 @@ namespace openspace { } _shader->activate(); - // Show crosshair and target when browser FOV < 2 degrees - float showCrosshairInTargetThreshold = 2.f; - bool showOnlyCrosshair; - bool showCrosshairInTarget; - showOnlyCrosshair = _fieldOfView < _showCrosshairThreshold; - showCrosshairInTarget = _fieldOfView < showCrosshairInTargetThreshold && !showOnlyCrosshair; - - _shader->setUniform(_uniformCache.showCrosshair, showOnlyCrosshair); - _shader->setUniform(_uniformCache.showCrosshairInTarget, showCrosshairInTarget); + bool showCrosshair = _fieldOfView < _showCrosshairThreshold; + bool showRect = _fieldOfView > _showRectangleThreshold; + + _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); + _shader->setUniform(_uniformCache.showRectangle, showRect); _shader->setUniform(_uniformCache.borderWidth, borderWidth); _shader->setUniform(_uniformCache.targetDimensions, targetDim); _shader->setUniform(_uniformCache.modelTransform, modelTransform); @@ -316,7 +325,7 @@ namespace openspace { glm::ivec2 windowRatio = global::windowDelegate->currentWindowSize(); float verticFOV = horizFOV * (static_cast(windowRatio.y) / static_cast(windowRatio.x)); - _scale = std::max((VFOV / verticFOV),(_showCrosshairThreshold.value()/ verticFOV)); + _scale = std::max((VFOV / verticFOV),(_showRectangleThreshold.value()/ verticFOV)); _fieldOfView = VFOV; } From 8b3c792f14320785bec14c999074cfe55ba081de Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 6 Sep 2021 14:42:37 +0200 Subject: [PATCH 127/251] Remove unnecessary texture --- .../skybrowser/include/screenspaceskytarget.h | 68 +++--- modules/skybrowser/shaders/target_fs.glsl | 18 +- modules/skybrowser/shaders/target_vs.glsl | 6 +- modules/skybrowser/skybrowsermodule.cpp | 4 +- modules/skybrowser/square.png | Bin 409 -> 0 bytes .../skybrowser/src/screenspaceskybrowser.cpp | 2 +- .../skybrowser/src/screenspaceskytarget.cpp | 229 ++++++------------ modules/skybrowser/target.png | Bin 2506 -> 0 bytes 8 files changed, 118 insertions(+), 209 deletions(-) delete mode 100644 modules/skybrowser/square.png delete mode 100644 modules/skybrowser/target.png diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index b3bd0d6ee5..feac775cb3 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -25,66 +25,58 @@ namespace openspace { bool initializeGL() override; bool isReady() const override; void render() override; + glm::mat4 scaleMatrix() override; + void bindTexture() override; // Empty function but has to be defined + void createShaders(); - void initializeWithBrowser(); - - void setBrowser(ScreenSpaceSkyBrowser* browser); ScreenSpaceSkyBrowser* getSkyBrowser(); - - void setDimensions(glm::vec2 currentBrowserDimensions); - void updateFOV(float browserFOV); - - glm::dvec3 getTargetDirectionGalactic(); - glm::dvec2 getScreenSpacePosition(); - bool setConnectedBrowser(); - void setBorderColor(glm::ivec3 color); + + void setVerticalFOV(float VFOV); + void setDimensions(glm::vec2 dimensions); + void setColor(glm::ivec3 color); glm::ivec3 getColor(); properties::FloatProperty& getOpacity(); - glm::dvec2 getScreenSpaceDimensions(); - glm::dvec2 getUpperRightCornerScreenSpace(); - glm::dvec2 getLowerLeftCornerScreenSpace(); - bool coordIsInsideCornersScreenSpace(glm::dvec2 coord); + // Target directions + glm::dvec3 getTargetDirectionGalactic(); glm::dvec2 getTargetDirectionCelestial(); + + // Locking functionality void unlock(); void lock(); bool isLocked(); - void animateToCoord(double deltaTime); - void startAnimation(glm::dvec2 coordsEnd, float FOVEnd, bool lockAfterwards = true); - bool animateFOV(float endFOV, float deltaTime); - - glm::mat4 scaleMatrix() override; - void bindTexture() override; - properties::StringProperty _skyBrowserID; + // Animations + void startAnimation(glm::dvec2 coordsEnd, float FOVEnd, bool lockAfterwards = true); + void animateToCoord(double deltaTime); + bool animateToFOV(float endFOV, float deltaTime); - private: - - properties::Vec2Property _targetDimensions; + properties::StringProperty _skyBrowserID; properties::FloatProperty _showCrosshairThreshold; properties::FloatProperty _showRectangleThreshold; - std::unique_ptr _texture; - - UniformCache(modelTransform, viewProj, texture, showCrosshair, showRectangle, borderWidth, targetDimensions, borderColor) _uniformCache; + private: + // Shader + UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, dimensions, lineColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; - float _fieldOfView = 100.f; + glm::ivec3 _color; + float _verticalFOV = 100.f; ScreenSpaceSkyBrowser* _skyBrowser; - glm::ivec3 _borderColor; + // Locking target to a coordinate on the sky bool _isLocked; - glm::dvec2 lockedCelestialCoords; + glm::dvec2 _lockedCoords; // Spherical celestial coords std::thread _lockTargetThread; + // Animating the target - bool isAnimated = false; - // Cartesian celestial coords - glm::dvec3 _coordsToAnimateTo; - glm::dvec3 _coordsStartAnimation; - double animationTime = 1.0; - float FOVToAnimateTo; - bool _lockAfterwards; + bool _isAnimated = false; + glm::dvec3 _coordsEndAnimation; // Cartesian celestial coords + glm::dvec3 _coordsStartAnimation; // Cartesian celestial coords + double _animationTime = 1.0; + float _FOVEndAnimation; + bool _lockAfterAnimation; }; } diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index bc595e4f75..fea8daa875 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,9 +1,8 @@ -uniform sampler2D texture; -uniform float borderWidth; -uniform vec2 targetDimensions; +uniform float lineWidth; +uniform vec2 dimensions; uniform bool showCrosshair; uniform bool showRectangle; -uniform vec4 borderColor; +uniform vec4 lineColor; in vec2 vs_st; in vec4 vs_position; @@ -58,27 +57,28 @@ float filledRectangle(in float _size, in float _ratio, in vec2 _coord) { #include "fragment.glsl" Fragment getFragment() { - float _ratio = targetDimensions.y / targetDimensions.x; + float _ratio = dimensions.y / dimensions.x; float _crosshair = 0.0f; float _rectangle = 0.0f; if(showCrosshair) { - _crosshair = crosshair(borderWidth, _ratio, vs_st); + _crosshair = crosshair(lineWidth, _ratio, vs_st); } if(showRectangle) { - _rectangle = rectangle(borderWidth, _ratio, vs_st); + _rectangle = rectangle(lineWidth, _ratio, vs_st); } // If both rectangle and crosshair are displayed, draw crosshair a bit smaller if(showCrosshair && showRectangle) { - _crosshair *= filledRectangle(borderWidth * 7.0f, _ratio, vs_st); + _crosshair *= filledRectangle(lineWidth * 7.0f, _ratio, vs_st); } float result = clamp(_crosshair + _rectangle, 0.0, 1.0); Fragment frag; - frag.color = vec4(vec3(borderColor), result); + frag.color = lineColor; + frag.color.a *= result; return frag; } diff --git a/modules/skybrowser/shaders/target_vs.glsl b/modules/skybrowser/shaders/target_vs.glsl index ab1eb58a10..c1d2e7c618 100644 --- a/modules/skybrowser/shaders/target_vs.glsl +++ b/modules/skybrowser/shaders/target_vs.glsl @@ -1,7 +1,7 @@ #version __CONTEXT__ -uniform mat4 ModelTransform; -uniform mat4 ViewProjectionMatrix; +uniform mat4 modelTransform; +uniform mat4 viewProj; layout(location = 0) in vec4 in_position; layout(location = 1) in vec2 in_st; @@ -11,6 +11,6 @@ out vec4 vs_position; void main(){ vs_st = in_st; - vs_position = ViewProjectionMatrix * ModelTransform * in_position; + vs_position = viewProj * modelTransform * in_position; gl_Position = vec4(vs_position); } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1fe951b0a8..051279182a 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -328,7 +328,7 @@ SkyBrowserModule::SkyBrowserModule() to_browser(lastObj)->setBorderColor(to_browser(lastObj)->getColor() - highlightAddition); } else if (to_target(lastObj)) { - to_target(lastObj)->setBorderColor(to_target(lastObj)->getColor() - highlightAddition); + to_target(lastObj)->setColor(to_target(lastObj)->getColor() - highlightAddition); } // Add highlight @@ -336,7 +336,7 @@ SkyBrowserModule::SkyBrowserModule() to_browser(_mouseOnObject)->setBorderColor(to_browser(_mouseOnObject)->getColor() + highlightAddition); } else if (to_target(_mouseOnObject)) { - to_target(_mouseOnObject)->setBorderColor(to_target(_mouseOnObject)->getColor() + highlightAddition); + to_target(_mouseOnObject)->setColor(to_target(_mouseOnObject)->getColor() + highlightAddition); } } diff --git a/modules/skybrowser/square.png b/modules/skybrowser/square.png deleted file mode 100644 index 79838c1580d5b058ada4b58bc3bffb209e8948cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRdwrjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4SJp~jv*CsZ!a1$GAQsI*w9#i{_#QQdCyih z%)2|+;=8#A^9HsA-UCt%rVQB(*BI6?MvPnm)6WbEY0Q76ANP3ygOkD2)z4*}Q$iB} DfoFKK diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index d83e881db3..6d42f2fa09 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -113,7 +113,7 @@ namespace openspace { _vfieldOfView.onChange([&]() { if (_skyTarget) { - _skyTarget->updateFOV(_vfieldOfView); + _skyTarget->setVerticalFOV(_vfieldOfView); } }); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 38251796ad..2bb5fa5261 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -13,14 +13,10 @@ #include #include #include -#include #include -#include -#include #include #include #include -#include #include #include #include @@ -31,44 +27,36 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; - constexpr const openspace::properties::Property::PropertyInfo TargetDimensionInfo = - { - "TargetDimensions", - "Target Dimensions Info", - "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " - }; - - constexpr const std::array UniformNames = { - "ModelTransform", "ViewProjectionMatrix", "texture", "showCrosshair", - "showRectangle", "borderWidth", "targetDimensions", "borderColor" + constexpr const std::array UniformNames = { + "modelTransform", "viewProj", "showCrosshair", "showRectangle", "lineWidth", + "dimensions", "lineColor" }; constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = { "BrowserID", - "Browser Info", - "tjobidabidobidabidopp plupp" + "Browser Identifier", + "The identifier of the corresponding sky browser." }; constexpr const openspace::properties::Property::PropertyInfo CrosshairThresholdInfo = { "CrosshairThreshold", - "Crosshair Threshold Info", - "tjobidabidobidabidopp plupp" + "Crosshair Threshold", + "When the field of view is smaller than the crosshair threshold, a crosshair will" + "be rendered in the target." }; constexpr const openspace::properties::Property::PropertyInfo RectangleThresholdInfo = { "RectangleThreshold", - "Rectangle Threshold Info", - "tjobidabidobidabidopp plupp" + "Rectangle Threshold", + "When the field of view is larger than the rectangle threshold, a rectangle will" + "be rendered in the target." }; struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { - // [[codegen::verbatim(TargetDimensionInfo.description)]] - std::optional targetDimensions; - // [[codegen::verbatim(BrowserIDInfo.description)]] std::optional browserID; @@ -86,31 +74,35 @@ namespace { namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _targetDimensions(TargetDimensionInfo, glm::ivec2(1000.f), glm::ivec2(0.f), - glm::ivec2(6000.f)) , _skyBrowserID(BrowserIDInfo) + , _skyBrowser(nullptr) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) - , _borderColor(220, 220, 220) - , _skyBrowser(nullptr) + , _color(220, 220, 220) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _targetDimensions = p.targetDimensions.value_or(_targetDimensions); _skyBrowserID = p.browserID.value_or(_skyBrowserID); _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); - - addProperty(_targetDimensions); + addProperty(_skyBrowserID); addProperty(_showCrosshairThreshold); addProperty(_showRectangleThreshold); + // If the ID changes for the corresponding browser, update _skyBrowserID.onChange([&]() { - setConnectedBrowser(); + initializeWithBrowser(); }); + // Always make sure that the target and browser are visible together + _enabled.onChange([&]() { + if (_skyBrowser) { + _skyBrowser->property("Enabled")->set(_enabled.value()); + } + }); + // Set a unique identifier std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -121,19 +113,11 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); + // Set the position to screen space z glm::dvec3 startPos{ _cartesianPosition.value().x, _cartesianPosition.value().y, skybrowser::SCREENSPACE_Z }; _cartesianPosition.setValue(startPos); - //_useRadiusAzimuthElevation.setValue(true); - - // Always make sure that the target and browser are visible together - _enabled.onChange([&]() { - if (_skyBrowser) { - _skyBrowser->property("Enabled")->set(_enabled.value()); - } - }); - } ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { @@ -142,24 +126,18 @@ namespace openspace { } } + // Pure virtual in the screen space renderable class and hence must be defined void ScreenSpaceSkyTarget::bindTexture() { - if (_texture) { - _texture->bind(); - } - } - bool ScreenSpaceSkyTarget::setConnectedBrowser() { - ScreenSpaceRenderable* browser = global::renderEngine->screenSpaceRenderable( - _skyBrowserID.value()); - _skyBrowser = dynamic_cast(browser); - return _skyBrowser; } void ScreenSpaceSkyTarget::initializeWithBrowser() { + _skyBrowser = dynamic_cast( + global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); if (_skyBrowser) { - _borderColor = _skyBrowser->getColor(); - updateFOV(_skyBrowser->_vfieldOfView.value()); - _targetDimensions = _skyBrowser->getBrowserPixelDimensions(); + _color = _skyBrowser->getColor(); + _objectSize = _skyBrowser->getBrowserPixelDimensions(); + setVerticalFOV(_skyBrowser->_vfieldOfView.value()); } } @@ -171,23 +149,6 @@ namespace openspace { glGenVertexArrays(1, &_vertexArray); glGenBuffers(1, &_vertexBuffer); - - std::unique_ptr texture = ghoul::io::TextureReader::ref().loadTexture(absPath("${MODULE_SKYBROWSER}/square.png")); - - - if (texture) { - // Images don't need to start on 4-byte boundaries, for example if the - // image is only RGB - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); - texture->purgeFromRAM(); - - _texture = std::move(texture); - _objectSize = _texture->dimensions(); - } - createShaders(); return isReady(); @@ -195,15 +156,16 @@ namespace openspace { glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { // To ensure the plane has the right ratio - // The _scale us how much of the windows height the - // browser covers: eg a browser that covers 0.25 of the - // height of the window will have scale = 0.25 - float textureRatio = _targetDimensions.value().x / _targetDimensions.value().y; + // The _scale us how much of the windows height the browser covers: eg a browser + // that covers 0.25 of the height of the window will have scale = 0.25 + float ratio = static_cast(_objectSize.x) / + static_cast(_objectSize.y); glm::mat4 scale = glm::scale( glm::mat4(1.f), - glm::vec3(textureRatio * _scale, _scale, 1.f) + glm::vec3(ratio * _scale, _scale, 1.f) ); + return scale; } @@ -220,16 +182,12 @@ namespace openspace { } - void ScreenSpaceSkyTarget::setBorderColor(glm::ivec3 color) { - _borderColor = color; + void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) { + _color = color; } glm::ivec3 ScreenSpaceSkyTarget::getColor() { - return _borderColor; - } - - void ScreenSpaceSkyTarget::setBrowser(ScreenSpaceSkyBrowser* browser) { - _skyBrowser = browser; + return _color; } ScreenSpaceSkyBrowser* ScreenSpaceSkyTarget::getSkyBrowser() { @@ -242,92 +200,53 @@ namespace openspace { glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float borderWidth = 0.0016f/_scale.value(); + float lineWidth = 0.0016f/_scale.value(); - glm::vec2 targetDim; - if(_targetDimensions.value() == glm::vec2(0)) { - targetDim = glm::vec2(1); - } - else { - targetDim = _targetDimensions.value(); - } _shader->activate(); - bool showCrosshair = _fieldOfView < _showCrosshairThreshold; - bool showRect = _fieldOfView > _showRectangleThreshold; + bool showCrosshair = _verticalFOV < _showCrosshairThreshold; + bool showRect = _verticalFOV > _showRectangleThreshold; + glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() }; _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); _shader->setUniform(_uniformCache.showRectangle, showRect); - _shader->setUniform(_uniformCache.borderWidth, borderWidth); - _shader->setUniform(_uniformCache.targetDimensions, targetDim); + _shader->setUniform(_uniformCache.lineWidth, lineWidth); + _shader->setUniform(_uniformCache.dimensions, glm::vec2(_objectSize)); _shader->setUniform(_uniformCache.modelTransform, modelTransform); - glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; - _shader->setUniform(_uniformCache.borderColor, color); - + _shader->setUniform(_uniformCache.lineColor, color); _shader->setUniform( _uniformCache.viewProj, global::renderEngine->scene()->camera()->viewProjectionMatrix() ); - ghoul::opengl::TextureUnit unit; - unit.activate(); - bindTexture(); - _shader->setUniform(_uniformCache.texture, unit); - - glBindVertexArray(rendering::helper::vertexObjects.square.vao); glDrawArrays(GL_TRIANGLES, 0, 6); glEnable(GL_CULL_FACE); _shader->deactivate(); - unbindTexture(); } - glm::dvec2 ScreenSpaceSkyTarget::getScreenSpacePosition() { - return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); - } - - glm::dvec2 ScreenSpaceSkyTarget::getScreenSpaceDimensions() { - return glm::dvec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); - } - - glm::dvec2 ScreenSpaceSkyTarget::getUpperRightCornerScreenSpace() { - - return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0); - } - - glm::dvec2 ScreenSpaceSkyTarget::getLowerLeftCornerScreenSpace() { - return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0); - } - - bool ScreenSpaceSkyTarget::coordIsInsideCornersScreenSpace(glm::dvec2 coord) { - bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; - bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; - return lessThanUpperRight && moreThanLowerLeft; - } - - void ScreenSpaceSkyTarget::setDimensions(glm::vec2 currentBrowserDimensions) { - _targetDimensions = currentBrowserDimensions; + void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { + _objectSize = dimensions; } glm::dvec3 ScreenSpaceSkyTarget::getTargetDirectionGalactic() { - // Get camera view direction and orthogonal coordinate system of camera view direction - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - //glm::dvec3 targetPosWorldSpace = glm::inverse(global::navigationHandler->camera()->combinedViewMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0); - //glm::dvec3 targetDirection = glm::normalize(targetPosWorldSpace - camPos); - glm::dvec3 targetDirection = glm::normalize(glm::inverse(global::navigationHandler->camera()->viewRotationMatrix()) * glm::dvec4(_cartesianPosition.value(), 1.0)); - return targetDirection; + glm::dmat4 rotation = glm::inverse( + global::navigationHandler->camera()->viewRotationMatrix()); + glm::dvec4 position = glm::dvec4(_cartesianPosition.value(), 1.0); + + return glm::normalize(rotation * position); } - void ScreenSpaceSkyTarget::updateFOV(float VFOV) { + void ScreenSpaceSkyTarget::setVerticalFOV(float VFOV) { + _verticalFOV = VFOV; + + // Update the scale of the target float horizFOV = global::windowDelegate->getHorizFieldOfView(); glm::ivec2 windowRatio = global::windowDelegate->currentWindowSize(); - float verticFOV = horizFOV * (static_cast(windowRatio.y) / static_cast(windowRatio.x)); - _scale = std::max((VFOV / verticFOV),(_showRectangleThreshold.value()/ verticFOV)); - - _fieldOfView = VFOV; + _scale = std::max((VFOV / verticFOV), (_showRectangleThreshold.value() / verticFOV)); } void ScreenSpaceSkyTarget::unlock() { @@ -342,12 +261,12 @@ namespace openspace { unlock(); } _isLocked = true; - lockedCelestialCoords = getTargetDirectionCelestial(); + _lockedCoords = getTargetDirectionCelestial(); // Start a thread to enable user interactions while locking target _lockTargetThread = std::thread([&] { while (_isLocked) { - glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(lockedCelestialCoords); + glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(_lockedCoords); _cartesianPosition = imageCoordsScreenSpace; } }); @@ -367,15 +286,15 @@ namespace openspace { } void ScreenSpaceSkyTarget::animateToCoord(double deltaTime) { - if (isAnimated) { + if (_isAnimated) { // Find smallest angle between the two vectors - double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsToAnimateTo) / (glm::length(_coordsStartAnimation) * glm::length(_coordsToAnimateTo))); + double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsEndAnimation) / (glm::length(_coordsStartAnimation) * glm::length(_coordsEndAnimation))); // Only keep animating when target is not at final position if (abs(smallestAngle) > 0.0005) { // Calculate rotation this frame double rotationAngle = smallestAngle * deltaTime * 5.0; // Create the rotation matrix - glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsToAnimateTo)); + glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsEndAnimation)); glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); // Rotate target direction glm::dvec3 newDir = rotmat * glm::dvec4(_coordsStartAnimation, 1.0); @@ -386,24 +305,22 @@ namespace openspace { } else { // Set the exact target position - _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsToAnimateTo); + _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsEndAnimation); // Lock target when it first arrives to the position - if (!_isLocked && _lockAfterwards) { + if (!_isLocked && _lockAfterAnimation) { lock(); } // When target is in position, animate the FOV until it has finished - if(animateFOV(FOVToAnimateTo, deltaTime)) { - isAnimated = false; + if(animateToFOV(_FOVEndAnimation, deltaTime)) { + _isAnimated = false; } } } } - bool ScreenSpaceSkyTarget::animateFOV(float endFOV, float deltaTime) { + bool ScreenSpaceSkyTarget::animateToFOV(float endFOV, float deltaTime) { if (!_skyBrowser) { - ScreenSpaceSkyBrowser* browser = dynamic_cast( - global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); - setBrowser(browser); + initializeWithBrowser(); } if (_skyBrowser) { double distance = static_cast(_skyBrowser->_vfieldOfView.value()) - endFOV; @@ -426,12 +343,12 @@ namespace openspace { bool lockAfterwards) { // Save the Cartesian celestial coordinates for animation // The coordinates are Cartesian to avoid wrap-around issues - _coordsToAnimateTo = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd)); + _coordsEndAnimation = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd)); _coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian( getTargetDirectionCelestial())); - FOVToAnimateTo = FOVEnd; - isAnimated = true; - _lockAfterwards = lockAfterwards; + _FOVEndAnimation = FOVEnd; + _isAnimated = true; + _lockAfterAnimation = lockAfterwards; } properties::FloatProperty& ScreenSpaceSkyTarget::getOpacity() { return _opacity; diff --git a/modules/skybrowser/target.png b/modules/skybrowser/target.png deleted file mode 100644 index 2db4325598d0b5a39820d159e07258aa7e98fed7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2506 zcmeAS@N?(olHy`uVBq!ia0y~yVA=u1CLC-)k#C!#dVmyTage(c!@6@aFM%AEbVpxD z28NCO+M1MG8 z`1?6esq_GErx;MMitY T?!v{fAOk&J{an^LB{Ts5>xHg5 From 7c3c878e2e178148e25859f5c3509c70d7cb5998 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 20 Sep 2021 13:36:38 +0200 Subject: [PATCH 128/251] Set gui to the latest version with the WWT logo --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 12b22c1095..0f8e350871 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "55adb23d5f564e407b8778101ab52bf9b1d79149" +local frontendHash = "60e1399472a86464e963a39ab6fc13de6a5f3bf4" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From fcdf33e178d77d326009408ec585a63c0eba39ca Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 20 Sep 2021 13:49:22 +0200 Subject: [PATCH 129/251] Set variables to better names cleanup --- modules/skybrowser/skybrowsermodule_lua.inl | 48 +++++++++++---------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 895504eba4..b49a06bddc 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -44,29 +44,29 @@ namespace openspace::skybrowser::luascriptfunctions { if (module->browserIdExists(module->selectedBrowserId())) { selectedBrowser = module->getSkyBrowsers()[module->selectedBrowserId()]; } - ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; if (selectedBrowser) { // Load image into browser - LINFO("Loading image " + resultImage.name); - selectedBrowser->addSelectedImage(resultImage, i); + LINFO("Loading image " + image.name); + selectedBrowser->addSelectedImage(image, i); ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); // If the image has coordinates, move the target - if (resultImage.hasCelestCoords && selectedTarget) { + if (image.hasCelestCoords && selectedTarget) { // Animate the target to the image coord position selectedTarget->unlock(); - selectedTarget->startAnimation(resultImage.celestCoords, resultImage.fov); + selectedTarget->startAnimation(image.celestCoords, image.fov); // Check if image coordinate is within current FOV - glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); + glm::dvec3 coordsScreen = J2000SphericalToScreenSpace(image.celestCoords); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); float r = windowRatio.x / windowRatio.y; - bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && - abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); - bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; + bool coordIsWithinView = (abs(coordsScreen.x) < r && + abs(coordsScreen.y) < 1.f && coordsScreen.z < 0); + bool coordIsBehindCamera = coordsScreen.z > 0; // If the coordinate is not in view, rotate camera if (!coordIsWithinView || coordIsBehindCamera) { - module->startRotation(resultImage.celestCoords); + module->startRotation(image.celestCoords); } } } @@ -76,7 +76,7 @@ namespace openspace::skybrowser::luascriptfunctions { RenderableSkyBrowser* browser3d = dynamic_cast( node->renderable()); if (browser3d) { - browser3d->displayImage(resultImage, i); + browser3d->displayImage(image, i); } else { LINFO("No browser selected!"); @@ -92,16 +92,17 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + const ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; // Only move and show circle if the image has coordinates - if (resultImage.hasCelestCoords && module->cameraInSolarSystem()) { + if (image.hasCelestCoords && module->cameraInSolarSystem()) { // Make circle visible - ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); + ScreenSpaceImageLocal* hoverCircle = dynamic_cast( + global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(true); // Calculate coords for the circle and translate - glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(resultImage.celestCoords); - hoverCircle->property("CartesianPosition")->set(imageCoordsScreenSpace); + glm::vec3 coordsScreen = skybrowser::J2000SphericalToScreenSpace(image.celestCoords); + hoverCircle->property("CartesianPosition")->set(coordsScreen); } return 0; @@ -109,7 +110,8 @@ namespace openspace::skybrowser::luascriptfunctions { int disableHoverCircle(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); - ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); + ScreenSpaceImageLocal* hoverCircle = dynamic_cast( + global::renderEngine->screenSpaceRenderable("HoverCircle")); if (hoverCircle->isEnabled()) { hoverCircle->property("Enabled")->set(false); } @@ -234,7 +236,7 @@ namespace openspace::skybrowser::luascriptfunctions { } else if (dynamic_cast(found)) { ScreenSpaceSkyTarget* target = dynamic_cast(found); - target->setConnectedBrowser(); + target->initializeWithBrowser(); } return 0; } @@ -529,10 +531,10 @@ namespace openspace::skybrowser::luascriptfunctions { int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); const std::string browserId = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 2); + const std::string i = std::to_string(ghoul::lua::value(L, 2)); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - ghoul::Dictionary message = wwtmessage::setLayerOpacity(std::to_string(i), opacity); + ghoul::Dictionary message = wwtmessage::setLayerOpacity(i, opacity); if (module->browserIdExists(browserId)) { module->getSkyBrowsers()[browserId]->sendMessageToWWT(message); @@ -623,18 +625,18 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string browserId = ghoul::lua::value(L, 2); // Get browser SkyBrowserModule* module = global::moduleEngine->module(); - ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; + ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; if (module->browserIdExists(browserId)) { ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; // Remove image - browser->removeSelectedImage(resultImage, i); + browser->removeSelectedImage(image, i); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( module->get3dBrowser()->renderable()); - browser3d->removeSelectedImage(resultImage, i); + browser3d->removeSelectedImage(image, i); } return 0; } From c895f249896f801c204bd750ffd6508abf650380 Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 25 Oct 2021 09:38:09 -0400 Subject: [PATCH 130/251] Cleanup --- data/assets/skyBrowserTargetPair.asset | 2 +- .../rendering/screenspacerenderable.h | 8 +- .../skybrowser/include/renderableskybrowser.h | 49 +-- .../include/screenspaceskybrowser.h | 105 +++--- .../skybrowser/include/screenspaceskytarget.h | 67 ++-- modules/skybrowser/include/utility.h | 56 ++-- modules/skybrowser/include/wwtdatahandler.h | 50 +-- modules/skybrowser/shaders/target_fs.glsl | 48 +-- modules/skybrowser/skybrowsermodule.cpp | 264 ++++++++------- modules/skybrowser/skybrowsermodule.h | 109 ++++--- modules/skybrowser/skybrowsermodule_lua.inl | 105 +++--- .../skybrowser/src/renderableskybrowser.cpp | 38 +-- .../skybrowser/src/screenspaceskybrowser.cpp | 304 ++++++++++-------- .../skybrowser/src/screenspaceskytarget.cpp | 143 ++++---- modules/skybrowser/src/utility.cpp | 137 ++++---- modules/skybrowser/src/wwtdatahandler.cpp | 161 ++++++---- src/rendering/screenspacerenderable.cpp | 16 +- 17 files changed, 910 insertions(+), 752 deletions(-) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 6c0d6e33eb..5fde6352b3 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -11,7 +11,7 @@ local browser = { Name = "Sky Browser", Url = serverUrl, FaceCamera = false, - TargetID = targetId, + TargetId = targetId, CartesianPosition = {-1.0, -0.5, -2.1}, }; diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 5e79c90c74..a27de28b34 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -73,10 +73,10 @@ public: // Added by skybrowser team // Screen space functionality in these coords: [-1,1][-ratio,ratio] - glm::vec2 getScreenSpacePosition(); - glm::vec2 getScreenSpaceDimensions(); - glm::vec2 getUpperRightCornerScreenSpace(); - glm::vec2 getLowerLeftCornerScreenSpace(); + glm::vec2 screenSpacePosition(); + glm::vec2 screenSpaceDimensions(); + glm::vec2 upperRightCornerScreenSpace(); + glm::vec2 lowerLeftCornerScreenSpace(); bool coordIsInsideCornersScreenSpace(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); friend bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs); diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index d1fabcd9f0..85daa90142 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -47,30 +47,35 @@ namespace openspace { RenderableSkyBrowser(const ghoul::Dictionary& dictionary); virtual ~RenderableSkyBrowser() = default; + // Inherited from RenderablePlane void initializeGL() override; void deinitializeGL() override; - void update(const UpdateData& data) override; + // Web page communication void executeJavascript(std::string script) const; - bool sendMessageToWWT(const ghoul::Dictionary& msg); - void connectToWwt(); - void stopConnectingToWwt(); + void setIdInBrowser(std::string id); + + // WorldWide Telescope communication void displayImage(ImageData& image, int i); void removeSelectedImage(ImageData& image, int i); - void setIdInBrowser(std::string id); - float fieldOfView() const; - std::deque& selectedImages(); + bool sendMessageToWwt(const ghoul::Dictionary& msg); + void syncWwtView(); + void stopSyncingWwtView(); + + // Getters + float verticalFov() const; + std::deque& getSelectedImages(); + + // Setters void setImageLayerOrder(int i, int order, int version); - protected: - - properties::Vec2Property _dimensions; - std::unique_ptr _browserInstance; - std::unique_ptr _texture; - - private: + // Properties + properties::Vec2Property _dimensions; + properties::StringProperty _url; + properties::TriggerProperty _reload; + class ScreenSpaceRenderHandler : public WebRenderHandler { public: void draw() override; @@ -79,23 +84,21 @@ namespace openspace { void setTexture(GLuint t); }; - CefRefPtr _renderHandler; - void bindTexture() override; - properties::StringProperty _url; - - properties::TriggerProperty _reload; - + // Browser variables + std::unique_ptr _browserInstance; + std::unique_ptr _texture; + CefRefPtr _renderHandler; CefRefPtr _keyboardHandler; + // Flags bool _isUrlDirty = false; bool _isDimensionsDirty = false; + bool _syncViewWithWwt; - float _fov; - bool _connectToWwt; + float _verticalFov; std::thread _threadWwtMessages; - std::deque _selectedImages; }; } diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 1d7c54ae98..52d716787b 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -13,63 +13,88 @@ namespace openspace { class ScreenSpaceSkyBrowser : public ScreenSpaceBrowser { public: + // Constructor and destructor ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyBrowser(); + // Inherited functions bool initializeGL() override; bool deinitializeGL() override; - bool setConnectedTarget(); + glm::mat4 scaleMatrix() override; + + // Target - browser connection + bool connectToSkyTarget(); void initializeBrowser(); - void setIdInBrowser(); + + // Getters returning values + bool hasLoadedImages() const; + glm::vec2 browserPixelDimensions() const; + glm::ivec3 borderColor() const; + float verticalFov() const; - // Communication with the webpage and WWT - void executeJavascript(std::string script) const; - bool sendMessageToWWT(const ghoul::Dictionary& msg); - void WWTfollowCamera(); - float fieldOfView() const; - void setVerticalFieldOfView(float fov); - void scrollZoom(float scroll); + // Getters returning references ScreenSpaceSkyTarget* getSkyTarget(); - bool hasLoadedCollections(); - void setHasLoadedCollections(bool isLoaded); + std::deque& getSelectedImages(); properties::FloatProperty& getOpacity(); - std::deque& selectedImages(); + + // Setters + void setHasLoadedImages(bool isLoaded); + void setVerticalFov(float vfov); + void setVerticalFovWithScroll(float scroll); + void setScale(glm::vec2 scalingFactor); + void setScale(float scalingFactor); + void setWebpageBorderColor(glm::ivec3 color); + + // Communication with the web page + void executeJavascript(std::string script); + void sendIdToBrowser(); + + // Communication with WorldWide Telescope void addSelectedImage(ImageData& image, int i); void removeSelectedImage(ImageData& image, int i); - void setImageLayerOrder(int i, int order, int version); + void setImageOrder(int i, int order, int version); + void sendMessageToWwt(const ghoul::Dictionary& msg); + void syncWwtView(); + + // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in + // image if the mouse is on a side of the browser + // __1__ + // y| -1 |_____|1 + // |__x -1 + glm::vec2 isOnResizeArea(glm::vec2 screenSpaceCoord); + + // Resize functions + void saveResizeStartSize(); + void updateBrowserSize(); // Translation //void translate(glm::vec2 translation); - - // Position and dimension and corners - glm::vec2 getBrowserPixelDimensions(); - glm::vec2 coordIsOnResizeArea(glm::vec2 coord); - // Scaling - void scale(glm::vec2 scalingFactor); - void scale(float scalingFactor); - glm::mat4 scaleMatrix() override; - // Resizing - void saveResizeStartSize(); - void updateBrowserSize(); - void setBorderColor(glm::ivec3 addColor); - glm::ivec3 getColor(); - // Flag for dimensions - bool _browserDimIsDirty; - properties::FloatProperty _vfieldOfView; - properties::StringProperty _skyTargetID; - properties::Vec3Property _borderColor; + private: - glm::vec2 _startDimensionsSize; - float _startScale; + // Properties + properties::FloatProperty _verticalFov; + properties::StringProperty _skyTargetId; properties::Vec2Property _browserDimensions; - bool _camIsSyncedWWT; - ScreenSpaceSkyTarget* _skyTarget; - std::thread _threadWWTMessages; - // For capping the calls to change the zoom from scrolling - constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; - std::chrono::system_clock::time_point _lastUpdateTime; - bool _hasLoadedCollections{ false }; + properties::Vec3Property _borderColor; + + // Flags + bool _hasLoadedImages{ false }; + bool _syncViewWithWwt{ false }; + + // Resizing of browser + glm::vec2 _originalDimensions; + float _originalScale; + float _resizeAreaPercentage{ 0.1f }; + + // Target & images + ScreenSpaceSkyTarget* _skyTarget{ nullptr }; + std::thread _threadWwtMessages; std::deque _selectedImages; + + // Time variables + // For capping the calls to change the zoom from scrolling + constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; + std::chrono::system_clock::time_point _lastUpdateTime; }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index feac775cb3..49fd66e66f 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -19,64 +19,77 @@ namespace openspace { class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { public: + // Constructor & destructor ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyTarget(); + // ScreenSpaceRenderable inherited functions bool initializeGL() override; bool isReady() const override; void render() override; glm::mat4 scaleMatrix() override; void bindTexture() override; // Empty function but has to be defined - void createShaders(); - void initializeWithBrowser(); + + // Sky browser functionality + bool findSkyBrowser(); + void matchAppearanceToSkyBrowser(); + + // Getters ScreenSpaceSkyBrowser* getSkyBrowser(); - - void setVerticalFOV(float VFOV); + glm::ivec3 borderColor() const; + float opacity() const; + + // Setters + void setScale(float verticalFov); void setDimensions(glm::vec2 dimensions); void setColor(glm::ivec3 color); - glm::ivec3 getColor(); - properties::FloatProperty& getOpacity(); + void setOpacity(float opacity); // Target directions - glm::dvec3 getTargetDirectionGalactic(); - glm::dvec2 getTargetDirectionCelestial(); + glm::dvec3 targetDirectionGalactic() const; + glm::dvec3 targetDirectionEquatorial() const; // Locking functionality - void unlock(); void lock(); + void unlock(); bool isLocked(); // Animations - void startAnimation(glm::dvec2 coordsEnd, float FOVEnd, bool lockAfterwards = true); - void animateToCoord(double deltaTime); - bool animateToFOV(float endFOV, float deltaTime); + void startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfter = true); + void animateToCoordinate(double deltaTime); + bool animateToFov(float endFOV, float deltaTime); - properties::StringProperty _skyBrowserID; + private: + // Properties + properties::StringProperty _skyBrowserId; properties::FloatProperty _showCrosshairThreshold; properties::FloatProperty _showRectangleThreshold; - private: + // Flags + bool _isAnimated{ false }; + bool _lockAfterAnimation{ false }; + bool _isLocked{ false }; + // Shader UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, dimensions, lineColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; - glm::ivec3 _color; - float _verticalFOV = 100.f; - ScreenSpaceSkyBrowser* _skyBrowser; - // Locking target to a coordinate on the sky - bool _isLocked; - glm::dvec2 _lockedCoords; // Spherical celestial coords - std::thread _lockTargetThread; + // Sky browser + ScreenSpaceSkyBrowser* _skyBrowser; + glm::ivec3 _color; + + // Lock target to a coordinate on the sky + glm::dvec3 _lockedCoordinates; // Spherical celestial coordinates + std::thread _lockTarget; - // Animating the target - bool _isAnimated = false; - glm::dvec3 _coordsEndAnimation; // Cartesian celestial coords - glm::dvec3 _coordsStartAnimation; // Cartesian celestial coords + // Animation of target + glm::dvec3 _animationEnd; // Cartesian celestial coordinates + glm::dvec3 _animationStart; // Cartesian celestial coordinates double _animationTime = 1.0; - float _FOVEndAnimation; - bool _lockAfterAnimation; + float _vfovEndAnimation; + }; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index f12998a09d..32069a701f 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -10,45 +10,49 @@ namespace openspace { namespace skybrowser { - const double SCREENSPACE_Z = -2.1; - const double RAD_TO_DEG = 180.0 / M_PI; - const double DEG_TO_RAD = M_PI / 180.0; - const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 }; - constexpr double infinity = std::numeric_limits::max(); + // Constants + constexpr const double ScreenSpaceZ = -2.1; + constexpr const glm::dvec3 NorthPole = { 0.0 , 0.0 , 1.0 }; + constexpr const double CelestialSphereRadius = std::numeric_limits::max(); - // Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1 + // Conversion matrix - J2000 equatorial <-> galactic + // https://arxiv.org/abs/1010.3773v1 const glm::dmat3 conversionMatrix = glm::dmat3({ -0.054875539390, 0.494109453633, -0.867666135681, // col 0 -0.873437104725, -0.444829594298, -0.198076389622, // col 1 -0.483834991775, 0.746982248696, 0.455983794523 // col 2 }); - // J2000 to galactic conversion and vice versa - glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords); - glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords); - glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal); - glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal); - glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords); - glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, - double distance = infinity); - glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, - double distance = infinity); - // Convert J2000, spherical or Cartesian, to screen space - glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords); - glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords); - glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord); - double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld); - glm::dvec3 cameraDirectionJ2000Cartesian(); + // Conversion spherical <-> Cartesian + glm::dvec2 cartesianToSpherical(glm::dvec3 coords); + glm::dvec3 sphericalToCartesian(glm::dvec2 coords); + + // Conversion J2000 equatorial <-> galactic + glm::dvec3 galacticToEquatorial(glm::dvec3 coords); + glm::dvec3 galacticToCameraLocal(glm::dvec3 coords); + glm::dvec3 equatorialToGalactic(glm::dvec3 coords); + + // Conversion J2000 equatorial / galactic <-> screen space + glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords); + glm::dvec3 galacticToScreenSpace(glm::dvec3 coords); + glm::dvec3 screenSpaceToGalactic(glm::dvec3 coords); + glm::dvec3 screenSpaceToEquatorial(glm::dvec3 coords); + + // Camera roll and direction + // Camera roll is with respect to the equatorial North Pole + double cameraRoll(); + glm::dvec3 cameraDirectionGalactic(); + glm::dvec3 cameraDirectionEquatorial(); } + // WorldWide Telescope messages namespace wwtmessage { - // WWT messages ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, const double roll, const bool moveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); - ghoul::Dictionary createImageLayer(const std::string& id, const std::string& url); - ghoul::Dictionary removeImageLayer(const std::string& id); - ghoul::Dictionary setLayerOpacity(const std::string& id, double opacity); + ghoul::Dictionary addImage(const std::string& id, const std::string& url); + ghoul::Dictionary removeImage(const std::string& id); + ghoul::Dictionary setImageOpacity(const std::string& id, double opacity); ghoul::Dictionary setForegroundOpacity(double val); ghoul::Dictionary setLayerOrder(const std::string& id, int order, int version); } diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 8d078cd804..45ab0a7a6e 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -57,12 +57,12 @@ namespace openspace { std::string name; std::string thumbnailUrl; std::string imageUrl; - std::string credits; std::string creditsUrl; - glm::dvec2 celestCoords; + std::string credits; + glm::dvec2 celestialCoords; std::string collection; float fov; - bool hasCelestCoords{ false }; + bool hasCelestialCoords{ false }; bool has3dCoords{ false }; glm::dvec3 position3d; }; @@ -73,24 +73,31 @@ namespace openspace { bool loaded = false; }; - class WWTDataHandler { + class WwtDataHandler { public: - WWTDataHandler() = default; - ~WWTDataHandler(); - // Image downloading and xml parsing - bool downloadFile(std::string& url, std::string& fileDestination); - void loadWTMLCollectionsFromURL(std::string directory, std::string url, std::string fileName); - bool loadWTMLCollectionsFromDirectory(std::string directory); - int loadImagesFromLoadedXMLs(); + // Constructor and destructor + WwtDataHandler() = default; + ~WwtDataHandler(); + // Image downloading and xml parsing + bool loadWtmlCollectionsFromUrl(std::string directory, std::string url, + std::string fileName); + bool loadWtmlCollectionsFromDirectory(std::string directory); + int loadImagesFromLoadedXmls(); + + // Loading speck files + void loadSpeckData(speck::Dataset& dataset); + + // Getters const std::vector& getAllImageCollectionUrls() const; std::vector& getLoadedImages(); - void loadSpeckData(speck::Dataset& dataset); - std::string createSearchableString(std::string name); private: - void loadImagesFromXML(tinyxml2::XMLElement* node, + + // Parsing and downloading of wtml files + bool downloadFile(std::string& url, std::string& fileDestination); + void loadImagesFromXml(tinyxml2::XMLElement* node, std::string collectionName); int loadImageFromXmlNode(tinyxml2::XMLElement* imageSet, std::string collectionName); @@ -105,17 +112,22 @@ namespace openspace { std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName); - std::string getURLFromPlace(tinyxml2::XMLElement* place); + std::string getUrlFromPlace(tinyxml2::XMLElement* place); tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, std::string name); tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); - std::vector images; - std::vector imageUrls; - std::vector xmls; + // Used for matching names + std::string createSearchableString(std::string name); + + // Images + std::vector _images; + std::vector _imageUrls; + std::vector _xmls; + // 3D position data loaded from speck files std::unordered_map _3dPositions; - int nImagesWith3dPositions = 0; + int _nImagesWith3dPositions = 0; }; } diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index fea8daa875..ee7d042cd6 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -11,45 +11,45 @@ in vec4 vs_position; // This compensates for the optical illusion that vertical lines appear thinner #define VERTICAL_THICKNESS 1.15f -float line(in float _lineCenter, in float _lineWidth, in float _coord) { +float createLine(in float lineCenter, in float lineWidth, in float coord) { // Calculate edges of line - float start_edge = _lineCenter - (_lineWidth * 0.5f); - float end_edge = _lineCenter + (_lineWidth * 0.5f); + float start_edge = lineCenter - (lineWidth * 0.5f); + float end_edge = lineCenter + (lineWidth * 0.5f); // Create line - float line = step(start_edge, _coord) - step(end_edge, _coord); + float line = step(start_edge, coord) - step(end_edge, coord); return line; } -float rectangle(in float _linewidth_y, in float _ratio, in vec2 _coord) { +float createRectangle(in float linewidth_y, in float ratio, in vec2 coord) { // Calculate the widths and centers for the lines - float linewidth_x = _linewidth_y * _ratio * VERTICAL_THICKNESS; + float linewidth_x = linewidth_y * ratio * VERTICAL_THICKNESS; float linecenter_x = linewidth_x * 0.5f; - float linecenter_y = _linewidth_y * 0.5f; + float linecenter_y = linewidth_y * 0.5f; // Create the four lines for the rectangle - float l = line(linecenter_x, linewidth_x, _coord.x); - float r = line(1.0f - linecenter_x, linewidth_x, _coord.x); - float b = line(linecenter_y, _linewidth_y, _coord.y); - float t = line(1.0f - linecenter_y, _linewidth_y, _coord.y); + float l = createLine(linecenter_x, linewidth_x, coord.x); + float r = createLine(1.0f - linecenter_x, linewidth_x, coord.x); + float b = createLine(linecenter_y, linewidth_y, coord.y); + float t = createLine(1.0f - linecenter_y, linewidth_y, coord.y); // Add all lines together return l + r + b + t; } -float crosshair(in float _linewidth, in float _ratio, in vec2 _coord) { +float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { float center = 0.5f; - float crosshair_vertical = line(center, _linewidth * _ratio * VERTICAL_THICKNESS, _coord.x); - float crosshair_horizontal = line(center, _linewidth, _coord.y); + float crosshair_vertical = createLine(center, linewidth * ratio * VERTICAL_THICKNESS, coord.x); + float crosshair_horizontal = createLine(center, linewidth, coord.y); return crosshair_horizontal + crosshair_vertical; } -float filledRectangle(in float _size, in float _ratio, in vec2 _coord) { +float createFilledRectangle(in float size, in float ratio, in vec2 coord) { float center = 0.5f; - float horizontal = line(center, _size, _coord.y); - float vertical = line(center, _size, _coord.x); + float horizontal = createLine(center, size, coord.y); + float vertical = createLine(center, size, coord.x); return horizontal * vertical; } @@ -57,24 +57,24 @@ float filledRectangle(in float _size, in float _ratio, in vec2 _coord) { #include "fragment.glsl" Fragment getFragment() { - float _ratio = dimensions.y / dimensions.x; - float _crosshair = 0.0f; - float _rectangle = 0.0f; + float ratio = dimensions.y / dimensions.x; + float crosshair = 0.0f; + float rectangle = 0.0f; if(showCrosshair) { - _crosshair = crosshair(lineWidth, _ratio, vs_st); + crosshair = createCrosshair(lineWidth, ratio, vs_st); } if(showRectangle) { - _rectangle = rectangle(lineWidth, _ratio, vs_st); + rectangle = createRectangle(lineWidth, ratio, vs_st); } // If both rectangle and crosshair are displayed, draw crosshair a bit smaller if(showCrosshair && showRectangle) { - _crosshair *= filledRectangle(lineWidth * 7.0f, _ratio, vs_st); + crosshair *= createFilledRectangle(lineWidth * 7.0f, ratio, vs_st); } - float result = clamp(_crosshair + _rectangle, 0.0, 1.0); + float result = clamp(crosshair + rectangle, 0.0, 1.0); Fragment frag; frag.color = lineColor; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 051279182a..4c3bf15d95 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -247,34 +247,37 @@ namespace openspace { return res; } +// Transforms a pixel coordinate to a screen space coordinate +glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate) { + glm::vec2 size = global::windowDelegate->currentWindowSize(); + // Change origin to middle of the window + glm::vec2 screenSpacePos = glm::vec2((mouseCoordinate - (size / 2.0f))); + // Ensure the upper right corner is positive on the y axis + screenSpacePos *= glm::vec2(1.0f, -1.0f); + // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] + screenSpacePos /= (0.5f * size.y); + return screenSpacePos; +} + SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) - , _mouseOnObject(nullptr) - , currentlyResizingBrowser(false) - , currentlyDraggingObject(false) - , resizeVector(0.f, 0.f) - , changeViewWithinBrowser(false) - , _browser3d(nullptr) - , _layerOrderCounter(0) - , _cameraInSolarSystem(true) - , highlightAddition(35, 35, 35) { global::callback::mousePosition->emplace_back( [&](double x, double y) { - glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); - _mousePosition = getMousePositionInScreenSpaceCoords(pos); + glm::vec2 pixel = glm::vec2(static_cast(x), static_cast(y)); + _mousePosition = pixelToScreenSpace(pixel); - if (currentlyDraggingObject) { + if (_isDragging) { - glm::dvec2 move = _mousePosition - startDragMousePos; + glm::dvec2 move = _mousePosition - _startMousePosition; - // Change view within the browser and move target accordingly to mousedrag movement - if (changeViewWithinBrowser) { + // Change view within the browser and move target accordingly to mouse drag movement + if (_fineTuneMode) { // WWT FOV - double WWTVerticalFOV = to_browser(_mouseOnObject)->fieldOfView(); - glm::dvec2 browserDim = to_browser(_mouseOnObject)->getScreenSpaceDimensions(); + double WWTVerticalFOV = toBrowser(_mouseOnObject)->verticalFov(); + glm::dvec2 browserDim = toBrowser(_mouseOnObject)->screenSpaceDimensions(); double browserRatio = browserDim.x / browserDim.y; glm::dvec2 WWTFOV = glm::dvec2(WWTVerticalFOV * browserRatio, WWTVerticalFOV); @@ -291,24 +294,24 @@ SkyBrowserModule::SkyBrowserModule() glm::dvec2 screenSpaceCoord{ (2 / windowRatio), 2.f }; glm::dvec2 result = screenSpaceCoord * OSresult; - to_browser(_mouseOnObject)->getSkyTarget()->translate(-result, startDragObjectPos); + toBrowser(_mouseOnObject)->getSkyTarget()->translate(-result, _startDragPosition); } // Move browser or target - else _mouseOnObject->translate(move, startDragObjectPos); + else _mouseOnObject->translate(move, _startDragPosition); } - else if (currentlyResizingBrowser) { + else if (_isResizing) { // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition - startDragMousePos); - glm::vec2 scalingVector = mouseDragVector * resizeVector; - glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; + glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); + glm::vec2 scalingVector = mouseDragVector * _resizeDirection; + glm::vec2 newSizeRelToOld = (_startBrowserSize + (scalingVector)) / _startBrowserSize; // Scale the browser - to_browser(_mouseOnObject)->scale(newSizeRelToOld); + toBrowser(_mouseOnObject)->setScale(newSizeRelToOld); // For dragging functionality, translate so it looks like the browser isn't moving // Make sure the browser doesn't move in directions it's not supposed to - _mouseOnObject->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPos); + _mouseOnObject->translate(mouseDragVector * abs(_resizeDirection) / 2.f, _startDragPosition); } // If there is no dragging or resizing, look for new objects else { @@ -316,27 +319,27 @@ SkyBrowserModule::SkyBrowserModule() ScreenSpaceRenderable* lastObj = _mouseOnObject; // Find and save what mouse is currently hovering on - auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { + auto currentlyOnObject = std::find_if(_renderables.begin(), _renderables.end(), [&](ScreenSpaceRenderable* obj) { return obj && (obj->coordIsInsideCornersScreenSpace(_mousePosition) && obj->isEnabled()); }); - _mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr; + _mouseOnObject = currentlyOnObject != _renderables.end() ? *currentlyOnObject : nullptr; // Selection has changed if (lastObj != _mouseOnObject) { // Remove highlight - if (to_browser(lastObj)) { - to_browser(lastObj)->setBorderColor(to_browser(lastObj)->getColor() - highlightAddition); + if (toBrowser(lastObj)) { + toBrowser(lastObj)->setWebpageBorderColor(toBrowser(lastObj)->borderColor() - _highlightAddition); } - else if (to_target(lastObj)) { - to_target(lastObj)->setColor(to_target(lastObj)->getColor() - highlightAddition); + else if (toTarget(lastObj)) { + toTarget(lastObj)->setColor(toTarget(lastObj)->borderColor() - _highlightAddition); } // Add highlight - if (to_browser(_mouseOnObject)) { - to_browser(_mouseOnObject)->setBorderColor(to_browser(_mouseOnObject)->getColor() + highlightAddition); + if (toBrowser(_mouseOnObject)) { + toBrowser(_mouseOnObject)->setWebpageBorderColor(toBrowser(_mouseOnObject)->borderColor() + _highlightAddition); } - else if (to_target(_mouseOnObject)) { - to_target(_mouseOnObject)->setColor(to_target(_mouseOnObject)->getColor() + highlightAddition); + else if (toTarget(_mouseOnObject)) { + toTarget(_mouseOnObject)->setColor(toTarget(_mouseOnObject)->borderColor() + _highlightAddition); } } @@ -348,12 +351,12 @@ SkyBrowserModule::SkyBrowserModule() [&](double, double scroll) -> bool { // If mouse is on browser or target, apply zoom - if (to_browser(_mouseOnObject)) { - to_browser(_mouseOnObject)->scrollZoom(static_cast(scroll)); + if (toBrowser(_mouseOnObject)) { + toBrowser(_mouseOnObject)->setVerticalFovWithScroll(static_cast(scroll)); return true; } - else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { - to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(static_cast(scroll)); + else if (toTarget(_mouseOnObject) && toTarget(_mouseOnObject)->getSkyBrowser()) { + toTarget(_mouseOnObject)->getSkyBrowser()->setVerticalFovWithScroll(static_cast(scroll)); } return false; @@ -366,62 +369,62 @@ SkyBrowserModule::SkyBrowserModule() if (_mouseOnObject && action == MouseAction::Press) { // Get the currently selected browser - if (to_browser(_mouseOnObject)) { - setSelectedBrowser(to_browser(_mouseOnObject)); + if (toBrowser(_mouseOnObject)) { + setSelectedBrowser(toBrowser(_mouseOnObject)); } - else if (to_target(_mouseOnObject) && - to_target(_mouseOnObject)->getSkyBrowser()) { + else if (toTarget(_mouseOnObject) && + toTarget(_mouseOnObject)->getSkyBrowser()) { - setSelectedBrowser(to_target(_mouseOnObject)->getSkyBrowser()); + setSelectedBrowser(toTarget(_mouseOnObject)->getSkyBrowser()); } if (button == MouseButton::Left) { - isRotating = false; - startDragMousePos = _mousePosition; - startDragObjectPos = _mouseOnObject->getScreenSpacePosition(); + _isRotating = false; + _startMousePosition = _mousePosition; + _startDragPosition = _mouseOnObject->screenSpacePosition(); // If current object is browser, check for resizing - if (to_browser(_mouseOnObject)) { + if (toBrowser(_mouseOnObject)) { // Resize browser if mouse is over resize button - resizeVector = to_browser(_mouseOnObject)->coordIsOnResizeArea(_mousePosition); - if (resizeVector != glm::vec2{ 0 }) { - to_browser(_mouseOnObject)->saveResizeStartSize(); - startResizeBrowserSize = to_browser(_mouseOnObject)->getScreenSpaceDimensions(); - currentlyResizingBrowser = true; + _resizeDirection = toBrowser(_mouseOnObject)->isOnResizeArea(_mousePosition); + if (_resizeDirection != glm::vec2{ 0 }) { + toBrowser(_mouseOnObject)->saveResizeStartSize(); + _startBrowserSize = toBrowser(_mouseOnObject)->screenSpaceDimensions(); + _isResizing = true; return true; } } // If you start dragging around the target, it should unlock - if (to_target(_mouseOnObject)) { - to_target(_mouseOnObject)->unlock(); + if (toTarget(_mouseOnObject)) { + toTarget(_mouseOnObject)->unlock(); } - currentlyDraggingObject = true; + _isDragging = true; return true; } - else if (to_browser(_mouseOnObject) && button == MouseButton::Right) { + else if (toBrowser(_mouseOnObject) && button == MouseButton::Right) { // If you start dragging around on the browser, the target should unlock - if (to_browser(_mouseOnObject) && to_browser(_mouseOnObject)->getSkyTarget()) { - to_browser(_mouseOnObject)->getSkyTarget()->unlock(); + if (toBrowser(_mouseOnObject) && toBrowser(_mouseOnObject)->getSkyTarget()) { + toBrowser(_mouseOnObject)->getSkyTarget()->unlock(); } // Change view (by moving target) within browser if right mouse click on browser - startDragMousePos = _mousePosition; - startDragObjectPos = to_browser(_mouseOnObject)->getSkyTarget()->getScreenSpacePosition(); - changeViewWithinBrowser = true; - currentlyDraggingObject = true; + _startMousePosition = _mousePosition; + _startDragPosition = toBrowser(_mouseOnObject)->getSkyTarget()->screenSpacePosition(); + _fineTuneMode = true; + _isDragging = true; return true; } } else if (action == MouseAction::Release) { - if (currentlyDraggingObject) { - currentlyDraggingObject = false; - changeViewWithinBrowser = false; + if (_isDragging) { + _isDragging = false; + _fineTuneMode = false; return true; } - if (currentlyResizingBrowser) { - currentlyResizingBrowser = false; - to_browser(_mouseOnObject)->updateBrowserSize(); + if (_isResizing) { + _isResizing = false; + toBrowser(_mouseOnObject)->updateBrowserSize(); return true; } } @@ -440,7 +443,7 @@ SkyBrowserModule::SkyBrowserModule() double deltaTime = global::windowDelegate->deltaTime(); // Fade out or in browser & target - for (std::pair pair : browsers) { + for (std::pair pair : _browsers) { ScreenSpaceSkyBrowser* browser = pair.second; // If outside solar system and browser is visible if (!_cameraInSolarSystem && browser->isEnabled()) { @@ -450,7 +453,7 @@ SkyBrowserModule::SkyBrowserModule() browser->property("Enabled")->set(false); // Select the 3D browser when moving out of the solar system if (_browser3d != nullptr) { - selectedBrowser = _browser3d->renderable()->identifier(); + _selectedBrowser = _browser3d->renderable()->identifier(); } } } @@ -458,8 +461,8 @@ SkyBrowserModule::SkyBrowserModule() else if (_cameraInSolarSystem && !browser->isEnabled()) { browser->property("Enabled")->set(true); // Select the first 2D browser when moving into the solar system - if (browsers.size() != 0) { - selectedBrowser = std::begin(browsers)->second->identifier(); + if (_browsers.size() != 0) { + _selectedBrowser = std::begin(_browsers)->second->identifier(); } } // If within solar system and browser is visible @@ -467,18 +470,18 @@ SkyBrowserModule::SkyBrowserModule() fadeBrowserAndTarget(false, fadingTime, deltaTime); if (browser->getSkyTarget()) { - browser->getSkyTarget()->animateToCoord(deltaTime); + browser->getSkyTarget()->animateToCoordinate(deltaTime); } } } - if (isRotating) { + if (_isRotating) { rotateCamera(deltaTime); } }); } SkyBrowserModule::~SkyBrowserModule() { - delete dataHandler; + delete _dataHandler; } void SkyBrowserModule::internalDeinitialize() { @@ -502,37 +505,26 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { fRenderable->registerClass("RenderableSkyBrowser"); // Create data handler dynamically to avoid the linking error that // came up when including the include file in the module header file - dataHandler = new WWTDataHandler(); + _dataHandler = new WwtDataHandler(); } -glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { - glm::vec2 size = global::windowDelegate->currentWindowSize(); - // Change origin to middle of the window - glm::vec2 screenSpacePos = glm::vec2((mousePos - (size / 2.0f))); - // Ensure the upper right corner is positive on the y axis - screenSpacePos *= glm::vec2(1.0f, -1.0f); - // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] - screenSpacePos /= (0.5f*size.y); - return screenSpacePos; -} - -int SkyBrowserModule::getAndIncrementLayerOrder() { - return _layerOrderCounter++; +int SkyBrowserModule::getAndIncrementMessageOrder() { + return _messageOrder++; } void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { - renderables.push_back(object); + _renderables.push_back(object); // Sort on z coordinate, objects closer to camera are in beginning of list - std::sort(renderables.begin(), renderables.end()); - ScreenSpaceSkyBrowser* browser = to_browser(object); + std::sort(_renderables.begin(), _renderables.end()); + ScreenSpaceSkyBrowser* browser = toBrowser(object); if (browser) { - browsers[browser->identifier()] = browser; + _browsers[browser->identifier()] = browser; } } bool SkyBrowserModule::browserIdExists(std::string id) { // If the id doesn't exist, return false - if (browsers.find(id) == browsers.end()) { + if (_browsers.find(id) == _browsers.end()) { return false; } return true; @@ -605,7 +597,7 @@ void SkyBrowserModule::createTargetBrowserPair() { void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { if (!browserIdExists(browserId)) return; - ScreenSpaceSkyBrowser* browser = browsers[browserId]; + ScreenSpaceSkyBrowser* browser = _browsers[browserId]; // Find corresponding target std::string targetId{ "" }; @@ -614,10 +606,10 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { targetId = browser->getSkyTarget()->identifier(); } // Remove pointer to the renderable from browsers vector - browsers.erase(browserId); + _browsers.erase(browserId); // Remove pointer to the renderable from screenspace renderable vector - renderables.erase(std::remove_if(std::begin(renderables), std::end(renderables), + _renderables.erase(std::remove_if(std::begin(_renderables), std::end(_renderables), [&](ScreenSpaceRenderable* renderable) { if (renderable->identifier() == browserId) { return true; @@ -628,7 +620,7 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { else { return false; } - }), std::end(renderables)); + }), std::end(_renderables)); // Remove from engine openspace::global::scriptEngine->queueScript( "openspace.removeScreenSpaceRenderable('" + browserId + "');", @@ -661,7 +653,7 @@ void SkyBrowserModule::place3dBrowser(ImageData& image) { // /_| Adjacent is the horizontal line, opposite the vertical // \ | Calculate for half the triangle first, then multiply with 2 // \| - glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); + glm::dvec3 j2000 = skybrowser::galacticToEquatorial(position); double adjacent = glm::length(j2000); double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); @@ -698,23 +690,23 @@ void SkyBrowserModule::set3dBrowser(SceneGraphNode* node) { _browser3d = node; } -ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { +ScreenSpaceSkyBrowser* SkyBrowserModule::toBrowser(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } -ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { +ScreenSpaceSkyTarget* SkyBrowserModule::toTarget(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } -WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { - return dataHandler; +WwtDataHandler* SkyBrowserModule::getWWTDataHandler() { + return _dataHandler; } std::map& SkyBrowserModule::getSkyBrowsers() { - return browsers; + return _browsers; } std::vector& SkyBrowserModule::getBrowsersAndTargets() { - return renderables; + return _renderables; } SceneGraphNode* SkyBrowserModule::get3dBrowser() { @@ -738,35 +730,32 @@ void SkyBrowserModule::lookAt3dBrowser() { ); } -void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) { - +void SkyBrowserModule::startRotation(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - _coordsToAnimateTo = skybrowser::J2000SphericalToGalacticCartesian(coordsEnd); - _coordsStartAnimation = (global::navigationHandler->camera()->viewDirectionWorldSpace() * skybrowser::infinity) + camPos; - isRotating = true; + _endAnimation = endAnimation; + _startAnimation = skybrowser::cameraDirectionGalactic(); + _isRotating = true; } void SkyBrowserModule::rotateCamera(double deltaTime) { // Find smallest angle between the two vectors - double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsToAnimateTo) / (glm::length(_coordsStartAnimation) * glm::length(_coordsToAnimateTo))); + double smallestAngle = std::acos(glm::dot(_startAnimation, _endAnimation) / (glm::length(_startAnimation) * glm::length(_endAnimation))); // Only keep animating when target is not at final position if (abs(smallestAngle) > 0.0001) { // Calculate rotation this frame double rotationAngle = smallestAngle * deltaTime; // Create the rotation matrix for local camera space - glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsToAnimateTo)); + glm::dvec3 rotationAxis = glm::normalize(glm::cross(_startAnimation, _endAnimation)); glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); // Rotate global::navigationHandler->camera()->rotate(glm::quat_cast(rotmat)); // Update camera direction - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - _coordsStartAnimation = (global::navigationHandler->camera()->viewDirectionWorldSpace() * skybrowser::infinity) + camPos; + _startAnimation = skybrowser::cameraDirectionGalactic(); } else { - isRotating = false; + _isRotating = false; } } @@ -780,17 +769,18 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim opacityDelta *= -1.f; } bool finished = true; - for (std::pair idAndBrowser : browsers) { + for (std::pair idAndBrowser : _browsers) { ScreenSpaceSkyBrowser* browser = idAndBrowser.second; // If there is a target, fade it as well. Otherwise, skip ScreenSpaceSkyTarget* target = browser->getSkyTarget(); bool targetFinished = true; if (target) { - target->getOpacity() = target->getOpacity().value() + opacityDelta; - float opacityTarget = abs(target->getOpacity().value()); + target->setOpacity(target->opacity() + opacityDelta); + float opacityTarget = abs(target->opacity()); targetFinished = makeTransparent ? opacityTarget < lowThreshold : opacityTarget > highTreshold; if (targetFinished) { - target->getOpacity() = makeTransparent ? transparent : opaque; + float newOpacity = makeTransparent ? transparent : opaque; + target->setOpacity(newOpacity); } } // Keep fading the browsers until all are finished @@ -809,16 +799,16 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim void SkyBrowserModule::setSelectedBrowser(ScreenSpaceSkyBrowser* browser) { if (browser) { - selectedBrowser = browser->identifier(); + _selectedBrowser = browser->identifier(); } } void SkyBrowserModule::setSelectedBrowser(std::string id) { - selectedBrowser = id; + _selectedBrowser = id; } std::string SkyBrowserModule::selectedBrowserId() { - return selectedBrowser; + return _selectedBrowser; } int SkyBrowserModule::loadImages(const std::string& root, const std::string& directory) { @@ -830,13 +820,13 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir speck::Dataset speckGlobularClusters = speck::loadSpeckFile(globularClusters); speck::Dataset speckOpenClusters = speck::loadSpeckFile(openClusters); - dataHandler->loadSpeckData(speckGlobularClusters); - dataHandler->loadSpeckData(speckOpenClusters); + _dataHandler->loadSpeckData(speckGlobularClusters); + _dataHandler->loadSpeckData(speckOpenClusters); int nLoadedImages; // Read from disc - bool loadedImages = dataHandler->loadWTMLCollectionsFromDirectory(directory); + bool loadedImages = _dataHandler->loadWtmlCollectionsFromDirectory(directory); // Reading from url if there is no directory if (loadedImages) { @@ -844,10 +834,10 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir } else { LINFO("Loading images from url"); - dataHandler->loadWTMLCollectionsFromURL(directory, root, "root"); + _dataHandler->loadWtmlCollectionsFromUrl(directory, root, "root"); } - nLoadedImages = dataHandler->loadImagesFromLoadedXMLs(); + nLoadedImages = _dataHandler->loadImagesFromLoadedXmls(); LINFO("Loaded " + std::to_string(nLoadedImages) + " WorldWide Telescope images."); return nLoadedImages; @@ -856,12 +846,12 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir bool SkyBrowserModule::cameraInSolarSystem() { return _cameraInSolarSystem; } -/* -std::vector SkyBrowserModule::documentations() const { - return { - ExoplanetsDataPreparationTask::documentation(), - RenderableOrbitDisc::Documentation() - }; -} -*/ + +//std::vector SkyBrowserModule::documentations() const { +// return { +// ExoplanetsDataPreparationTask::documentation(), +// RenderableOrbitDisc::Documentation() +// }; +//} + } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index a193624bf4..7c41afda01 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -43,7 +43,7 @@ class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; class RenderableSkyBrowser; class ScreenSpaceRenderable; -class WWTDataHandler; +class WwtDataHandler; class SceneGraphNode; class ImageData; @@ -51,32 +51,42 @@ class ImageData; class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; - constexpr static const int FROM_DIRECTORY = 0; - constexpr static const int FROM_URL = 1; - + + // Constructor & destructor SkyBrowserModule(); virtual ~SkyBrowserModule(); - glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos); - void addRenderable(ScreenSpaceRenderable* object); - WWTDataHandler* getWWTDataHandler(); + + // Getters std::map& getSkyBrowsers(); std::vector& getBrowsersAndTargets(); SceneGraphNode* get3dBrowser(); - void startRotation(glm::dvec2 coordsEnd); - void rotateCamera(double deltaTime); - bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); + WwtDataHandler* getWWTDataHandler(); + std::string selectedBrowserId(); + + // Setters void setSelectedBrowser(ScreenSpaceSkyBrowser* ptr); void setSelectedBrowser(std::string id); - bool browserIdExists(std::string id); - std::string selectedBrowserId(); - int loadImages(const std::string& root, const std::string& directory); void set3dBrowser(SceneGraphNode* node); + + // Rotation and animation + void startRotation(glm::dvec3 endAnimation); // Pass in galactic coord + void rotateCamera(double deltaTime); + bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); + void lookAt3dBrowser(); + + // Boolean functions + bool browserIdExists(std::string id); bool cameraInSolarSystem(); + + // Managing the browsers void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); + void addRenderable(ScreenSpaceRenderable* object); void place3dBrowser(ImageData& image); - void lookAt3dBrowser(); - int getAndIncrementLayerOrder(); + + // Image collection handling + int loadImages(const std::string& root, const std::string& directory); + int getAndIncrementMessageOrder(); // For version handling calls to WWT scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -84,43 +94,42 @@ public: protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; - - // Using snake case on these casting functions to make them similar to eg std::to_string - ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr); - ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr); + +private: + // Cast screen space renderable to either target or browser + ScreenSpaceSkyBrowser* toBrowser(ScreenSpaceRenderable* ptr); + ScreenSpaceSkyTarget* toTarget(ScreenSpaceRenderable* ptr); // The browsers and targets - std::vector renderables; - // Only the browsers - std::map browsers; - // 3D browser - SceneGraphNode* _browser3d; - // Pointer to what mouse is currently on - ScreenSpaceRenderable* _mouseOnObject; - // Dragging - glm::vec2 startDragMousePos; - glm::vec2 startDragObjectPos; - bool changeViewWithinBrowser; - // Resizing - glm::vec2 startResizeBrowserSize; - glm::vec2 resizeVector; - // The current mouse position in screenspace coordinates - glm::vec2 _mousePosition; - // Current interaction status - bool currentlyResizingBrowser; - bool currentlyDraggingObject; - // Data handler - WWTDataHandler* dataHandler; - // For animating rotation of camera to look at coordinate - glm::dvec3 _coordsToAnimateTo; - glm::dvec3 _coordsStartAnimation; - bool isRotating = false; - // For tracking the currently selected browser - std::string selectedBrowser; - glm::ivec3 highlightAddition; - // Mode of browsing - bool _cameraInSolarSystem; - int _layerOrderCounter; + std::vector _renderables; // 2D browsers and targets + std::map _browsers; // Only the 2D browsers + ScreenSpaceRenderable* _mouseOnObject{ nullptr }; // Pointer to what mouse is currently on + SceneGraphNode* _browser3d{ nullptr }; + std::string _selectedBrowser; // Currently selected browser (2D or 3D) + + // Flags + bool _fineTuneMode{ false }; + bool _isResizing{ false }; + bool _isDragging{ false }; + bool _cameraInSolarSystem{ true }; + bool _isRotating = false; + + // Mouse interaction - dragging and resizing + glm::vec2 _mousePosition; // Current mouse position in screen space coordinates + glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers + glm::vec2 _startMousePosition; + glm::vec2 _startDragPosition; + glm::vec2 _startBrowserSize; + glm::vec2 _resizeDirection{ 0.f }; + + // Animation of rotation of camera to look at coordinate galactic coordinates + glm::dvec3 _startAnimation; + glm::dvec3 _endAnimation; + + // Data handler for the image collections + WwtDataHandler* _dataHandler; + int _messageOrder{ 0 }; // Version handler for WorldWide Telescope messages + }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b49a06bddc..02421ca2b6 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -53,12 +53,15 @@ namespace openspace::skybrowser::luascriptfunctions { ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); // If the image has coordinates, move the target - if (image.hasCelestCoords && selectedTarget) { + if (image.hasCelestialCoords && selectedTarget) { + // Animate the target to the image coord position selectedTarget->unlock(); - selectedTarget->startAnimation(image.celestCoords, image.fov); + glm::dvec3 equatorial = skybrowser::sphericalToCartesian(image.celestialCoords); + selectedTarget->startAnimation(equatorial, image.fov); + // Check if image coordinate is within current FOV - glm::dvec3 coordsScreen = J2000SphericalToScreenSpace(image.celestCoords); + glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); float r = windowRatio.x / windowRatio.y; bool coordIsWithinView = (abs(coordsScreen.x) < r && @@ -66,7 +69,8 @@ namespace openspace::skybrowser::luascriptfunctions { bool coordIsBehindCamera = coordsScreen.z > 0; // If the coordinate is not in view, rotate camera if (!coordIsWithinView || coordIsBehindCamera) { - module->startRotation(image.celestCoords); + glm::dvec3 galactic = skybrowser::equatorialToGalactic(equatorial); + module->startRotation(galactic); } } } @@ -95,13 +99,14 @@ namespace openspace::skybrowser::luascriptfunctions { const ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; // Only move and show circle if the image has coordinates - if (image.hasCelestCoords && module->cameraInSolarSystem()) { + if (image.hasCelestialCoords && module->cameraInSolarSystem()) { // Make circle visible ScreenSpaceImageLocal* hoverCircle = dynamic_cast( global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(true); // Calculate coords for the circle and translate - glm::vec3 coordsScreen = skybrowser::J2000SphericalToScreenSpace(image.celestCoords); + glm::dvec3 equatorialCartesian = skybrowser::sphericalToCartesian(image.celestialCoords); + glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace(equatorialCartesian); hoverCircle->property("CartesianPosition")->set(coordsScreen); } @@ -152,12 +157,12 @@ namespace openspace::skybrowser::luascriptfunctions { const int i = ghoul::lua::value(L, 2); int order = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - int version = module->getAndIncrementLayerOrder(); + int version = module->getAndIncrementMessageOrder(); if (module->browserIdExists(browserId)) { ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; - browser->setImageLayerOrder(i, order, version); + browser->setImageOrder(i, order, version); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( @@ -180,9 +185,9 @@ namespace openspace::skybrowser::luascriptfunctions { ScreenSpaceSkyBrowser* browser = dynamic_cast( global::renderEngine->screenSpaceRenderable(id)); - if (browser && !browser->hasLoadedCollections()) { - browser->sendMessageToWWT(wwtmessage::loadCollection(root)); - browser->setHasLoadedCollections(true); + if (browser && !browser->hasLoadedImages()) { + browser->sendMessageToWwt(wwtmessage::loadCollection(root)); + browser->setHasLoadedImages(true); } else { SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); @@ -191,9 +196,9 @@ namespace openspace::skybrowser::luascriptfunctions { node->renderable()); if (browser3d) { // Load Image collections - browser3d->stopConnectingToWwt(); + browser3d->stopSyncingWwtView(); LINFO("Load images to " + browser3d->identifier()); - browser3d->sendMessageToWWT(wwtmessage::loadCollection(root)); + browser3d->sendMessageToWwt(wwtmessage::loadCollection(root)); LINFO("Image collection loaded in " + browser3d->identifier()); } } @@ -210,7 +215,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); std::map browsers = module->getSkyBrowsers(); for (std::pair pair : browsers) { - pair.second->setIdInBrowser(); + pair.second->sendIdToBrowser(); } SceneGraphNode* node = module->get3dBrowser(); if(node) { @@ -228,15 +233,17 @@ namespace openspace::skybrowser::luascriptfunctions { // Find the ScreenSpaceRenderable that has the id ScreenSpaceRenderable* found = global::renderEngine->screenSpaceRenderable(id); + ScreenSpaceSkyBrowser* browser = dynamic_cast(found); + ScreenSpaceSkyTarget* target = dynamic_cast(found); // Connect it to its corresponding target / browser - if (dynamic_cast(found)) { - ScreenSpaceSkyBrowser* browser = dynamic_cast(found); - browser->setConnectedTarget(); + if (browser) { + + browser->connectToSkyTarget(); } - else if (dynamic_cast(found)) { - ScreenSpaceSkyTarget* target = dynamic_cast(found); - target->initializeWithBrowser(); + else if (target) { + + target->findSkyBrowser(); } return 0; } @@ -247,12 +254,12 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string id = ghoul::lua::value(L, 1); ScreenSpaceSkyBrowser* browser = dynamic_cast( global::renderEngine->screenSpaceRenderable(id)); - LINFO("Initializing sky browsers"); + LINFO("Initializing sky browser " + id); if (browser) { browser->initializeBrowser(); ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { - target->initializeWithBrowser(); + target->findSkyBrowser(); } } else { @@ -263,7 +270,7 @@ namespace openspace::skybrowser::luascriptfunctions { if (browser3d && id == node->identifier()) { // Initialize LINFO("Initializing 3D sky browsers"); - browser3d->connectToWwt(); + browser3d->syncWwtView(); } } } @@ -315,7 +322,7 @@ namespace openspace::skybrowser::luascriptfunctions { for (int i = 0; i < images.size(); i++) { std::string name = images[i].name != "" ? images[i].name : "undefined"; std::string thumbnail = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; - glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestCoords); + glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestialCoords); std::vector cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z }; glm::dvec3 position = images[i].position3d; std::vector position3d = { position.x, position.y, position.z }; @@ -328,13 +335,13 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "thumbnail", thumbnail); lua_settable(L, -3); - ghoul::lua::push(L, "ra", images[i].celestCoords.x); + ghoul::lua::push(L, "ra", images[i].celestialCoords.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", images[i].celestCoords.y); + ghoul::lua::push(L, "dec", images[i].celestialCoords.y); lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); lua_settable(L, -3); - ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestCoords); + ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestialCoords); lua_settable(L, -3); ghoul::lua::push(L, "credits", images[i].credits); lua_settable(L, -3); @@ -364,7 +371,7 @@ namespace openspace::skybrowser::luascriptfunctions { // Add the window data for OpenSpace ghoul::lua::push(L, "OpenSpace"); lua_newtable(L); - glm::dvec3 cartesianJ2000 = skybrowser::cameraDirectionJ2000Cartesian(); + glm::dvec3 cartesianJ2000 = skybrowser::cameraDirectionEquatorial(); glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000); // Convert to vector so ghoul can read it std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; @@ -400,18 +407,19 @@ namespace openspace::skybrowser::luascriptfunctions { std::string id = pair.first; // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - std::deque selectedImages = browser->selectedImages(); - std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { - selectedImagesVector.push_back(index); + std::deque selectedImages = browser->getSelectedImages(); + std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) { + selectedImagesVector.push_back(i); }); // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { - glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial(); - glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical); + glm::dvec3 celestialCart = target->targetDirectionEquatorial(); + glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); + std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; // Convert color to vector so ghoul can read it - glm::ivec3 color = browser->_borderColor.value(); + glm::ivec3 color = browser->borderColor(); std::vector colorVec = { color.r, color.g, color.b }; ghoul::lua::push(L, id); @@ -421,7 +429,7 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "name", browser->guiName()); lua_settable(L, -3); - ghoul::lua::push(L, "FOV", browser->fieldOfView()); + ghoul::lua::push(L, "FOV", browser->verticalFov()); lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); @@ -447,12 +455,12 @@ namespace openspace::skybrowser::luascriptfunctions { node->renderable()); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - std::deque selectedImages = browser3d->selectedImages(); + std::deque selectedImages = browser3d->getSelectedImages(); std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { selectedImagesVector.push_back(index); }); glm::dvec3 worldPosition = node->position(); - glm::dvec3 celestialCart = skybrowser::galacticCartesianToJ2000Cartesian(worldPosition); + glm::dvec3 celestialCart = skybrowser::galacticToEquatorial(worldPosition); glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; // Convert color to vector so ghoul can read it @@ -466,7 +474,7 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "name", node->guiName()); lua_settable(L, -3); - ghoul::lua::push(L, "FOV", browser3d->fieldOfView()); + ghoul::lua::push(L, "FOV", browser3d->verticalFov()); lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); @@ -496,7 +504,8 @@ namespace openspace::skybrowser::luascriptfunctions { if(module->cameraInSolarSystem() && module->browserIdExists(id)) { ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); if (target) { - module->startRotation(target->getTargetDirectionCelestial()); + glm::dvec3 cartesian = target->targetDirectionEquatorial(); + module->startRotation(skybrowser::equatorialToGalactic(cartesian)); } } else if (!module->cameraInSolarSystem() && id3dBrowser == id) { @@ -516,9 +525,9 @@ namespace openspace::skybrowser::luascriptfunctions { RenderableSkyBrowser* browser3d = dynamic_cast( module->get3dBrowser()->renderable()); // Empty 3D browser selection - browser3d->selectedImages().clear(); + browser3d->getSelectedImages().clear(); // Copy 2D selection of images to 3D browser - std::deque images = browser->selectedImages(); + std::deque images = browser->getSelectedImages(); std::for_each(std::begin(images), std::end(images), [&](int index) { ImageData& image = module->getWWTDataHandler()->getLoadedImages()[index]; browser3d->displayImage(image, index); @@ -534,15 +543,15 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string i = std::to_string(ghoul::lua::value(L, 2)); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - ghoul::Dictionary message = wwtmessage::setLayerOpacity(i, opacity); + ghoul::Dictionary message = wwtmessage::setImageOpacity(i, opacity); if (module->browserIdExists(browserId)) { - module->getSkyBrowsers()[browserId]->sendMessageToWWT(message); + module->getSkyBrowsers()[browserId]->sendMessageToWwt(message); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( module->get3dBrowser()->renderable()); - browser3d->sendMessageToWWT(message); + browser3d->sendMessageToWwt(message); } return 0; @@ -558,12 +567,10 @@ namespace openspace::skybrowser::luascriptfunctions { // Animate the target to the center of the screen browser->getSkyTarget()->unlock(); // Get camera direction in celestial spherical coordinates - glm::dvec3 viewDirection = skybrowser::cameraDirectionJ2000Cartesian(); - glm::dvec2 centerOfScreen = skybrowser::cartesianToSpherical( - viewDirection); + glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); // Keep the current fov - float fov = browser->fieldOfView(); - browser->getSkyTarget()->startAnimation(centerOfScreen, fov, false); + float fov = browser->verticalFov(); + browser->getSkyTarget()->startAnimation(viewDirection, fov, false); browser->getSkyTarget()->unlock(); } } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index a284c25a43..4b01031b52 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -68,8 +68,8 @@ namespace openspace { , _url(UrlInfo) , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) , _reload(ReloadInfo) - , _fov(70.f) - , _connectToWwt(false) + , _verticalFov(70.f) + , _syncViewWithWwt(false) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -182,22 +182,22 @@ namespace openspace { } } - bool RenderableSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) { + bool RenderableSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) { std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; executeJavascript(script); return true; } void RenderableSkyBrowser::displayImage(ImageData& image, int i) { - sendMessageToWWT(wwtmessage::moveCamera(image.celestCoords, image.fov, 0.0)); - _fov = image.fov; + sendMessageToWwt(wwtmessage::moveCamera(image.celestialCoords, image.fov, 0.0)); + _verticalFov = image.fov; // Add to selected images if there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it == std::end(_selectedImages)) { // Push newly selected image to front _selectedImages.push_front(i); // Create image layer and center WWT app on the image - sendMessageToWWT(wwtmessage::createImageLayer(std::to_string(i), image.imageUrl)); + sendMessageToWwt(wwtmessage::addImage(std::to_string(i), image.imageUrl)); LINFO("Image has been loaded to " + identifier()); } } @@ -207,7 +207,7 @@ namespace openspace { auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it != std::end(_selectedImages)) { _selectedImages.erase(it); - sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i))); + sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); } } @@ -216,22 +216,22 @@ namespace openspace { executeJavascript("setId('" + id + "')"); } - float RenderableSkyBrowser::fieldOfView() const { - return _fov; + float RenderableSkyBrowser::verticalFov() const { + return _verticalFov; } - void RenderableSkyBrowser::connectToWwt() { + void RenderableSkyBrowser::syncWwtView() { // If the camera is already synced, the browser is already initialized - if (!_connectToWwt) { - _connectToWwt = true; + if (!_syncViewWithWwt) { + _syncViewWithWwt = true; // Start a thread to enable user interaction while sending the calls to WWT _threadWwtMessages = std::thread([&] { - while (_connectToWwt) { + while (_syncViewWithWwt) { glm::dvec2 aim{ 0.0 }; // Send a message just to establish contact - ghoul::Dictionary message = wwtmessage::moveCamera(aim, _fov, 0.0); - sendMessageToWWT(message); + ghoul::Dictionary message = wwtmessage::moveCamera(aim, _verticalFov, 0.0); + sendMessageToWwt(message); // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(500)); @@ -241,15 +241,15 @@ namespace openspace { } - void RenderableSkyBrowser::stopConnectingToWwt() { - _connectToWwt = false; + void RenderableSkyBrowser::stopSyncingWwtView() { + _syncViewWithWwt = false; if (_threadWwtMessages.joinable()) { _threadWwtMessages.join(); } } - std::deque& RenderableSkyBrowser::selectedImages() { + std::deque& RenderableSkyBrowser::getSelectedImages() { return _selectedImages; } @@ -267,7 +267,7 @@ namespace openspace { int reverseOrder = _selectedImages.size() - order - 1; ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), reverseOrder, version); - sendMessageToWWT(message); + sendMessageToWwt(message); } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 6d42f2fa09..2ebcce44e7 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -30,26 +30,27 @@ namespace { constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = { "BrowserDimensions", - "Browser Dimensions Info", - "Set the dimensions of the SkyTarget according to the SkyBrowser ratio " + "Browser Dimensions", + "The pixel dimensions of the sky browser." }; - constexpr const openspace::properties::Property::PropertyInfo ZoomInfo = + constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = { - "Zoom", - "Zoom Info", - "tjobidabidobidabidopp plupp" + "VerticalFieldOfView", + "Vertical Field Of View", + "The vertical field of view in degrees." }; - constexpr const openspace::properties::Property::PropertyInfo TargetIDInfo = + constexpr const openspace::properties::Property::PropertyInfo TargetIdInfo = { - "TargetID", - "Target Info", - "tjobidabidobidabidopp plupp" + "TargetId", + "Target Id", + "The identifier of the target. It is used to synchronize the sky browser and the" + "sky target." }; constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = { "BorderColor", - "Border color Info", - "tjobidabidobidabidopp plupp" + "Border Color", + "The color of the border of the sky browser as well as the sky target." }; @@ -58,14 +59,14 @@ namespace { // [[codegen::verbatim(BrowserDimensionInfo.description)]] std::optional browserDimensions; - // [[codegen::verbatim(ZoomInfo.description)]] - std::optional zoom; + // [[codegen::verbatim(VerticalFovInfo.description)]] + std::optional verticalFov; - // [[codegen::verbatim(TargetIDInfo.description)]] - std::optional targetID; + // [[codegen::verbatim(TargetIdInfo.description)]] + std::optional targetId; // [[codegen::verbatim(BorderColorInfo.description)]] - std::optional borderColor; + std::optional borderColor; }; #include "screenspaceskybrowser_codegen.cpp" @@ -76,47 +77,44 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0), glm::ivec2(300)) - , _vfieldOfView(ZoomInfo, 10.f, 0.1f, 70.f) - , _borderColor(BorderColorInfo, glm::ivec3(rand() % 256, rand() % 256, rand() % 256)) - , _skyTargetID(TargetIDInfo) - , _camIsSyncedWWT(false) - , _skyTarget(nullptr) + , _verticalFov(VerticalFovInfo, 10.f, 0.1f, 70.f) + , _borderColor(BorderColorInfo, glm::vec3(rand() % 256, rand() % 256, rand() % 256)) + , _skyTargetId(TargetIdInfo) { - // Ensure the color of the border is bright enough. - // Make sure the RGB color at least is 50% brightness - // By making each channel 50% bright in general - // 222 = sqrt(3*(0.5*256)^2) - while (glm::length(_borderColor.value()) < 222) { - _borderColor = glm::ivec3(rand() % 256, rand() % 256, rand() % 256); - } + // Make the color property display a color picker in the GUI + _borderColor.setViewOption("Color", true); // Handle target dimension property const Parameters p = codegen::bake(dictionary); _browserDimensions = p.browserDimensions.value_or(_browserDimensions); - _browserDimensions.onChange([&]() { - if(_skyTarget) { - glm::vec2 dim = getBrowserPixelDimensions(); + _verticalFov = p.verticalFov.value_or(_verticalFov); + _borderColor = p.borderColor.value_or(_borderColor); + _skyTargetId = p.targetId.value_or(_skyTargetId); + + addProperty(_browserDimensions); + addProperty(_verticalFov); + addProperty(_borderColor); + addProperty(_skyTargetId); + + _browserDimensions.onChange([&]() { + if (_skyTarget) { + glm::vec2 dim = browserPixelDimensions(); _skyTarget->setDimensions(dim); } }); - addProperty(_browserDimensions); - - _vfieldOfView = p.zoom.value_or(_vfieldOfView); - addProperty(_vfieldOfView); - - _skyTargetID = p.targetID.value_or(_skyTargetID); - addProperty(_skyTargetID); - - _skyTargetID.onChange([&]() { - setConnectedTarget(); - }); - - _vfieldOfView.onChange([&]() { + _verticalFov.onChange([&]() { if (_skyTarget) { - _skyTarget->setVerticalFOV(_vfieldOfView); + _skyTarget->setScale(_verticalFov); } }); - + _borderColor.onChange([&]() { + setWebpageBorderColor(_borderColor.value()); + }); + _skyTargetId.onChange([&]() { + connectToSkyTarget(); + }); + + // Set a unique identifier std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -127,7 +125,8 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - _cartesianPosition.setValue(glm::dvec3(_cartesianPosition.value().x, _cartesianPosition.value().y, skybrowser::SCREENSPACE_Z)); + glm::vec2 screenPosition = _cartesianPosition.value(); + _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); // Always make sure that the target and browser are visible together _enabled.onChange([&]() { @@ -135,13 +134,21 @@ namespace openspace { _skyTarget->property("Enabled")->set(_enabled.value()); } }); + + // Ensure the color of the border is bright enough. + // Make sure the RGB color at least is 50% brightness + // By making each channel 50% bright in general + // 222 = sqrt(3*(0.5*256)^2) + while (glm::length(_borderColor.value()) < 222) { + _borderColor = glm::vec3(rand() % 256, rand() % 256, rand() % 256); + } } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { // Set flag to false so the thread can exit - _camIsSyncedWWT = false; - if (_threadWWTMessages.joinable()) { - _threadWWTMessages.join(); + _syncViewWithWwt = false; + if (_threadWwtMessages.joinable()) { + _threadWwtMessages.join(); LINFO("Joined thread"); } } @@ -150,38 +157,39 @@ namespace openspace { return ScreenSpaceBrowser::initializeGL(); } - void ScreenSpaceSkyBrowser::setIdInBrowser() { + void ScreenSpaceSkyBrowser::sendIdToBrowser() { // Send ID to it's browser executeJavascript("setId('" + identifier() + "')"); } void ScreenSpaceSkyBrowser::initializeBrowser() { // If the camera is already synced, the browser is already initialized - if (!_camIsSyncedWWT) { - _camIsSyncedWWT = true; + if (!_syncViewWithWwt) { + _syncViewWithWwt = true; // Set border color - setBorderColor(_borderColor.value()); + setWebpageBorderColor(_borderColor.value()); // Connect to target if they haven't been connected if (!_skyTarget) { - setConnectedTarget(); + connectToSkyTarget(); } // Track target - WWTfollowCamera(); + syncWwtView(); } } bool ScreenSpaceSkyBrowser::deinitializeGL() { // Set flag to false so the thread can exit - _camIsSyncedWWT = false; - if (_threadWWTMessages.joinable()) { - _threadWWTMessages.join(); + _syncViewWithWwt = false; + if (_threadWwtMessages.joinable()) { + _threadWwtMessages.join(); LINFO("Joined thread"); } return ScreenSpaceBrowser::deinitializeGL(); } - bool ScreenSpaceSkyBrowser::setConnectedTarget() { - _skyTarget = dynamic_cast(global::renderEngine->screenSpaceRenderable(_skyTargetID.value())); + bool ScreenSpaceSkyBrowser::connectToSkyTarget() { + _skyTarget = dynamic_cast( + global::renderEngine->screenSpaceRenderable(_skyTargetId.value())); return _skyTarget; } @@ -189,72 +197,81 @@ namespace openspace { return _skyTarget; } - bool ScreenSpaceSkyBrowser::hasLoadedCollections() { - return _hasLoadedCollections; + bool ScreenSpaceSkyBrowser::hasLoadedImages() const { + return _hasLoadedImages; } - void ScreenSpaceSkyBrowser::setHasLoadedCollections(bool isLoaded) { - _hasLoadedCollections = isLoaded; + void ScreenSpaceSkyBrowser::setHasLoadedImages(bool isLoaded) { + _hasLoadedImages = isLoaded; } - float ScreenSpaceSkyBrowser::fieldOfView() const { - return _vfieldOfView; + void ScreenSpaceSkyBrowser::setVerticalFov(float vfov) { + _verticalFov = vfov; } - void ScreenSpaceSkyBrowser::setVerticalFieldOfView(float fov) { - _vfieldOfView = fov; - } - - void ScreenSpaceSkyBrowser::scrollZoom(float scroll) { + void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { // Cap how often the zoom is allowed to update std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - if (now - _lastUpdateTime > TimeUpdateInterval) { + std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; + + if (timeSinceLastUpdate > _timeUpdateInterval) { // Make scroll more sensitive the smaller the FOV - float x = _vfieldOfView; + float x = _verticalFov; float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f); + _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); _lastUpdateTime = std::chrono::system_clock::now(); } } - void ScreenSpaceSkyBrowser::executeJavascript(std::string script) const { - //LINFOC(_loggerCat, "Executing javascript " + script); - if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) { + void ScreenSpaceSkyBrowser::executeJavascript(std::string script) { + // Make sure that the browser has a main frame + bool browserExists = _browserInstance && _browserInstance->getBrowser(); + bool frameIsLoaded = browserExists && + _browserInstance->getBrowser()->GetMainFrame(); + + if (frameIsLoaded) { CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); frame->ExecuteJavaScript(script, frame->GetURL(), 0); } } - glm::ivec3 ScreenSpaceSkyBrowser::getColor() { + glm::ivec3 ScreenSpaceSkyBrowser::borderColor() const { return _borderColor.value(); } - void ScreenSpaceSkyBrowser::setBorderColor(glm::ivec3 col) { - std::string stringColor = std::to_string(col.x) + "," + std::to_string(col.y) + "," + std::to_string(col.z); - std::string script = "document.body.style.backgroundColor = 'rgb(" + stringColor + ")';"; + float ScreenSpaceSkyBrowser::verticalFov() const { + return _verticalFov.value(); + } + + void ScreenSpaceSkyBrowser::setWebpageBorderColor(glm::ivec3 color) { + std::string stringColor = std::to_string(color.x) + "," + + std::to_string(color.y) + "," + std::to_string(color.z); + std::string script = "document.body.style.backgroundColor = 'rgb(" + + stringColor + ")';"; executeJavascript(script); } - bool ScreenSpaceSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) { + void ScreenSpaceSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) { std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; executeJavascript(script); - return true; } - void ScreenSpaceSkyBrowser::WWTfollowCamera() { + void ScreenSpaceSkyBrowser::syncWwtView() { // Start a thread to enable user interaction while sending the calls to WWT - _threadWWTMessages = std::thread([&] { - while (_camIsSyncedWWT) { - if (_skyTarget) { - glm::dvec2 aim = _skyTarget->getTargetDirectionCelestial(); - // Calculate roll between up vector of camera and J2000 equatorial north - glm::dvec3 upVector = global::navigationHandler->camera()->lookUpVectorWorldSpace(); - glm::dvec3 viewVector = global::navigationHandler->camera()->viewDirectionWorldSpace(); - double roll = skybrowser::calculateRoll(upVector, viewVector); - ghoul::Dictionary message = wwtmessage::moveCamera(aim, _vfieldOfView, roll); - sendMessageToWWT(message); + _threadWwtMessages = std::thread([&] { + while (_syncViewWithWwt) { + if (_skyTarget) { + // Message WorldWide Telescope current view + glm::dvec3 cartesian = _skyTarget->targetDirectionEquatorial(); + + ghoul::Dictionary message = wwtmessage::moveCamera( + skybrowser::cartesianToSpherical(cartesian), + _verticalFov, + skybrowser::cameraRoll() + ); + sendMessageToWwt(message); } // Sleep so we don't bombard WWT with too many messages @@ -264,23 +281,24 @@ namespace openspace { } - /* - void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { - glm::vec3 position = _cartesianPosition; - _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); - }*/ + // + //void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { + // glm::vec3 position = _cartesianPosition; + // _cartesianPosition =glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); + //} - glm::vec2 ScreenSpaceSkyBrowser::coordIsOnResizeArea(glm::vec2 coord) { + glm::vec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 screenSpaceCoord) { glm::vec2 resizePosition = glm::vec2{ 0 }; - // Make sure coord is on browser - if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; + // Make sure coordinate is on browser + if (!coordIsInsideCornersScreenSpace(screenSpaceCoord)) return resizePosition; - float resizeButtonSize = 0.1f; - - bool isOnTop = coord.y > getUpperRightCornerScreenSpace().y - (getScreenSpaceDimensions().y * resizeButtonSize); - bool isOnBottom = coord.y < getLowerLeftCornerScreenSpace().y + (getScreenSpaceDimensions().y * resizeButtonSize); - bool isOnRight = coord.x > getUpperRightCornerScreenSpace().x - (getScreenSpaceDimensions().x * resizeButtonSize); - bool isOnLeft = coord.x < getLowerLeftCornerScreenSpace().x + (getScreenSpaceDimensions().x * resizeButtonSize); + float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; + float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; + + bool isOnTop = screenSpaceCoord.y > upperRightCornerScreenSpace().y - resizeAreaY; + bool isOnBottom = screenSpaceCoord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; + bool isOnRight = screenSpaceCoord.x > upperRightCornerScreenSpace().x - resizeAreaX; + bool isOnLeft = screenSpaceCoord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; resizePosition.x = isOnRight ? 1.f : isOnLeft ? -1.f : 0.f; resizePosition.y = isOnTop ? 1.f : isOnBottom ? -1.f : 0.f; @@ -288,13 +306,13 @@ namespace openspace { return resizePosition; } // Scales the ScreenSpaceBrowser to a new ratio - void ScreenSpaceSkyBrowser::scale(glm::vec2 scalingFactor) { + void ScreenSpaceSkyBrowser::setScale(glm::vec2 scalingFactor) { // Scale on the y axis, this is to ensure that _scale = 1 is // equal to the height of the window - scale(abs(scalingFactor.y)); + setScale(abs(scalingFactor.y)); // Resize the dimensions of the texture on the x axis - glm::vec2 newSize = abs(scalingFactor) * _startDimensionsSize; + glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; _texture->setDimensions(glm::ivec3(newSize, 1)); _objectSize = _texture->dimensions(); _browserDimensions = newSize; @@ -303,8 +321,9 @@ namespace openspace { glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { // To ensure the plane has the right ratio // The _scale tells us how much of the windows height the - // browser covers: eg a browser that covers 0.25 of the + // browser covers: e.g. a browser that covers 0.25 of the // height of the window will have scale = 0.25 + float textureRatio = static_cast(_texture->dimensions().x) / static_cast(_texture->dimensions().y); @@ -316,19 +335,19 @@ namespace openspace { } void ScreenSpaceSkyBrowser::saveResizeStartSize() { - _startDimensionsSize = glm::vec2(_dimensions.value().x, _dimensions.value().y); - _startScale = _scale.value(); + _originalDimensions = _dimensions.value(); + _originalScale = _scale.value(); } // Updates the browser size to match the size of the texture void ScreenSpaceSkyBrowser::updateBrowserSize() { _dimensions = _texture->dimensions(); } - void ScreenSpaceSkyBrowser::scale(float scalingFactor) { - _scale = _startScale * scalingFactor; + void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { + _scale = _originalScale * scalingFactor; } - glm::vec2 ScreenSpaceSkyBrowser::getBrowserPixelDimensions() { + glm::vec2 ScreenSpaceSkyBrowser::browserPixelDimensions() const { return _browserDimensions.value(); } @@ -336,45 +355,62 @@ namespace openspace { return _opacity; } - std::deque& ScreenSpaceSkyBrowser::selectedImages() { + std::deque& ScreenSpaceSkyBrowser::getSelectedImages() { return _selectedImages; } void ScreenSpaceSkyBrowser::addSelectedImage(ImageData& image, int i) { // Ensure there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it == std::end(_selectedImages)) { + bool found = it != std::end(_selectedImages); + if (!found) { // Push newly selected image to front _selectedImages.push_front(i); // Index of image is used as layer ID as it is unique in the image data set - sendMessageToWWT(wwtmessage::createImageLayer(std::to_string(i), image.imageUrl)); - sendMessageToWWT(wwtmessage::setLayerOpacity(std::to_string(i), 1.0)); + sendMessageToWwt(wwtmessage::addImage(std::to_string(i), image.imageUrl)); + sendMessageToWwt(wwtmessage::setImageOpacity(std::to_string(i), 1.0)); } } void ScreenSpaceSkyBrowser::removeSelectedImage(ImageData& image, int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it != std::end(_selectedImages)) { + bool found = it != std::end(_selectedImages); + if (found) { _selectedImages.erase(it); - sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i))); + sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); } } - void ScreenSpaceSkyBrowser::setImageLayerOrder(int i, int order, int version) { - // Remove from selected list - auto current = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + void ScreenSpaceSkyBrowser::setImageOrder(int i, int order, int version) { + + // Find the selected image + auto selected = std::find( + std::begin(_selectedImages), + std::end(_selectedImages), + i + ); + + // Find the target for the swap auto target = std::begin(_selectedImages) + order; - // Make sure the image was found in the list - if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { + // Make sure the selected and the target placement was found in the list + bool foundSelected = selected != std::end(_selectedImages); + bool foundTarget = target != std::end(_selectedImages); + + if (foundSelected && foundTarget) { // Swap the two images - std::iter_swap(current, target); + std::iter_swap(selected, target); } + // The images in the selected list are displayed in the reverse order from how the + // WorldWide Telescope application sees them int reverseOrder = _selectedImages.size() - order - 1; - ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), - reverseOrder, version); - sendMessageToWWT(message); + ghoul::Dictionary message = wwtmessage::setLayerOrder( + std::to_string(i), + reverseOrder, + version + ); + sendMessageToWwt(message); } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 2bb5fa5261..d422b6cbcd 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -74,7 +74,7 @@ namespace { namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _skyBrowserID(BrowserIDInfo) + , _skyBrowserId(BrowserIDInfo) , _skyBrowser(nullptr) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) @@ -82,17 +82,17 @@ namespace openspace { { // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _skyBrowserID = p.browserID.value_or(_skyBrowserID); + _skyBrowserId = p.browserID.value_or(_skyBrowserId); _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); - addProperty(_skyBrowserID); + addProperty(_skyBrowserId); addProperty(_showCrosshairThreshold); addProperty(_showRectangleThreshold); // If the ID changes for the corresponding browser, update - _skyBrowserID.onChange([&]() { - initializeWithBrowser(); + _skyBrowserId.onChange([&]() { + findSkyBrowser(); }); // Always make sure that the target and browser are visible together @@ -115,14 +115,14 @@ namespace openspace { // Set the position to screen space z glm::dvec3 startPos{ _cartesianPosition.value().x, _cartesianPosition.value().y, - skybrowser::SCREENSPACE_Z }; + skybrowser::ScreenSpaceZ }; _cartesianPosition.setValue(startPos); } ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { - if (_lockTargetThread.joinable()) { - _lockTargetThread.join(); + if (_lockTarget.joinable()) { + _lockTarget.join(); } } @@ -131,13 +131,18 @@ namespace openspace { } - void ScreenSpaceSkyTarget::initializeWithBrowser() { + bool ScreenSpaceSkyTarget::findSkyBrowser() { _skyBrowser = dynamic_cast( - global::renderEngine->screenSpaceRenderable(_skyBrowserID.value())); + global::renderEngine->screenSpaceRenderable(_skyBrowserId.value())); + matchAppearanceToSkyBrowser(); + return _skyBrowser; + } + + void ScreenSpaceSkyTarget::matchAppearanceToSkyBrowser() { if (_skyBrowser) { - _color = _skyBrowser->getColor(); - _objectSize = _skyBrowser->getBrowserPixelDimensions(); - setVerticalFOV(_skyBrowser->_vfieldOfView.value()); + _color = _skyBrowser->borderColor(); + _objectSize = _skyBrowser->browserPixelDimensions(); + setScale(_skyBrowser->verticalFov()); } } @@ -156,10 +161,10 @@ namespace openspace { glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { // To ensure the plane has the right ratio - // The _scale us how much of the windows height the browser covers: eg a browser + // The _scale us how much of the windows height the browser covers: e.g. a browser // that covers 0.25 of the height of the window will have scale = 0.25 - float ratio = static_cast(_objectSize.x) / - static_cast(_objectSize.y); + glm::vec2 floatObjectSize = glm::abs(_objectSize); + float ratio = floatObjectSize.x / floatObjectSize.y; glm::mat4 scale = glm::scale( glm::mat4(1.f), @@ -186,7 +191,7 @@ namespace openspace { _color = color; } - glm::ivec3 ScreenSpaceSkyTarget::getColor() { + glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { return _color; } @@ -196,20 +201,18 @@ namespace openspace { void ScreenSpaceSkyTarget::render() { - glDisable(GL_CULL_FACE); - + bool showCrosshair = _skyBrowser->verticalFov() < _showCrosshairThreshold; + bool showRectangle = _skyBrowser->verticalFov() > _showRectangleThreshold; + glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() }; glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); float lineWidth = 0.0016f/_scale.value(); - _shader->activate(); + glDisable(GL_CULL_FACE); - bool showCrosshair = _verticalFOV < _showCrosshairThreshold; - bool showRect = _verticalFOV > _showRectangleThreshold; - glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() }; - + _shader->activate(); _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); - _shader->setUniform(_uniformCache.showRectangle, showRect); + _shader->setUniform(_uniformCache.showRectangle, showRectangle); _shader->setUniform(_uniformCache.lineWidth, lineWidth); _shader->setUniform(_uniformCache.dimensions, glm::vec2(_objectSize)); _shader->setUniform(_uniformCache.modelTransform, modelTransform); @@ -231,7 +234,7 @@ namespace openspace { _objectSize = dimensions; } - glm::dvec3 ScreenSpaceSkyTarget::getTargetDirectionGalactic() { + glm::dvec3 ScreenSpaceSkyTarget::targetDirectionGalactic() const { glm::dmat4 rotation = glm::inverse( global::navigationHandler->camera()->viewRotationMatrix()); glm::dvec4 position = glm::dvec4(_cartesianPosition.value(), 1.0); @@ -239,20 +242,26 @@ namespace openspace { return glm::normalize(rotation * position); } - void ScreenSpaceSkyTarget::setVerticalFOV(float VFOV) { - _verticalFOV = VFOV; - - // Update the scale of the target - float horizFOV = global::windowDelegate->getHorizFieldOfView(); - glm::ivec2 windowRatio = global::windowDelegate->currentWindowSize(); - float verticFOV = horizFOV * (static_cast(windowRatio.y) / static_cast(windowRatio.x)); - _scale = std::max((VFOV / verticFOV), (_showRectangleThreshold.value() / verticFOV)); + // Update the scale of the target (the height of the target in relation to the + // OpenSpace window) + void ScreenSpaceSkyTarget::setScale(float verticalFov) { + + // Calculate the vertical field of view of the OpenSpace window + float hFovOs = global::windowDelegate->getHorizFieldOfView(); + glm::vec2 windowRatio = glm::vec2(global::windowDelegate->currentWindowSize()); + float vFovOs = hFovOs * windowRatio.y / windowRatio.x; + + // Cap the scale at small scales so it is still visible + float heightRatio = verticalFov / vFovOs; + float smallestHeightRatio = _showRectangleThreshold.value() / vFovOs; + + _scale = std::max(heightRatio, smallestHeightRatio); } void ScreenSpaceSkyTarget::unlock() { _isLocked = false; - if (_lockTargetThread.joinable()) { - _lockTargetThread.join(); + if (_lockTarget.joinable()) { + _lockTarget.join(); } } @@ -261,13 +270,13 @@ namespace openspace { unlock(); } _isLocked = true; - _lockedCoords = getTargetDirectionCelestial(); + _lockedCoordinates = targetDirectionEquatorial(); // Start a thread to enable user interactions while locking target - _lockTargetThread = std::thread([&] { + _lockTarget = std::thread([&] { while (_isLocked) { - glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(_lockedCoords); - _cartesianPosition = imageCoordsScreenSpace; + glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace(_lockedCoordinates); + _cartesianPosition = coordsScreen; } }); } @@ -276,57 +285,55 @@ namespace openspace { return _isLocked; } - glm::dvec2 ScreenSpaceSkyTarget::getTargetDirectionCelestial() { + glm::dvec3 ScreenSpaceSkyTarget::targetDirectionEquatorial() const { // Calculate the galactic coordinate of the target direction - // with infinite radius - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - constexpr double infinity = std::numeric_limits::max(); - glm::dvec3 galCoord = camPos + (infinity * getTargetDirectionGalactic()); - return skybrowser::galacticCartesianToJ2000Spherical(galCoord); + // projected onto the celestial sphere + return skybrowser::screenSpaceToEquatorial(_cartesianPosition.value()); } - void ScreenSpaceSkyTarget::animateToCoord(double deltaTime) { + void ScreenSpaceSkyTarget::animateToCoordinate(double deltaTime) { if (_isAnimated) { // Find smallest angle between the two vectors - double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsEndAnimation) / (glm::length(_coordsStartAnimation) * glm::length(_coordsEndAnimation))); + double smallestAngle = std::acos(glm::dot(_animationStart, _animationEnd) / (glm::length(_animationStart) * glm::length(_animationEnd))); // Only keep animating when target is not at final position if (abs(smallestAngle) > 0.0005) { // Calculate rotation this frame double rotationAngle = smallestAngle * deltaTime * 5.0; // Create the rotation matrix - glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsEndAnimation)); + glm::dvec3 rotationAxis = glm::normalize(glm::cross(_animationStart, _animationEnd)); glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); // Rotate target direction - glm::dvec3 newDir = rotmat * glm::dvec4(_coordsStartAnimation, 1.0); - // Convert to screenspace - _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(newDir); + glm::dvec3 newDir = rotmat * glm::dvec4(_animationStart, 1.0); + // Convert to screen space + _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); // Update position - _coordsStartAnimation = glm::normalize(newDir); + _animationStart = glm::normalize(newDir); } else { // Set the exact target position - _cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsEndAnimation); + _cartesianPosition = skybrowser::equatorialToScreenSpace(_animationEnd); // Lock target when it first arrives to the position if (!_isLocked && _lockAfterAnimation) { lock(); } // When target is in position, animate the FOV until it has finished - if(animateToFOV(_FOVEndAnimation, deltaTime)) { + if(animateToFov(_vfovEndAnimation, deltaTime)) { _isAnimated = false; } } } } - bool ScreenSpaceSkyTarget::animateToFOV(float endFOV, float deltaTime) { + bool ScreenSpaceSkyTarget::animateToFov(float endFOV, float deltaTime) { if (!_skyBrowser) { - initializeWithBrowser(); + findSkyBrowser(); } if (_skyBrowser) { - double distance = static_cast(_skyBrowser->_vfieldOfView.value()) - endFOV; + double distance = static_cast(_skyBrowser->verticalFov()) - endFOV; + // If distance is too large, keep animating if (abs(distance) > 0.01) { - _skyBrowser->scrollZoom(distance); + _skyBrowser->setVerticalFovWithScroll(distance); return false; } // Animation is finished @@ -339,18 +346,22 @@ namespace openspace { return true; } - void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd, + void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfterwards) { // Save the Cartesian celestial coordinates for animation // The coordinates are Cartesian to avoid wrap-around issues - _coordsEndAnimation = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd)); - _coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian( - getTargetDirectionCelestial())); - _FOVEndAnimation = FOVEnd; + _animationEnd = glm::normalize(coordsEnd); + _animationStart = glm::normalize(targetDirectionEquatorial()); + _vfovEndAnimation = FOVEnd; _isAnimated = true; _lockAfterAnimation = lockAfterwards; } - properties::FloatProperty& ScreenSpaceSkyTarget::getOpacity() { - return _opacity; + + float ScreenSpaceSkyTarget::opacity() const { + return _opacity.value(); + } + + void ScreenSpaceSkyTarget::setOpacity(float opacity) { + _opacity = opacity; } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 6849559b0a..b83ba06a44 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -12,103 +12,118 @@ namespace openspace::skybrowser { - glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) { + glm::dvec3 sphericalToCartesian(glm::dvec2 coords) { + + glm::dvec2 coordsRadians = glm::radians(coords); glm::dvec3 cartesian = glm::dvec3( - cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), - sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD), - sin(sphericalCoords.y * DEG_TO_RAD) + cos(coordsRadians.x) * cos(coordsRadians.y), + sin(coordsRadians.x) * cos(coordsRadians.y), + sin(coordsRadians.y) ); return cartesian; } - glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) { - - double ra = atan2(cartesianCoords[1], cartesianCoords[0]); - double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1]))); + glm::dvec2 cartesianToSpherical(glm::dvec3 coord) { + // Equatorial coordinates RA = right ascension, Dec = declination + double ra = atan2(coord.y, coord.x); + double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y))); ra = ra > 0 ? ra : ra + (2 * M_PI); - return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec); + glm::dvec2 celestialCoords{ ra, dec }; + + return glm::degrees(celestialCoords); } - glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) { - return glm::transpose(conversionMatrix) * rGal; - } - - glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) { - return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal)); - } - - glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) { - glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere - return distance * rGalactic; + glm::dvec3 galacticToEquatorial(glm::dvec3 coords) { + return glm::transpose(conversionMatrix) * glm::normalize(coords); } - glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) { - glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere - return distance * rGalactic; + glm::dvec3 equatorialToGalactic(glm::dvec3 coords) { + // On the unit sphere + glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); + return rGalactic * CelestialSphereRadius; } - glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) { + glm::dvec3 galacticToScreenSpace(glm::dvec3 coords) { - glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian); - // Ensure that if the coord is behind the camera, the converted coord will be there too - double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z; + glm::dvec3 localCameraSpace = galacticToCameraLocal(coords); + // Ensure that if the coord is behind the camera, + // the converted coordinate will be there too + double zCoord = localCameraSpace.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ; // Calculate screen space coords x and y - long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z; - long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z; + double tan_x = localCameraSpace.x / localCameraSpace.z; + double tan_y = localCameraSpace.y / localCameraSpace.z; - glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y)); - glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast(std::tanl(angleCoordsLocal.x)), zCoord * static_cast(std::tanl(angleCoordsLocal.y)), zCoord); + glm::dvec3 screenSpace = glm::dvec3(zCoord * tan_x, zCoord * tan_y, zCoord); - return imageCoordsScreenSpace; + return screenSpace; + } + + glm::dvec3 screenSpaceToGalactic(glm::dvec3 coords) { + glm::dmat4 rotation = glm::inverse( + global::navigationHandler->camera()->viewRotationMatrix()); + glm::dvec4 position = glm::dvec4(coords, 1.0); + + return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius; + } + + glm::dvec3 screenSpaceToEquatorial(glm::dvec3 coords) { + // Calculate the galactic coordinate of the target direction + // projected onto the celestial sphere + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 galactic = camPos + skybrowser::screenSpaceToGalactic(coords); + + return skybrowser::galacticToEquatorial(galactic); } - glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) { + glm::dvec3 galacticToCameraLocal(glm::dvec3 coords) { // Transform vector to camera's local coordinate system glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos); glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0); - viewDirectionLocal = glm::normalize(viewDirectionLocal); - return viewDirectionLocal; + glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0); + + return glm::normalize(viewDirectionLocal); } - glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) { + glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords) { // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity); + glm::dvec3 galactic = equatorialToGalactic(coords); // Transform galactic coord to screen space - return galacticToScreenSpace(imageCoordsGalacticCartesian); + return galacticToScreenSpace(galactic); } - glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) { - // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity); - // Transform galactic coord to screen space - return galacticToScreenSpace(imageCoordsGalacticCartesian); - } + double cameraRoll() { + openspace::Camera* camera = global::navigationHandler->camera(); + glm::dvec3 upWorld = camera->lookUpVectorWorldSpace(); + glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace(); - double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld) { - glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(upWorld); - glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(forwardWorld); + glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld); + glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld); - glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NORTH_POLE); - double dotNorthUp = glm::dot(skybrowser::NORTH_POLE, camUpJ2000); + glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole); + double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000); double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000); - double roll = glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); - return roll; + + return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); } - glm::dvec3 cameraDirectionJ2000Cartesian() { + glm::dvec3 cameraDirectionEquatorial() { // Get the view direction of the screen in cartesian J2000 coordinates + return galacticToEquatorial(cameraDirectionGalactic()); + } + + glm::dvec3 cameraDirectionGalactic() { + // Get the view direction of the screen in galactic coordinates glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - constexpr double infinity = std::numeric_limits::max(); - glm::dvec3 galCoord = camPos + (infinity * global::navigationHandler->camera()->viewDirectionWorldSpace()); - glm::dvec3 cartesianJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(galCoord); - return cartesianJ2000; + glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view); + + return galCoord; } } @@ -150,7 +165,7 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary createImageLayer(const std::string& id, const std::string& url) { + ghoul::Dictionary addImage(const std::string& id, const std::string& url) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_create"s); @@ -162,7 +177,7 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary removeImageLayer(const std::string& imageId) { + ghoul::Dictionary removeImage(const std::string& imageId) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_remove"s); @@ -171,7 +186,7 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary setLayerOpacity(const std::string& imageId, double opacity) { + ghoul::Dictionary setImageOpacity(const std::string& imageId, double opacity) { using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_set"s); diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 57abb11be4..f08a4b10bd 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -20,20 +20,37 @@ namespace { namespace openspace { - WWTDataHandler::~WWTDataHandler() { - // Call destructor of all allocated xmls - xmls.clear(); + bool hasAttribute(tinyxml2::XMLElement* element, std::string name) { + return element->FindAttribute(name.c_str()); } - bool WWTDataHandler::downloadFile(std::string& url, std::string& fileDestination) { - // Get the webpage and save to file + std::string getAttribute(tinyxml2::XMLElement* element, std::string name) { + if (hasAttribute(element, name)) { + return element->FindAttribute(name.c_str())->Value(); + } + else { + return ""; + } + } + + WwtDataHandler::~WwtDataHandler() { + // Call destructor of all allocated xmls + _xmls.clear(); + } + + bool WwtDataHandler::downloadFile(std::string& url, std::string& fileDestination) { + // Get the web page and save to file HttpRequest::RequestOptions opt{ 5 }; - SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes); + SyncHttpFileDownload wtml_root( + url, fileDestination, HttpFileDownload::Overwrite::Yes + ); wtml_root.download(opt); return wtml_root.hasSucceeded(); } - void WWTDataHandler::loadWTMLCollectionsFromURL(std::string directory, std::string url, std::string fileName) { + bool WwtDataHandler::loadWtmlCollectionsFromUrl(std::string directory, + std::string url, std::string fileName) + { // Look for WWT image data folder if (!directoryExists(directory)) { std::string newDir = directory; @@ -46,7 +63,7 @@ namespace openspace { std::string file = directory + fileName + ".aspx"; if (!downloadFile(url, file)) { LINFO("Couldn't download file " + url); - return; + return false; } // Parse to XML using namespace tinyxml2; @@ -55,41 +72,52 @@ namespace openspace { XMLElement* root = doc->RootElement(); XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); + // If there are no folders, or there are folder but without urls, stop recursion - if (!element || (element && !element->FindAttribute("Url"))) { + bool folderExists = element; + bool folderContainNoUrls = folderExists && !hasAttribute(element, "Url"); + + if (!folderExists || folderContainNoUrls) { // Save the url - std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; - if (collectionName != "") { + if (hasAttribute(root, "Name")) { + std::string collectionName = getAttribute(root, "Name"); ImageCollection newCollection{ collectionName, url }; - imageUrls.push_back(newCollection); + _imageUrls.push_back(newCollection); } - xmls.push_back(doc); + _xmls.push_back(doc); LINFO("Saving " + url); - return; + return true; } // Iterate through all the folders while (element && std::string(element->Value()) == "Folder") { - // Get all attributes for the - std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : ""; - std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : ""; - if (subUrl != "" && subName != "") { - loadWTMLCollectionsFromURL(directory, subUrl, subName); + + // Get all attributes for the + if (hasAttribute(element, "Url") && hasAttribute(element, "Name")) { + std::string subUrl = getAttribute(element, "Url"); + std::string subName = getAttribute(element, "Name"); + loadWtmlCollectionsFromUrl(directory, subUrl, subName); } element = element->NextSiblingElement(); } } - bool WWTDataHandler::directoryExists(std::string& path) + bool WwtDataHandler::directoryExists(std::string& path) { struct stat info; int statRC = stat(path.c_str(), &info); if (statRC != 0) { - if (errno == ENOENT) { return false; } // something along the path does not exist - if (errno == ENOTDIR) { return false; } // something in path prefix is not a dir + // something along the path does not exist + if (errno == ENOENT) { + return false; + } + // something in path prefix is not a dir + if (errno == ENOTDIR) { + return false; + } return false; } @@ -98,43 +126,49 @@ namespace openspace { return directoryExists; } - bool WWTDataHandler::loadWTMLCollectionsFromDirectory(std::string directory) { + bool WwtDataHandler::loadWtmlCollectionsFromDirectory(std::string directory) { if (!directoryExists(directory)) return false; for (const auto& entry : std::filesystem::directory_iterator(directory)) { - tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - - if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) { - tinyxml2::XMLElement* root = doc->RootElement(); - std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; - if (collectionName != "") { - ImageCollection newCollection{collectionName, entry.path().u8string()}; - imageUrls.push_back(newCollection); + + tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument(); + std::string path = entry.path().u8string(); + tinyxml2::XMLError successCode = document->LoadFile(path.c_str()); + bool fileIsLoaded = successCode == tinyxml2::XMLError::XML_SUCCESS; + + if (fileIsLoaded) { + tinyxml2::XMLElement* root = document->RootElement(); + + if (hasAttribute(root, "Name")) { + std::string collectionName = getAttribute(root, "Name"); + ImageCollection newCollection{ collectionName, path }; + _imageUrls.push_back(newCollection); } - xmls.push_back(doc); + _xmls.push_back(document); } } return true; } std::ostream& operator<<(std::ostream& os, const ImageData& img) { - os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl; + os << "Name: " << img.name << " Coords: ra: " << img.celestialCoords.x + << " dec: " << img.celestialCoords.y << std::endl; os << "Thumbnail: " << img.thumbnailUrl << std::endl; os << "Collection: " << img.collection << std::endl << std::endl; return os; } - int WWTDataHandler::loadImagesFromLoadedXMLs() { - for (tinyxml2::XMLDocument* doc : xmls) { + int WwtDataHandler::loadImagesFromLoadedXmls() { + for (tinyxml2::XMLDocument* doc : _xmls) { tinyxml2::XMLElement* root = doc->FirstChildElement(); std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; - loadImagesFromXML(root, collectionName); + loadImagesFromXml(root, collectionName); } - // Sort images in alphabetial order - std::sort(images.begin(), images.end(), [](ImageData a, ImageData b) { - // If the first charachter in the names are lowercase, make it upper case + // Sort images in alphabetical order + std::sort(_images.begin(), _images.end(), [](ImageData a, ImageData b) { + // If the first character in the names are lowercase, make it upper case if (std::islower(a.name[0])) { // convert string to upper case a.name[0] = ::toupper(a.name[0]); @@ -144,16 +178,16 @@ namespace openspace { } return a.name < b.name; }); - LINFO(std::to_string(nImagesWith3dPositions) + " 3D positions were matched in the speck files!"); + LINFO(std::to_string(_nImagesWith3dPositions) + " 3D positions were matched in the speck files!"); - return images.size(); + return _images.size(); } - const std::vector& WWTDataHandler::getAllImageCollectionUrls() const { - return imageUrls; + const std::vector& WwtDataHandler::getAllImageCollectionUrls() const { + return _imageUrls; } - void WWTDataHandler::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) { + void WwtDataHandler::loadImagesFromXml(tinyxml2::XMLElement* node, std::string collectionName) { // Get direct child of node called "Place" using namespace tinyxml2; XMLElement* ptr = node->FirstChildElement(); @@ -171,7 +205,7 @@ namespace openspace { if (ptr->FindAttribute("Name")) { newCollectionName += std::string(ptr->FindAttribute("Name")->Value()); } - loadImagesFromXML(ptr, newCollectionName); + loadImagesFromXml(ptr, newCollectionName); } ptr = ptr->NextSiblingElement(); @@ -179,7 +213,7 @@ namespace openspace { } - int WWTDataHandler::loadImageFromXmlNode(tinyxml2::XMLElement* node, std::string collectionName) { + int WwtDataHandler::loadImageFromXmlNode(tinyxml2::XMLElement* node, std::string collectionName) { // Only load "Sky" type images if (std::string(node->FindAttribute("DataSetType")->Value()) != "Sky") return -1; @@ -195,7 +229,7 @@ namespace openspace { imageSet = node; } else if (std::string(node->Name()) == "Place") { - thumbnailUrl = getURLFromPlace(node); + thumbnailUrl = getUrlFromPlace(node); imageSet = getChildNode(node, "ImageSet"); } else { @@ -218,19 +252,19 @@ namespace openspace { ImageData image{}; setImageDataValues(node, credits, creditsUrl, thumbnailUrl, collectionName, imageUrl, image); - images.push_back(image); + _images.push_back(image); // Return index of image in vector - return images.size(); + return _images.size(); } - std::string WWTDataHandler::getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName) { + std::string WwtDataHandler::getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName) { // FInd the thumbnail image url // The thumbnail is the last node so traverse backwards for speed tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement(elementName.c_str()); return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; } - std::string WWTDataHandler::getURLFromPlace(tinyxml2::XMLElement* place) { + std::string WwtDataHandler::getUrlFromPlace(tinyxml2::XMLElement* place) { // Get thumbnail attribute, if there is one std::string url = place->FindAttribute("Thumbnail") ? place->FindAttribute("Thumbnail")->Value() : ""; // Url found! Return it @@ -244,14 +278,14 @@ namespace openspace { return imageSet ? getChildNodeContentFromImageSet(imageSet, "ThumbnailUrl") : ""; } - tinyxml2::XMLElement* WWTDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) { + tinyxml2::XMLElement* WwtDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) { while (node && std::string(node->Name()) != name) { node = node->FirstChildElement(); } return node; } - tinyxml2::XMLElement* WWTDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) { + tinyxml2::XMLElement* WwtDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) { // Traverse the children and look at all their first child to find ImageSet tinyxml2::XMLElement* child = node->FirstChildElement(); tinyxml2::XMLElement* imageSet = nullptr; @@ -263,7 +297,7 @@ namespace openspace { return imageSet; } - void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node, + void WwtDataHandler::setImageDataValues(tinyxml2::XMLElement* node, std::string credits, std::string creditsUrl, std::string thumbnail, @@ -272,11 +306,11 @@ namespace openspace { ImageData& img) { // Get attributes for the image img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; - img.hasCelestCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); - if (img.hasCelestCoords) { + img.hasCelestialCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); + if (img.hasCelestialCoords) { // The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h) = 15 - img.celestCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value()); - img.celestCoords.y = std::stof(node->FindAttribute("Dec")->Value()); + img.celestialCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value()); + img.celestialCoords.y = std::stof(node->FindAttribute("Dec")->Value()); } img.collection = collectionName; img.thumbnailUrl = thumbnail; @@ -292,15 +326,15 @@ namespace openspace { if (it != _3dPositions.end()) { img.position3d = it->second; img.has3dCoords = true; - nImagesWith3dPositions++; + _nImagesWith3dPositions++; } } - std::vector& WWTDataHandler::getLoadedImages() { - return images; + std::vector& WwtDataHandler::getLoadedImages() { + return _images; } - void WWTDataHandler::loadSpeckData(speck::Dataset& dataset) { + void WwtDataHandler::loadSpeckData(speck::Dataset& dataset) { for (speck::Dataset::Entry entry : dataset.entries) { if (entry.comment.has_value()) { std::string name = createSearchableString(entry.comment.value()); @@ -310,7 +344,7 @@ namespace openspace { LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + " entries!"); } - std::string WWTDataHandler::createSearchableString(std::string str) { + std::string WwtDataHandler::createSearchableString(std::string str) { // Remove white spaces and all special characters str.erase(std::remove_if(str.begin(), str.end(), [](char c) { bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); @@ -322,7 +356,6 @@ namespace openspace { [](unsigned char c) { return std::tolower(c); }); return str; } - } // Loading of speck files diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index a5e3172ed9..a91dff3d6c 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -498,25 +498,25 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { return scale; } -glm::vec2 ScreenSpaceRenderable::getScreenSpacePosition() { +glm::vec2 ScreenSpaceRenderable::screenSpacePosition() { return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); } -glm::vec2 ScreenSpaceRenderable::getScreenSpaceDimensions() { +glm::vec2 ScreenSpaceRenderable::screenSpaceDimensions() { return glm::vec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); } -glm::vec2 ScreenSpaceRenderable::getUpperRightCornerScreenSpace() { - return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0f); +glm::vec2 ScreenSpaceRenderable::upperRightCornerScreenSpace() { + return screenSpacePosition() + (screenSpaceDimensions() / 2.0f); } -glm::vec2 ScreenSpaceRenderable::getLowerLeftCornerScreenSpace() { - return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0f); +glm::vec2 ScreenSpaceRenderable::lowerLeftCornerScreenSpace() { + return screenSpacePosition() - (screenSpaceDimensions() / 2.0f); } bool ScreenSpaceRenderable::coordIsInsideCornersScreenSpace(glm::vec2 coord) { - bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y; - bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y; + bool lessThanUpperRight = coord.x < upperRightCornerScreenSpace().x && coord.y < upperRightCornerScreenSpace().y; + bool moreThanLowerLeft = coord.x > lowerLeftCornerScreenSpace().x && coord.y > lowerLeftCornerScreenSpace().y; return lessThanUpperRight && moreThanLowerLeft; } From d5422f429da85d0b198bdbbb1edc6462523a5bcb Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 3 Nov 2021 10:37:20 -0400 Subject: [PATCH 131/251] Restructure and clean up --- data/assets/skyBrowserTargetPair.asset | 7 +- .../skybrowser/include/renderableskybrowser.h | 9 +- .../include/screenspaceskybrowser.h | 15 +- .../skybrowser/include/screenspaceskytarget.h | 7 + modules/skybrowser/include/utility.h | 19 +- modules/skybrowser/include/wwtdatahandler.h | 97 ++- modules/skybrowser/skybrowsermodule.cpp | 634 +++++++++--------- modules/skybrowser/skybrowsermodule.h | 94 ++- modules/skybrowser/skybrowsermodule_lua.inl | 363 +++++----- .../skybrowser/src/renderableskybrowser.cpp | 62 +- .../skybrowser/src/screenspaceskybrowser.cpp | 51 +- .../skybrowser/src/screenspaceskytarget.cpp | 91 ++- modules/skybrowser/src/utility.cpp | 80 ++- modules/skybrowser/src/wwtdatahandler.cpp | 554 ++++++++------- 14 files changed, 1154 insertions(+), 929 deletions(-) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 5fde6352b3..4a741655da 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -20,17 +20,16 @@ local target = { Identifier = targetId, Name = "Sky Target", FaceCamera = false, - BrowserID = browserId, + BrowserId = browserId, }; asset.onInitialize(function () openspace.addScreenSpaceRenderable(browser) openspace.addScreenSpaceRenderable(target) - openspace.skybrowser.addToSkyBrowserModule(browserId) - openspace.skybrowser.addToSkyBrowserModule(targetId) openspace.skybrowser.connectBrowserTarget(browserId) openspace.skybrowser.connectBrowserTarget(targetId) - openspace.skybrowser.setSelectedBrowser(browserId) + openspace.skybrowser.addPairToSkyBrowserModule(targetId,browserId) + openspace.skybrowser.setSelectedBrowser(browserId) end) asset.onDeinitialize(function () diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 85daa90142..56d27923e6 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -57,18 +57,21 @@ namespace openspace { void setIdInBrowser(std::string id); // WorldWide Telescope communication - void displayImage(ImageData& image, int i); - void removeSelectedImage(ImageData& image, int i); + void displayImage(const ImageData& image, int i); + void removeSelectedImage(const ImageData& image, int i); bool sendMessageToWwt(const ghoul::Dictionary& msg); void syncWwtView(); void stopSyncingWwtView(); + // Place + void placeAt3dPosition(const ImageData& image); + // Getters float verticalFov() const; std::deque& getSelectedImages(); // Setters - void setImageLayerOrder(int i, int order, int version); + void setImageLayerOrder(int i, int order); private: // Properties diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 52d716787b..9b81cfd5d2 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace openspace { @@ -25,12 +26,14 @@ namespace openspace { // Target - browser connection bool connectToSkyTarget(); void initializeBrowser(); + glm::dvec2 fineTuneTarget(glm::dvec2 drag); // Getters returning values bool hasLoadedImages() const; glm::vec2 browserPixelDimensions() const; glm::ivec3 borderColor() const; float verticalFov() const; + glm::dvec2 fieldsOfView(); // Getters returning references ScreenSpaceSkyTarget* getSkyTarget(); @@ -49,10 +52,14 @@ namespace openspace { void executeJavascript(std::string script); void sendIdToBrowser(); + // Display + void highlight(glm::ivec3 addition); + void removeHighlight(glm::ivec3 removal); + // Communication with WorldWide Telescope - void addSelectedImage(ImageData& image, int i); - void removeSelectedImage(ImageData& image, int i); - void setImageOrder(int i, int order, int version); + void addSelectedImage(const ImageData& image, int i); + void removeSelectedImage(const ImageData& image, int i); + void setImageOrder(int i, int order); void sendMessageToWwt(const ghoul::Dictionary& msg); void syncWwtView(); @@ -75,7 +82,7 @@ namespace openspace { properties::FloatProperty _verticalFov; properties::StringProperty _skyTargetId; properties::Vec2Property _browserDimensions; - properties::Vec3Property _borderColor; + properties::IVec3Property _borderColor; // Flags bool _hasLoadedImages{ false }; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 49fd66e66f..f42484986b 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -60,11 +61,17 @@ namespace openspace { void animateToCoordinate(double deltaTime); bool animateToFov(float endFOV, float deltaTime); + // Display + void highlight(glm::ivec3 addition); + void removeHighlight(glm::ivec3 removal); + private: // Properties properties::StringProperty _skyBrowserId; properties::FloatProperty _showCrosshairThreshold; properties::FloatProperty _showRectangleThreshold; + properties::DoubleProperty _stopAnimationThreshold; + properties::DoubleProperty _animationSpeed; // Flags bool _isAnimated{ false }; diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 32069a701f..bf7627aa19 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -23,29 +23,40 @@ namespace openspace { -0.483834991775, 0.746982248696, 0.455983794523 // col 2 }); + // Galactic coordinates are projected onto the celestial sphere + // Equatorial coordinates are unit length // Conversion spherical <-> Cartesian glm::dvec2 cartesianToSpherical(glm::dvec3 coords); glm::dvec3 sphericalToCartesian(glm::dvec2 coords); // Conversion J2000 equatorial <-> galactic glm::dvec3 galacticToEquatorial(glm::dvec3 coords); - glm::dvec3 galacticToCameraLocal(glm::dvec3 coords); + glm::dvec3 galacticToLocalCamera(glm::dvec3 coords); glm::dvec3 equatorialToGalactic(glm::dvec3 coords); // Conversion J2000 equatorial / galactic <-> screen space glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords); glm::dvec3 galacticToScreenSpace(glm::dvec3 coords); - glm::dvec3 screenSpaceToGalactic(glm::dvec3 coords); - glm::dvec3 screenSpaceToEquatorial(glm::dvec3 coords); + glm::dvec3 localCameraToGalactic(glm::dvec3 coords); + glm::dvec3 localCameraToEquatorial(glm::dvec3 coords); // Camera roll and direction // Camera roll is with respect to the equatorial North Pole + bool coordinateIsOutsideView(glm::dvec3 equatorial); + float windowRatio(); double cameraRoll(); + glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate); + glm::dvec2 fovWindow(); glm::dvec3 cameraDirectionGalactic(); glm::dvec3 cameraDirectionEquatorial(); + double angleVector(glm::dvec3 start, glm::dvec3 end); + void incrementalAnimationMatrix(glm::dmat4& rotation, glm::dvec3 start, + glm::dvec3 end, double deltaTime, + double speedFactor = 1.0); } // WorldWide Telescope messages namespace wwtmessage { + inline int messageCounter{ 0 }; ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, const double roll, const bool moveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); @@ -54,7 +65,7 @@ namespace openspace { ghoul::Dictionary removeImage(const std::string& id); ghoul::Dictionary setImageOpacity(const std::string& id, double opacity); ghoul::Dictionary setForegroundOpacity(double val); - ghoul::Dictionary setLayerOrder(const std::string& id, int order, int version); + ghoul::Dictionary setLayerOrder(const std::string& id, int version); } } diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 45ab0a7a6e..97726c3512 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -4,13 +4,13 @@ #include #include #include +#include +#include // For speck loading #include #include #include #include -#include -#include namespace openspace::documentation { struct Documentation; } @@ -49,28 +49,41 @@ namespace openspace::speck { Dataset loadSpeckFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); -} // namespace openspace::speck +} // namespace openspace::speck\ + +namespace openspace::wwt { + const std::string Thumbnail = "Thumbnail"; + const std::string Name = "Name"; + const std::string ImageSet = "ImageSet"; + const std::string Dec = "Dec"; + const std::string RA = "RA"; + const std::string Undefined = ""; + const std::string Folder = "Folder"; + const std::string Place = "Place"; + const std::string ThumbnailUrl = "ThumbnailUrl"; + const std::string Url = "Url"; + const std::string Credits = "Credits"; + const std::string CreditsUrl = "CreditsUrl"; + const std::string ZoomLevel = "ZoomLevel"; + const std::string DataSetType = "DataSetType"; + const std::string Sky = "Sky"; +} // namespace openspace::wwt\ namespace openspace { - struct ImageData { - std::string name; - std::string thumbnailUrl; - std::string imageUrl; - std::string creditsUrl; - std::string credits; - glm::dvec2 celestialCoords; - std::string collection; - float fov; + struct ImageData { + std::string name{ wwt::Undefined }; + std::string thumbnailUrl{ wwt::Undefined }; + std::string imageUrl{ wwt::Undefined }; + std::string credits{ wwt::Undefined }; + std::string creditsUrl{ wwt::Undefined }; + std::string collection{ wwt::Undefined }; bool hasCelestialCoords{ false }; bool has3dCoords{ false }; - glm::dvec3 position3d; - }; - - struct ImageCollection { - std::string name; - std::string url; - bool loaded = false; + float fov{ 0.f }; + glm::dvec2 equatorialSpherical{ 0.0 }; + glm::dvec3 equatorialCartesian{ 0.0 }; + glm::dvec3 position3d{ 0.0 }; }; class WwtDataHandler { @@ -80,54 +93,24 @@ namespace openspace { WwtDataHandler() = default; ~WwtDataHandler(); - // Image downloading and xml parsing - bool loadWtmlCollectionsFromUrl(std::string directory, std::string url, - std::string fileName); - bool loadWtmlCollectionsFromDirectory(std::string directory); - int loadImagesFromLoadedXmls(); - - // Loading speck files - void loadSpeckData(speck::Dataset& dataset); - - // Getters - const std::vector& getAllImageCollectionUrls() const; - std::vector& getLoadedImages(); + void loadImages(const std::string& root, const std::string& directory, + std::vector& speckFiles); + int nLoadedImages() const; + const ImageData& getImage(const int i) const; private: - // Parsing and downloading of wtml files - bool downloadFile(std::string& url, std::string& fileDestination); - void loadImagesFromXml(tinyxml2::XMLElement* node, - std::string collectionName); - int loadImageFromXmlNode(tinyxml2::XMLElement* imageSet, - std::string collectionName); - void setImageDataValues(tinyxml2::XMLElement* node, - std::string credits, - std::string creditsUrl, - std::string thumbnail, - std::string collectionName, - std::string imageUrl, - ImageData& img); - bool directoryExists(std::string& path); + void saveImageFromNode(tinyxml2::XMLElement* node, std::string collection); + void saveImagesFromXml(tinyxml2::XMLElement* root, std::string collection); - std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, - std::string elementName); - std::string getUrlFromPlace(tinyxml2::XMLElement* place); - tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, - std::string name); - tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name); - - // Used for matching names - std::string createSearchableString(std::string name); - // Images std::vector _images; - std::vector _imageUrls; std::vector _xmls; + int _nMatched3dPositions = 0; // 3D position data loaded from speck files std::unordered_map _3dPositions; - int _nImagesWith3dPositions = 0; + }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 4c3bf15d95..d70c9b5527 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -22,28 +22,28 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include - //#include - //#include + #include +#include #include #include #include #include #include -#include -#include +#include #include -#include #include - +#include +#include #include +#include +#include #include "skybrowsermodule_lua.inl" +#include +#include // For printing glm data #include #include #include // For atan2 -#include // For printing glm data #include #include @@ -211,8 +211,8 @@ namespace openspace { "input. An input string should be the name of the system host star" }, { - "addToSkyBrowserModule", - &skybrowser::luascriptfunctions::addToSkyBrowserModule, + "add3dBrowserToSkyBrowserModule", + &skybrowser::luascriptfunctions::add3dBrowserToSkyBrowserModule, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " @@ -241,177 +241,65 @@ namespace openspace { "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" + }, + { + "addPairToSkyBrowserModule", + &skybrowser::luascriptfunctions::addPairToSkyBrowserModule, + {}, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" }, }; return res; } -// Transforms a pixel coordinate to a screen space coordinate -glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate) { - glm::vec2 size = global::windowDelegate->currentWindowSize(); - // Change origin to middle of the window - glm::vec2 screenSpacePos = glm::vec2((mouseCoordinate - (size / 2.0f))); - // Ensure the upper right corner is positive on the y axis - screenSpacePos *= glm::vec2(1.0f, -1.0f); - // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] - screenSpacePos /= (0.5f * size.y); - return screenSpacePos; -} SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) { - global::callback::mousePosition->emplace_back( - [&](double x, double y) { - - glm::vec2 pixel = glm::vec2(static_cast(x), static_cast(y)); - _mousePosition = pixelToScreenSpace(pixel); - - if (_isDragging) { - - glm::dvec2 move = _mousePosition - _startMousePosition; - - // Change view within the browser and move target accordingly to mouse drag movement - if (_fineTuneMode) { - // WWT FOV - double WWTVerticalFOV = toBrowser(_mouseOnObject)->verticalFov(); - glm::dvec2 browserDim = toBrowser(_mouseOnObject)->screenSpaceDimensions(); - double browserRatio = browserDim.x / browserDim.y; - glm::dvec2 WWTFOV = glm::dvec2(WWTVerticalFOV * browserRatio, WWTVerticalFOV); - - // OpenSpace FOV - glm::dvec2 windowDim = global::windowDelegate->currentWindowSize(); - double windowRatio = windowDim.y / windowDim.x; - double OpenSpaceHorizontalFOV = global::windowDelegate->getHorizFieldOfView(); - glm::dvec2 OpenSpaceFOV = glm::dvec2(OpenSpaceHorizontalFOV, OpenSpaceHorizontalFOV * windowRatio); - - glm::dvec2 angleResult = WWTFOV * (move / browserDim); - glm::dvec2 OSresult = angleResult / OpenSpaceFOV; - - // Calculate translation in ScreenSpaceCoordinates - glm::dvec2 screenSpaceCoord{ (2 / windowRatio), 2.f }; - glm::dvec2 result = screenSpaceCoord * OSresult; - - toBrowser(_mouseOnObject)->getSkyTarget()->translate(-result, _startDragPosition); - - } - // Move browser or target - else _mouseOnObject->translate(move, _startDragPosition); - - } - else if (_isResizing) { - // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); - glm::vec2 scalingVector = mouseDragVector * _resizeDirection; - glm::vec2 newSizeRelToOld = (_startBrowserSize + (scalingVector)) / _startBrowserSize; - // Scale the browser - toBrowser(_mouseOnObject)->setScale(newSizeRelToOld); - - // For dragging functionality, translate so it looks like the browser isn't moving - // Make sure the browser doesn't move in directions it's not supposed to - _mouseOnObject->translate(mouseDragVector * abs(_resizeDirection) / 2.f, _startDragPosition); - } - // If there is no dragging or resizing, look for new objects - else { - // Save old selection for removing highlight - ScreenSpaceRenderable* lastObj = _mouseOnObject; - - // Find and save what mouse is currently hovering on - auto currentlyOnObject = std::find_if(_renderables.begin(), _renderables.end(), [&](ScreenSpaceRenderable* obj) { - return obj && (obj->coordIsInsideCornersScreenSpace(_mousePosition) && obj->isEnabled()); - }); - _mouseOnObject = currentlyOnObject != _renderables.end() ? *currentlyOnObject : nullptr; - - // Selection has changed - if (lastObj != _mouseOnObject) { - // Remove highlight - if (toBrowser(lastObj)) { - toBrowser(lastObj)->setWebpageBorderColor(toBrowser(lastObj)->borderColor() - _highlightAddition); - } - else if (toTarget(lastObj)) { - toTarget(lastObj)->setColor(toTarget(lastObj)->borderColor() - _highlightAddition); - } - - // Add highlight - if (toBrowser(_mouseOnObject)) { - toBrowser(_mouseOnObject)->setWebpageBorderColor(toBrowser(_mouseOnObject)->borderColor() + _highlightAddition); - } - else if (toTarget(_mouseOnObject)) { - toTarget(_mouseOnObject)->setColor(toTarget(_mouseOnObject)->borderColor() + _highlightAddition); - } - } - - } - } - ); - - global::callback::mouseScrollWheel->emplace_back( - [&](double, double scroll) -> bool { - - // If mouse is on browser or target, apply zoom - if (toBrowser(_mouseOnObject)) { - toBrowser(_mouseOnObject)->setVerticalFovWithScroll(static_cast(scroll)); - return true; - } - else if (toTarget(_mouseOnObject) && toTarget(_mouseOnObject)->getSkyBrowser()) { - toTarget(_mouseOnObject)->getSkyBrowser()->setVerticalFovWithScroll(static_cast(scroll)); - } - - return false; - } - ); - global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { - if (_mouseOnObject && action == MouseAction::Press) { + if (_mouseOnPair && action == MouseAction::Press) { // Get the currently selected browser - if (toBrowser(_mouseOnObject)) { - setSelectedBrowser(toBrowser(_mouseOnObject)); - } - else if (toTarget(_mouseOnObject) && - toTarget(_mouseOnObject)->getSkyBrowser()) { - - setSelectedBrowser(toTarget(_mouseOnObject)->getSkyBrowser()); - } + setSelectedBrowser(_mouseOnPair->getBrowser()); if (button == MouseButton::Left) { - _isRotating = false; + _cameraIsRotating = false; _startMousePosition = _mousePosition; - _startDragPosition = _mouseOnObject->screenSpacePosition(); + _startDragPosition = _isBrowser ? _mouseOnPair->getBrowser()->screenSpacePosition() + : _mouseOnPair->getTarget()->screenSpacePosition(); // If current object is browser, check for resizing - if (toBrowser(_mouseOnObject)) { + if (_isBrowser) { // Resize browser if mouse is over resize button - _resizeDirection = toBrowser(_mouseOnObject)->isOnResizeArea(_mousePosition); + _resizeDirection = _mouseOnPair->getBrowser()->isOnResizeArea(_mousePosition); if (_resizeDirection != glm::vec2{ 0 }) { - toBrowser(_mouseOnObject)->saveResizeStartSize(); - _startBrowserSize = toBrowser(_mouseOnObject)->screenSpaceDimensions(); + _mouseOnPair->getBrowser()->saveResizeStartSize(); + _startBrowserSize = _mouseOnPair->getBrowser()->screenSpaceDimensions(); _isResizing = true; return true; } } // If you start dragging around the target, it should unlock - if (toTarget(_mouseOnObject)) { - toTarget(_mouseOnObject)->unlock(); + else { + _mouseOnPair->getTarget()->unlock(); } _isDragging = true; return true; - } - else if (toBrowser(_mouseOnObject) && button == MouseButton::Right) { + } + else if (_isBrowser && button == MouseButton::Right) { // If you start dragging around on the browser, the target should unlock - if (toBrowser(_mouseOnObject) && toBrowser(_mouseOnObject)->getSkyTarget()) { - toBrowser(_mouseOnObject)->getSkyTarget()->unlock(); - } + _mouseOnPair->getTarget()->unlock(); // Change view (by moving target) within browser if right mouse click on browser _startMousePosition = _mousePosition; - _startDragPosition = toBrowser(_mouseOnObject)->getSkyTarget()->screenSpacePosition(); + _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); _fineTuneMode = true; - _isDragging = true; return true; } @@ -419,12 +307,16 @@ SkyBrowserModule::SkyBrowserModule() else if (action == MouseAction::Release) { if (_isDragging) { _isDragging = false; + + return true; + } + if (_fineTuneMode) { _fineTuneMode = false; return true; } if (_isResizing) { _isResizing = false; - toBrowser(_mouseOnObject)->updateBrowserSize(); + _mouseOnPair->getBrowser()->updateBrowserSize(); return true; } } @@ -433,24 +325,80 @@ SkyBrowserModule::SkyBrowserModule() } ); + global::callback::mousePosition->emplace_back( + [&](double x, double y) { + + if (_cameraInSolarSystem) { + glm::vec2 pixel{ static_cast(x), static_cast(y) }; + _mousePosition = skybrowser::pixelToScreenSpace(pixel); + glm::vec2 translation = _mousePosition - _startMousePosition; + + if (_isDragging || _isResizing) { + if (_isResizing) { + // Calculate scaling factor + glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); + glm::vec2 scalingVector = mouseDragVector * _resizeDirection; + glm::vec2 newSizeRelToOld = (_startBrowserSize + (scalingVector)) / _startBrowserSize; + // Scale the browser + _mouseOnPair->getBrowser()->setScale(newSizeRelToOld); + + // For dragging functionality, translate so it looks like the browser + // isn't moving. Make sure the browser doesn't move in directions it's + // not supposed to + translation = mouseDragVector * abs(_resizeDirection) / 2.f; + + } + // Translate + if (_isBrowser) { + _mouseOnPair->getBrowser()->translate(translation, _startDragPosition); + } + else { + _mouseOnPair->getTarget()->translate(translation, _startDragPosition); + } + } + else if (_fineTuneMode) { + glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneTarget(translation); + _mouseOnPair->getTarget()->translate(fineTune, _startDragPosition); + } + // If there is no dragging or resizing, look for new objects + else { + setSelectedObject(); + } + } + + } + ); + + global::callback::mouseScrollWheel->emplace_back( + [&](double, double scroll) -> bool { + + // If mouse is on browser or target, apply zoom + if (_mouseOnPair) { + _mouseOnPair->getBrowser()->setVerticalFovWithScroll(static_cast(scroll)); + return true; + } + + return false; + } + ); + + global::callback::preSync->emplace_back([this]() { // Disable browser and targets when camera is outside of solar system - double solarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; double cameraSSBDistance = glm::length( global::navigationHandler->camera()->positionVec3()); - _cameraInSolarSystem = cameraSSBDistance < solarSystemRadius; - double fadingTime = 2.0; + _cameraInSolarSystem = cameraSSBDistance < _solarSystemRadius; double deltaTime = global::windowDelegate->deltaTime(); // Fade out or in browser & target - for (std::pair pair : _browsers) { - ScreenSpaceSkyBrowser* browser = pair.second; + for (SkyBrowserModule::Pair pair : _targetsBrowsers) { + ScreenSpaceSkyBrowser* browser = pair.getBrowser(); // If outside solar system and browser is visible if (!_cameraInSolarSystem && browser->isEnabled()) { - bool fadingIsFinished = fadeBrowserAndTarget(true, fadingTime, deltaTime); + bool fadingIsFinished = fadeBrowserAndTarget(true, _fadingTime, deltaTime); if (fadingIsFinished) { - browser->property("Enabled")->set(false); + pair.getBrowser()->property("Enabled")->set(false); // Select the 3D browser when moving out of the solar system if (_browser3d != nullptr) { _selectedBrowser = _browser3d->renderable()->identifier(); @@ -459,25 +407,26 @@ SkyBrowserModule::SkyBrowserModule() } // If within solar system and browser is not visible else if (_cameraInSolarSystem && !browser->isEnabled()) { - browser->property("Enabled")->set(true); + pair.getBrowser()->property("Enabled")->set(true); // Select the first 2D browser when moving into the solar system - if (_browsers.size() != 0) { - _selectedBrowser = std::begin(_browsers)->second->identifier(); + if (_targetsBrowsers.size() != 0) { + _selectedBrowser = std::begin(_targetsBrowsers)->getBrowser()->identifier(); } } // If within solar system and browser is visible if (_cameraInSolarSystem && browser->isEnabled()) { - fadeBrowserAndTarget(false, fadingTime, deltaTime); + fadeBrowserAndTarget(false, _fadingTime, deltaTime); - if (browser->getSkyTarget()) { - browser->getSkyTarget()->animateToCoordinate(deltaTime); - } + pair.getTarget()->animateToCoordinate(deltaTime); } } - if (_isRotating) { + if (_cameraIsRotating) { rotateCamera(deltaTime); } }); + + _hoverCircle = dynamic_cast( + global::renderEngine->screenSpaceRenderable("HoverCircle")); } SkyBrowserModule::~SkyBrowserModule() { @@ -508,30 +457,58 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { _dataHandler = new WwtDataHandler(); } -int SkyBrowserModule::getAndIncrementMessageOrder() { - return _messageOrder++; -} +void SkyBrowserModule::setSelectedObject() +{ + // Save old selection for removing highlight + Pair* lastObj = _mouseOnPair; -void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { - _renderables.push_back(object); - // Sort on z coordinate, objects closer to camera are in beginning of list - std::sort(_renderables.begin(), _renderables.end()); - ScreenSpaceSkyBrowser* browser = toBrowser(object); - if (browser) { - _browsers[browser->identifier()] = browser; + // Find and save what mouse is currently hovering on + auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers),[&](Pair &pair) { + bool onBrowser = pair.getBrowser()->coordIsInsideCornersScreenSpace(_mousePosition); + bool onTarget = pair.getTarget()->coordIsInsideCornersScreenSpace(_mousePosition); + if (onBrowser || onTarget) { + _mouseOnPair = &pair; + _isBrowser = onBrowser; + return true; + } + return false; + }); + + if (it == std::end(_targetsBrowsers)) { + _mouseOnPair = nullptr; + } + + + // Selection has changed + if (lastObj != _mouseOnPair) { + + // Remove highlight + if (lastObj) { + lastObj->getBrowser()->removeHighlight(_highlightAddition); + lastObj->getTarget()->removeHighlight(_highlightAddition); + } + // Add highlight to new selection + if (_mouseOnPair) { + _mouseOnPair->getBrowser()->highlight(_highlightAddition); + _mouseOnPair->getTarget()->highlight(_highlightAddition); + std::string id = _mouseOnPair->getBrowser()->identifier(); + std::string info = "Currently selected browser is " + id; + LINFO(info + id); + } + } } -bool SkyBrowserModule::browserIdExists(std::string id) { - // If the id doesn't exist, return false - if (_browsers.find(id) == _browsers.end()) { - return false; +void SkyBrowserModule::addTargetBrowserPair(ScreenSpaceSkyTarget* newTarget, ScreenSpaceSkyBrowser* newBrowser) { + // Assert pair to have both target and browser + if (newBrowser && newTarget) { + Pair newPair(newBrowser, newTarget); + _targetsBrowsers.push_back(newPair); } - return true; } void SkyBrowserModule::createTargetBrowserPair() { - int noOfPairs = static_cast(getSkyBrowsers().size()) + 1; + int noOfPairs = static_cast(_targetsBrowsers.size()) + 1; std::string nameBrowser = "Sky Browser " + std::to_string(noOfPairs); std::string nameTarget = "Sky Target " + std::to_string(noOfPairs); std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); @@ -547,7 +524,7 @@ void SkyBrowserModule::createTargetBrowserPair() { "Name = '" + nameBrowser + "'," "Url = '"+ url +"'," "FaceCamera = false," - "TargetID = '" + idTarget + "'," + "TargetId = '" + idTarget + "'," "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," "}"; const std::string target = "{" @@ -555,7 +532,7 @@ void SkyBrowserModule::createTargetBrowserPair() { "Type = 'ScreenSpaceSkyTarget'," "Name = '" + nameTarget + "'," "FaceCamera = false," - "BrowserID = '" + idBrowser + "'," + "BrowserId = '" + idBrowser + "'," "}"; openspace::global::scriptEngine->queueScript( @@ -568,16 +545,6 @@ void SkyBrowserModule::createTargetBrowserPair() { scripting::ScriptEngine::RemoteScripting::Yes ); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.addToSkyBrowserModule('" + idTarget + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.addToSkyBrowserModule('" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( "openspace.skybrowser.connectBrowserTarget('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes @@ -588,125 +555,133 @@ void SkyBrowserModule::createTargetBrowserPair() { scripting::ScriptEngine::RemoteScripting::Yes ); + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + idBrowser + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes ); } -void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) { - if (!browserIdExists(browserId)) return; +void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { - ScreenSpaceSkyBrowser* browser = _browsers[browserId]; - - // Find corresponding target - std::string targetId{ "" }; - bool hasTarget = browser->getSkyTarget(); - if (hasTarget) { - targetId = browser->getSkyTarget()->identifier(); + Pair* found = getPair(id); + if (!found) { + return; } - // Remove pointer to the renderable from browsers vector - _browsers.erase(browserId); + auto it = std::remove(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + *found); - // Remove pointer to the renderable from screenspace renderable vector - _renderables.erase(std::remove_if(std::begin(_renderables), std::end(_renderables), - [&](ScreenSpaceRenderable* renderable) { - if (renderable->identifier() == browserId) { - return true; - } - else if (renderable->identifier() == targetId) { - return true; - } - else { - return false; - } - }), std::end(_renderables)); + std::string browserId = found->getBrowser()->identifier(); + std::string targetId = found->getTarget()->identifier(); // Remove from engine openspace::global::scriptEngine->queueScript( "openspace.removeScreenSpaceRenderable('" + browserId + "');", scripting::ScriptEngine::RemoteScripting::Yes ); - if (hasTarget) { - openspace::global::scriptEngine->queueScript( - "openspace.removeScreenSpaceRenderable('" + targetId + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - } + openspace::global::scriptEngine->queueScript( + "openspace.removeScreenSpaceRenderable('" + targetId + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); - _mouseOnObject = nullptr; + _targetsBrowsers.erase(it, std::end(_targetsBrowsers)); + _mouseOnPair = nullptr; } -void SkyBrowserModule::place3dBrowser(ImageData& image) { - if (_browser3d) { - std::string id = _browser3d->identifier(); - std::string renderableId = _browser3d->renderable()->identifier(); - // Uris for properties - std::string sizeUri = "Scene." + id + "." + renderableId + ".Size"; - std::string positionUri = "Scene." + id + ".Translation.Position"; - std::string rotationUri = "Scene." + id + ".Rotation.Rotation"; - std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; - glm::dvec3 position = image.position3d * distanceconstants::Parsec; - // Calculate the size of the plane with trigonometry - // Calculate in equatorial coordinate system since the FOV is from Earth - // /| - // /_| Adjacent is the horizontal line, opposite the vertical - // \ | Calculate for half the triangle first, then multiply with 2 - // \| - glm::dvec3 j2000 = skybrowser::galacticToEquatorial(position); - double adjacent = glm::length(j2000); - double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); - - // Calculate rotation to make the plane face the solar system barycenter - glm::dvec3 normal = glm::normalize(-position); - glm::dvec3 newRight = glm::normalize( - glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) - ); - glm::dvec3 newUp = glm::cross(normal, newRight); - // Face the Solar System Barycenter - glm::dmat3 rotation = glm::dmat3(1.0); - rotation[0] = newRight; - rotation[1] = newUp; - rotation[2] = normal; - - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle('" + sizeUri + "', " + std::to_string(opposite) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle('" + positionUri + "', " + ghoul::to_string(position) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle('" + rotationUri + "', " + ghoul::to_string(rotation) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - lookAt3dBrowser(); - - } -} void SkyBrowserModule::set3dBrowser(SceneGraphNode* node) { _browser3d = node; } -ScreenSpaceSkyBrowser* SkyBrowserModule::toBrowser(ScreenSpaceRenderable* ptr) { - return dynamic_cast(ptr); -} -ScreenSpaceSkyTarget* SkyBrowserModule::toTarget(ScreenSpaceRenderable* ptr) { - return dynamic_cast(ptr); +void SkyBrowserModule::selectImage2dBrowser(int i) +{ + Pair* selected = getPair(_selectedBrowser); + if (selected) { + + const ImageData& image = _dataHandler->getImage(i); + // Load image into browser + LINFO("Loading image " + image.name); + selected->getBrowser()->addSelectedImage(image, i); + + // If the image has coordinates, move the target + if (image.hasCelestialCoords) { + + // Animate the target to the image coordinate position + selected->getTarget()->unlock(); + selected->getTarget()->startAnimation(image.equatorialCartesian, image.fov); + + // If the coordinate is not in view, rotate camera + if (skybrowser::coordinateIsOutsideView(image.equatorialCartesian)) { + glm::dvec3 galactic = skybrowser::equatorialToGalactic(image.equatorialCartesian); + startRotation(galactic); + } + } + } } -WwtDataHandler* SkyBrowserModule::getWWTDataHandler() { + +void SkyBrowserModule::selectImage3dBrowser(int i) +{ + const ImageData& image = _dataHandler->getImage(i); + if (_browser3d) { + RenderableSkyBrowser* browser3d = dynamic_cast( + _browser3d->renderable()); + if (browser3d) { + browser3d->displayImage(image, i); + } + } +} + +void SkyBrowserModule::moveHoverCircle(int i) +{ + const ImageData& image = _dataHandler->getImage(i); + + // Only move and show circle if the image has coordinates + if (_hoverCircle && image.hasCelestialCoords && _cameraInSolarSystem) { + // Make circle visible + _hoverCircle->property("Enabled")->set(true); + + // Calculate coords for the circle and translate + glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace( + image.equatorialCartesian + ); + _hoverCircle->property("CartesianPosition")->set(coordsScreen); + } +} + +void SkyBrowserModule::loadImages(const std::string& root, const std::string& directory, + std::vector& speckFiles) +{ + _dataHandler->loadImages(root, directory, speckFiles); +} + +int SkyBrowserModule::nLoadedImages() +{ + return _dataHandler->nLoadedImages(); +} + +const WwtDataHandler* SkyBrowserModule::getWWTDataHandler() { return _dataHandler; } -std::map& SkyBrowserModule::getSkyBrowsers() { - return _browsers; +std::vector& SkyBrowserModule::getPairs() +{ + return _targetsBrowsers; } -std::vector& SkyBrowserModule::getBrowsersAndTargets() { - return _renderables; +SkyBrowserModule::Pair* SkyBrowserModule::getPair(std::string id) +{ + auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + [&](Pair& pair) { + bool foundBrowser = pair.getBrowser()->identifier() == id; + bool foundTarget = pair.getTarget()->identifier() == id; + return foundBrowser || foundTarget; + }); + return &(*it); } SceneGraphNode* SkyBrowserModule::get3dBrowser() { @@ -717,15 +692,18 @@ void SkyBrowserModule::lookAt3dBrowser() { std::string id = _browser3d->identifier(); // Target camera on the 3D sky browser openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil)", + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." + "RetargetAnchor\", nil)", scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", '" + id + "')", + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." + "Anchor\", '" + id + "')", scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '')", + "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." + "Aim\", '')", scripting::ScriptEngine::RemoteScripting::Yes ); } @@ -734,50 +712,66 @@ void SkyBrowserModule::startRotation(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates _endAnimation = endAnimation; _startAnimation = skybrowser::cameraDirectionGalactic(); - _isRotating = true; + _cameraIsRotating = true; } void SkyBrowserModule::rotateCamera(double deltaTime) { - + // Find smallest angle between the two vectors - double smallestAngle = std::acos(glm::dot(_startAnimation, _endAnimation) / (glm::length(_startAnimation) * glm::length(_endAnimation))); - // Only keep animating when target is not at final position - if (abs(smallestAngle) > 0.0001) { - // Calculate rotation this frame - double rotationAngle = smallestAngle * deltaTime; - // Create the rotation matrix for local camera space - glm::dvec3 rotationAxis = glm::normalize(glm::cross(_startAnimation, _endAnimation)); - glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); + double smallestAngle = skybrowser::angleVector(_startAnimation, _endAnimation); + + if(smallestAngle > _threshold) { + + glm::dmat4 rotMat; + skybrowser::incrementalAnimationMatrix( + rotMat, + _startAnimation, + _endAnimation, + deltaTime, + _speed + ); + // Rotate - global::navigationHandler->camera()->rotate(glm::quat_cast(rotmat)); + global::navigationHandler->camera()->rotate(glm::quat_cast(rotMat)); // Update camera direction _startAnimation = skybrowser::cameraDirectionGalactic(); } else { - _isRotating = false; + _cameraIsRotating = false; } } -bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime) { +bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTime, + double deltaTime) { float opacityDelta = static_cast(deltaTime / fadeTime); float highTreshold = 0.99f; float lowThreshold = 0.01f; float transparent = 0.0; float opaque = 1.0; + if (makeTransparent) { opacityDelta *= -1.f; } bool finished = true; - for (std::pair idAndBrowser : _browsers) { - ScreenSpaceSkyBrowser* browser = idAndBrowser.second; - // If there is a target, fade it as well. Otherwise, skip - ScreenSpaceSkyTarget* target = browser->getSkyTarget(); + + for (Pair pair : _targetsBrowsers) { + ScreenSpaceSkyBrowser* browser = pair.getBrowser(); + ScreenSpaceSkyTarget* target = pair.getTarget(); + bool targetFinished = true; + bool browserFinished = true; + if (target) { target->setOpacity(target->opacity() + opacityDelta); float opacityTarget = abs(target->opacity()); - targetFinished = makeTransparent ? opacityTarget < lowThreshold : opacityTarget > highTreshold; + + if (makeTransparent) { + targetFinished = opacityTarget < lowThreshold; + } + else { + targetFinished = opacityTarget > highTreshold; + } if (targetFinished) { float newOpacity = makeTransparent ? transparent : opaque; target->setOpacity(newOpacity); @@ -786,13 +780,21 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim // Keep fading the browsers until all are finished browser->getOpacity() = browser->getOpacity().value() + opacityDelta; float opacityBrowser = abs(browser->getOpacity().value()); - bool browserFinished = makeTransparent ? opacityBrowser < lowThreshold : opacityBrowser > highTreshold; + + if (makeTransparent) { + browserFinished = opacityBrowser < lowThreshold; + } + else { + browserFinished = opacityBrowser > highTreshold; + } + if (browserFinished && targetFinished) { browser->getOpacity() = makeTransparent ? transparent : opaque; } else { finished = false; } + } return finished; } @@ -811,37 +813,7 @@ std::string SkyBrowserModule::selectedBrowserId() { return _selectedBrowser; } -int SkyBrowserModule::loadImages(const std::string& root, const std::string& directory) { - - // Load speck files for 3D positions - std::filesystem::path globularClusters = absPath("${BASE}/sync/http/digitaluniverse_globularclusters_speck/2/gc.speck"); - std::filesystem::path openClusters = absPath("${BASE}/sync/http/digitaluniverse_openclusters_speck/2/oc.speck"); - speck::Dataset speckGlobularClusters = speck::loadSpeckFile(globularClusters); - speck::Dataset speckOpenClusters = speck::loadSpeckFile(openClusters); - - _dataHandler->loadSpeckData(speckGlobularClusters); - _dataHandler->loadSpeckData(speckOpenClusters); - - int nLoadedImages; - - // Read from disc - bool loadedImages = _dataHandler->loadWtmlCollectionsFromDirectory(directory); - - // Reading from url if there is no directory - if (loadedImages) { - LINFO("Loading images from directory"); - } - else { - LINFO("Loading images from url"); - _dataHandler->loadWtmlCollectionsFromUrl(directory, root, "root"); - } - - nLoadedImages = _dataHandler->loadImagesFromLoadedXmls(); - LINFO("Loaded " + std::to_string(nLoadedImages) + " WorldWide Telescope images."); - - return nLoadedImages; -} bool SkyBrowserModule::cameraInSolarSystem() { return _cameraInSolarSystem; diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 7c41afda01..f8fec8fb67 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; class RenderableSkyBrowser; class ScreenSpaceRenderable; +class ScreenSpaceImageLocal; class WwtDataHandler; class SceneGraphNode; class ImageData; @@ -50,73 +52,117 @@ class ImageData; class SkyBrowserModule : public OpenSpaceModule { public: + constexpr static const char* Name = "SkyBrowser"; - + + class Pair { + public: + + Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) + : _target(target), _browser(browser) {} + + Pair(Pair const&) = default; + + Pair& operator=(Pair other) + { + std::swap(_target, other._target); + std::swap(_browser, other._browser); + return *this; + } + + ScreenSpaceSkyTarget* getTarget() { + return _target; + } + + ScreenSpaceSkyBrowser* getBrowser() { + return _browser; + } + + friend bool operator==(const Pair& lhs, const Pair& rhs) { + return lhs._target == rhs._target && lhs._browser == rhs._browser; + } + friend bool operator!=(const Pair& lhs, const Pair& rhs) { + return !(lhs == rhs); + } + + private: + ScreenSpaceSkyTarget* _target{ nullptr }; + ScreenSpaceSkyBrowser* _browser{ nullptr }; + }; + // Constructor & destructor SkyBrowserModule(); virtual ~SkyBrowserModule(); // Getters - std::map& getSkyBrowsers(); - std::vector& getBrowsersAndTargets(); + std::vector& getPairs(); + Pair* getPair(std::string id); SceneGraphNode* get3dBrowser(); - WwtDataHandler* getWWTDataHandler(); + const WwtDataHandler* getWWTDataHandler(); std::string selectedBrowserId(); // Setters void setSelectedBrowser(ScreenSpaceSkyBrowser* ptr); void setSelectedBrowser(std::string id); void set3dBrowser(SceneGraphNode* node); - + void selectImage2dBrowser(int i); + void selectImage3dBrowser(int i); + // Rotation and animation - void startRotation(glm::dvec3 endAnimation); // Pass in galactic coord + void startRotation(glm::dvec3 endAnimation); // Pass in galactic coordinate void rotateCamera(double deltaTime); bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); void lookAt3dBrowser(); // Boolean functions - bool browserIdExists(std::string id); bool cameraInSolarSystem(); // Managing the browsers void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); - void addRenderable(ScreenSpaceRenderable* object); - void place3dBrowser(ImageData& image); + void addTargetBrowserPair(ScreenSpaceSkyTarget* target, ScreenSpaceSkyBrowser* browser); + void moveHoverCircle(int i); // Image collection handling - int loadImages(const std::string& root, const std::string& directory); - int getAndIncrementMessageOrder(); // For version handling calls to WWT + void loadImages(const std::string& root, const std::string& directory, + std::vector& speckFiles); + int nLoadedImages(); + + // Manage mouse interactions + void setSelectedObject(); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; + protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; private: - // Cast screen space renderable to either target or browser - ScreenSpaceSkyBrowser* toBrowser(ScreenSpaceRenderable* ptr); - ScreenSpaceSkyTarget* toTarget(ScreenSpaceRenderable* ptr); - // The browsers and targets - std::vector _renderables; // 2D browsers and targets - std::map _browsers; // Only the 2D browsers - ScreenSpaceRenderable* _mouseOnObject{ nullptr }; // Pointer to what mouse is currently on + std::vector _targetsBrowsers; + Pair* _mouseOnPair{ nullptr }; + Pair* _selectedPair{ nullptr }; + bool _isBrowser{ false }; + ScreenSpaceImageLocal* _hoverCircle{ nullptr }; SceneGraphNode* _browser3d{ nullptr }; - std::string _selectedBrowser; // Currently selected browser (2D or 3D) + std::string _selectedBrowser{ "" }; // Currently selected browser (2D or 3D) + + // 2D vs 3D visualization mode + double _solarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; + double _fadingTime = 2.0; // Flags bool _fineTuneMode{ false }; bool _isResizing{ false }; bool _isDragging{ false }; bool _cameraInSolarSystem{ true }; - bool _isRotating = false; + bool _cameraIsRotating = false; // Mouse interaction - dragging and resizing - glm::vec2 _mousePosition; // Current mouse position in screen space coordinates glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers + glm::vec2 _mousePosition; // Current mouse position in screen space coordinates glm::vec2 _startMousePosition; glm::vec2 _startDragPosition; glm::vec2 _startBrowserSize; @@ -125,11 +171,11 @@ private: // Animation of rotation of camera to look at coordinate galactic coordinates glm::dvec3 _startAnimation; glm::dvec3 _endAnimation; + double _threshold{ 0.0005 }; + double _speed{ 1.0 }; // Data handler for the image collections - WwtDataHandler* _dataHandler; - int _messageOrder{ 0 }; // Version handler for WorldWide Telescope messages - + WwtDataHandler* _dataHandler; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 02421ca2b6..2b6a7239ce 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -1,27 +1,26 @@ -#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include -#include -#include #include #include -#include +#include +#include #include +#include #include #include #include @@ -39,53 +38,12 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - // TO DO: Make this prettier with 3D browsers... - ScreenSpaceSkyBrowser* selectedBrowser = nullptr; - if (module->browserIdExists(module->selectedBrowserId())) { - selectedBrowser = module->getSkyBrowsers()[module->selectedBrowserId()]; - } - ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; - if (selectedBrowser) { - // Load image into browser - LINFO("Loading image " + image.name); - selectedBrowser->addSelectedImage(image, i); - - ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); - // If the image has coordinates, move the target - if (image.hasCelestialCoords && selectedTarget) { - - // Animate the target to the image coord position - selectedTarget->unlock(); - glm::dvec3 equatorial = skybrowser::sphericalToCartesian(image.celestialCoords); - selectedTarget->startAnimation(equatorial, image.fov); - - // Check if image coordinate is within current FOV - glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial); - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - float r = windowRatio.x / windowRatio.y; - bool coordIsWithinView = (abs(coordsScreen.x) < r && - abs(coordsScreen.y) < 1.f && coordsScreen.z < 0); - bool coordIsBehindCamera = coordsScreen.z > 0; - // If the coordinate is not in view, rotate camera - if (!coordIsWithinView || coordIsBehindCamera) { - glm::dvec3 galactic = skybrowser::equatorialToGalactic(equatorial); - module->startRotation(galactic); - } - } + if (module->cameraInSolarSystem()) { + module->selectImage2dBrowser(i); } else { - SceneGraphNode* node = module->get3dBrowser(); - if (node) { - RenderableSkyBrowser* browser3d = dynamic_cast( - node->renderable()); - if (browser3d) { - browser3d->displayImage(image, i); - } - else { - LINFO("No browser selected!"); - } - } + module->selectImage3dBrowser(i); } return 0; @@ -96,19 +54,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; - - // Only move and show circle if the image has coordinates - if (image.hasCelestialCoords && module->cameraInSolarSystem()) { - // Make circle visible - ScreenSpaceImageLocal* hoverCircle = dynamic_cast( - global::renderEngine->screenSpaceRenderable("HoverCircle")); - hoverCircle->property("Enabled")->set(true); - // Calculate coords for the circle and translate - glm::dvec3 equatorialCartesian = skybrowser::sphericalToCartesian(image.celestialCoords); - glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace(equatorialCartesian); - hoverCircle->property("CartesianPosition")->set(coordsScreen); - } + module->moveHoverCircle(i); return 0; } @@ -128,11 +74,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->browserIdExists(id)) { - ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); - if (target) { - target->lock(); - } + if (module->getPair(id)) { + SkyBrowserModule::Pair* pair = module->getPair(id); + pair->getTarget()->lock(); } return 0; } @@ -141,11 +85,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->browserIdExists(id)) { - ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); - if (target) { - target->unlock(); - } + if (module->getPair(id)) { + SkyBrowserModule::Pair* pair = module->getPair(id); + pair->getTarget()->unlock(); } return 0; } @@ -153,21 +95,19 @@ namespace openspace::skybrowser::luascriptfunctions { int setImageLayerOrder(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); - const std::string browserId = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 1); const int i = ghoul::lua::value(L, 2); int order = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - int version = module->getAndIncrementMessageOrder(); - if (module->browserIdExists(browserId)) { - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; - - browser->setImageOrder(i, order, version); + if (module->getPair(id)) { + SkyBrowserModule::Pair* pair = module->getPair(id); + pair->getBrowser()->setImageOrder(i, order); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( module->get3dBrowser()->renderable()); - browser3d->setImageLayerOrder(i, order, version); + browser3d->setImageLayerOrder(i, order); } return 0; @@ -213,9 +153,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Send out ID's to the browsers SkyBrowserModule* module = global::moduleEngine->module(); - std::map browsers = module->getSkyBrowsers(); - for (std::pair pair : browsers) { - pair.second->sendIdToBrowser(); + std::vector pairs = module->getPairs(); + for (SkyBrowserModule::Pair pair : pairs) { + pair.getBrowser()->sendIdToBrowser(); } SceneGraphNode* node = module->get3dBrowser(); if(node) { @@ -278,25 +218,39 @@ namespace openspace::skybrowser::luascriptfunctions { return 0; } - int addToSkyBrowserModule(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addToSkyBrowserModule"); + int add3dBrowserToSkyBrowserModule(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::add3dBrowserToSkyBrowserModule"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); LINFO("Add to sky browser module id " + id); - ScreenSpaceRenderable* object = global::renderEngine->screenSpaceRenderable(id); - if (object) { + SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); + if (node) { // Add to module - module->addRenderable(object); - } - else { - SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); - if (node) { - // Add to module - module->set3dBrowser(node); - } + module->set3dBrowser(node); } + + return 0; + } + + int addPairToSkyBrowserModule(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); + const std::string targetId = ghoul::lua::value(L, 1); + const std::string browserId = ghoul::lua::value(L, 2); + SkyBrowserModule* module = global::moduleEngine->module(); + + LINFO("Add browser " + browserId + " to sky browser module."); + LINFO("Add target " + targetId + " to sky browser module."); + ScreenSpaceSkyTarget* target = dynamic_cast( + global::renderEngine->screenSpaceRenderable(targetId) + ); + ScreenSpaceSkyBrowser* browser = dynamic_cast( + global::renderEngine->screenSpaceRenderable(browserId) + ); + + + module->addTargetBrowserPair(target, browser); return 0; } @@ -306,50 +260,60 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); SkyBrowserModule* module = global::moduleEngine->module(); - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; - std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); - // If no data has been loaded yet, download the data from the web! - if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { - module->loadImages(root, directory); + + if (module->nLoadedImages() == 0) { + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; + std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); + + // 3D images + std::string http = "${BASE}/sync/http/"; + std::string globular = "digitaluniverse_globularclusters_speck/2/gc.speck"; + std::string open = "digitaluniverse_openclusters_speck/2/oc.speck"; + // Load speck files for 3D positions + std::filesystem::path globularClusters = absPath(http + globular); + std::filesystem::path openClusters = absPath(http + open); + std::vector specks = { openClusters, globularClusters }; + + module->loadImages(root, directory, specks); } // Create Lua table to send to the GUI - const std::vector& images = module->getWWTDataHandler()->getLoadedImages(); lua_newtable(L); - for (int i = 0; i < images.size(); i++) { - std::string name = images[i].name != "" ? images[i].name : "undefined"; - std::string thumbnail = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; - glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestialCoords); + for (int i = 0; i < module->nLoadedImages(); i++) { + const ImageData& img = module->getWWTDataHandler()->getImage(i); + glm::dvec3 cartCoords = img.equatorialCartesian; + glm::dvec3 position = img.position3d; + + // Conversions for ghoul std::vector cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z }; - glm::dvec3 position = images[i].position3d; std::vector position3d = { position.x, position.y, position.z }; // Index for current ImageData ghoul::lua::push(L, i + 1); lua_newtable(L); // Push ("Key", value) - ghoul::lua::push(L, "name", name); + ghoul::lua::push(L, "name", img.name); lua_settable(L, -3); - ghoul::lua::push(L, "thumbnail", thumbnail); + ghoul::lua::push(L, "thumbnail", img.thumbnailUrl); lua_settable(L, -3); - ghoul::lua::push(L, "ra", images[i].celestialCoords.x); + ghoul::lua::push(L, "ra", img.equatorialSpherical.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", images[i].celestialCoords.y); + ghoul::lua::push(L, "dec", img.equatorialSpherical.y); lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); lua_settable(L, -3); - ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestialCoords); + ghoul::lua::push(L, "hasCelestialCoords", img.hasCelestialCoords); lua_settable(L, -3); - ghoul::lua::push(L, "credits", images[i].credits); + ghoul::lua::push(L, "credits", img.credits); lua_settable(L, -3); - ghoul::lua::push(L, "creditsUrl", images[i].creditsUrl); + ghoul::lua::push(L, "creditsUrl", img.creditsUrl); lua_settable(L, -3); ghoul::lua::push(L, "identifier", std::to_string(i)); lua_settable(L, -3); - ghoul::lua::push(L, "has3dCoords", images[i].has3dCoords); + ghoul::lua::push(L, "has3dCoords", img.has3dCoords); lua_settable(L, -3); ghoul::lua::push(L, "position3d", position3d); lua_settable(L, -3); @@ -378,10 +342,8 @@ namespace openspace::skybrowser::luascriptfunctions { // Calculate the smallest FOV of vertical and horizontal - double HFOV = global::windowDelegate->getHorizFieldOfView(); - glm::dvec2 windowRatio = global::windowDelegate->currentWindowSize(); - double VFOV = HFOV * (windowRatio.y / windowRatio.x); - double FOV = std::min(HFOV, VFOV); + glm::dvec2 fovs = skybrowser::fovWindow(); + double FOV = std::min(fovs.x, fovs.y); // Push window data ghoul::lua::push(L, "windowHFOV", FOV); lua_settable(L, -3); @@ -400,53 +362,52 @@ namespace openspace::skybrowser::luascriptfunctions { // Pass data for all the browsers and the corresponding targets if (module->cameraInSolarSystem()) { - std::map browsers = module->getSkyBrowsers(); + std::vector pairs = module->getPairs(); - for (std::pair pair : browsers) { - ScreenSpaceSkyBrowser* browser = pair.second; - std::string id = pair.first; + for (SkyBrowserModule::Pair pair : pairs) { + ScreenSpaceSkyBrowser* browser = pair.getBrowser(); + ScreenSpaceSkyTarget* target = pair.getTarget(); + std::string id = browser->identifier(); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; std::deque selectedImages = browser->getSelectedImages(); std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) { selectedImagesVector.push_back(i); }); - // Only add browsers that have an initialized target - ScreenSpaceSkyTarget* target = browser->getSkyTarget(); - if (target) { - glm::dvec3 celestialCart = target->targetDirectionEquatorial(); - glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); + + glm::dvec3 celestialCart = target->targetDirectionEquatorial(); + glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); - std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; - // Convert color to vector so ghoul can read it - glm::ivec3 color = browser->borderColor(); - std::vector colorVec = { color.r, color.g, color.b }; + std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; + // Convert color to vector so ghoul can read it + glm::ivec3 color = browser->borderColor(); + std::vector colorVec = { color.r, color.g, color.b }; - ghoul::lua::push(L, id); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "id", id); - lua_settable(L, -3); - ghoul::lua::push(L, "name", browser->guiName()); - lua_settable(L, -3); - ghoul::lua::push(L, "FOV", browser->verticalFov()); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedImages", selectedImagesVector); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", celestialCartVec); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", celestialSpherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", celestialSpherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "color", colorVec); - lua_settable(L, -3); - ghoul::lua::push(L, "isLocked", target->isLocked()); - lua_settable(L, -3); + ghoul::lua::push(L, id); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "id", id); + lua_settable(L, -3); + ghoul::lua::push(L, "name", browser->guiName()); + lua_settable(L, -3); + ghoul::lua::push(L, "FOV", browser->verticalFov()); + lua_settable(L, -3); + ghoul::lua::push(L, "selectedImages", selectedImagesVector); + lua_settable(L, -3); + ghoul::lua::push(L, "cartesianDirection", celestialCartVec); + lua_settable(L, -3); + ghoul::lua::push(L, "ra", celestialSpherical.x); + lua_settable(L, -3); + ghoul::lua::push(L, "dec", celestialSpherical.y); + lua_settable(L, -3); + ghoul::lua::push(L, "color", colorVec); + lua_settable(L, -3); + ghoul::lua::push(L, "isLocked", target->isLocked()); + lua_settable(L, -3); - // Set table for the current target - lua_settable(L, -3); - } + // Set table for the current target + lua_settable(L, -3); + } } else { @@ -498,17 +459,12 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - std::string idNode3dBrowser = module->get3dBrowser()->identifier(); - std::string id3dBrowser = module->get3dBrowser()->renderable()->identifier(); - if(module->cameraInSolarSystem() && module->browserIdExists(id)) { - ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget(); - if (target) { - glm::dvec3 cartesian = target->targetDirectionEquatorial(); - module->startRotation(skybrowser::equatorialToGalactic(cartesian)); - } + if(module->cameraInSolarSystem() && module->getPair(id)) { + SkyBrowserModule::Pair* pair = module->getPair(id); + module->startRotation(pair->getTarget()->targetDirectionGalactic()); } - else if (!module->cameraInSolarSystem() && id3dBrowser == id) { + else if (!module->cameraInSolarSystem() && module->get3dBrowser()) { module->lookAt3dBrowser(); } @@ -519,18 +475,18 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule::Pair* pair = module->getPair(id); - if (module->browserIdExists(id) && module->get3dBrowser() != nullptr) { - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[id]; + if (pair && module->get3dBrowser()) { RenderableSkyBrowser* browser3d = dynamic_cast( module->get3dBrowser()->renderable()); // Empty 3D browser selection browser3d->getSelectedImages().clear(); // Copy 2D selection of images to 3D browser - std::deque images = browser->getSelectedImages(); - std::for_each(std::begin(images), std::end(images), [&](int index) { - ImageData& image = module->getWWTDataHandler()->getLoadedImages()[index]; - browser3d->displayImage(image, index); + std::deque images = pair->getBrowser()->getSelectedImages(); + std::for_each(std::begin(images), std::end(images), [&](int i) { + const ImageData& image = module->getWWTDataHandler()->getImage(i); + browser3d->displayImage(image, i); }); } @@ -539,14 +495,15 @@ namespace openspace::skybrowser::luascriptfunctions { int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); - const std::string browserId = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 1); const std::string i = std::to_string(ghoul::lua::value(L, 2)); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); ghoul::Dictionary message = wwtmessage::setImageOpacity(i, opacity); - if (module->browserIdExists(browserId)) { - module->getSkyBrowsers()[browserId]->sendMessageToWwt(message); + if (module->getPair(id)) { + SkyBrowserModule::Pair* pair = module->getPair(id); + pair->getBrowser()->sendMessageToWwt(message); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( @@ -561,19 +518,17 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->browserIdExists(id)) { - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[id]; - if (browser && browser->getSkyTarget()) { - // Animate the target to the center of the screen - browser->getSkyTarget()->unlock(); - // Get camera direction in celestial spherical coordinates - glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); - // Keep the current fov - float fov = browser->verticalFov(); - browser->getSkyTarget()->startAnimation(viewDirection, fov, false); - browser->getSkyTarget()->unlock(); - } + SkyBrowserModule::Pair* pair = module->getPair(id); + if (pair) { + // Animate the target to the center of the screen + pair->getTarget()->unlock(); + // Get camera direction in celestial spherical coordinates + glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); + // Keep the current fov + float currentFov = pair->getBrowser()->verticalFov(); + pair->getTarget()->startAnimation(viewDirection, currentFov, false); } + return 0; } @@ -581,7 +536,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->browserIdExists(id)) { + if (module->getPair(id)) { module->setSelectedBrowser(id); } return 0; @@ -609,14 +564,14 @@ namespace openspace::skybrowser::luascriptfunctions { // Image index to place in 3D const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - ImageData image = module->getWWTDataHandler()->getLoadedImages()[i]; + const ImageData image = module->getWWTDataHandler()->getImage(i); // If the image has a 3D position, add it to the scene graph - if (image.has3dCoords) { + if (image.has3dCoords && module->get3dBrowser()) { RenderableSkyBrowser* browser = dynamic_cast( module->get3dBrowser()->renderable()); browser->displayImage(image, i); - module->place3dBrowser(image); + browser->placeAt3dPosition(image); } else { LINFO("Image has no 3D coordinate!"); @@ -629,16 +584,16 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); // Image index const int i = ghoul::lua::value(L, 1); - const std::string browserId = ghoul::lua::value(L, 2); + const std::string id = ghoul::lua::value(L, 2); // Get browser SkyBrowserModule* module = global::moduleEngine->module(); - ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i]; + const ImageData& image = module->getWWTDataHandler()->getImage(i); - if (module->browserIdExists(browserId)) { - ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId]; + if (module->getPair(id)) { + SkyBrowserModule::Pair* pair = module->getPair(id); // Remove image - browser->removeSelectedImage(image, i); + pair->getBrowser()->removeSelectedImage(image, i); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 4b01031b52..58dd3c1325 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,6 +9,7 @@ #include #include #include +#include #include #include // formatJson #include @@ -188,8 +190,8 @@ namespace openspace { return true; } - void RenderableSkyBrowser::displayImage(ImageData& image, int i) { - sendMessageToWwt(wwtmessage::moveCamera(image.celestialCoords, image.fov, 0.0)); + void RenderableSkyBrowser::displayImage(const ImageData& image, int i) { + sendMessageToWwt(wwtmessage::moveCamera(image.equatorialSpherical, image.fov, 0.0)); _verticalFov = image.fov; // Add to selected images if there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); @@ -202,7 +204,7 @@ namespace openspace { } } - void RenderableSkyBrowser::removeSelectedImage(ImageData& image, int i) { + void RenderableSkyBrowser::removeSelectedImage(const ImageData& image, int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it != std::end(_selectedImages)) { @@ -249,11 +251,59 @@ namespace openspace { } } - std::deque& RenderableSkyBrowser::getSelectedImages() { + void RenderableSkyBrowser::placeAt3dPosition(const ImageData& image) + { + std::string renderableId = dynamic_cast( + this)->renderable()->identifier(); + // Uris for properties + std::string sizeUri = "Scene." + _identifier + "." + renderableId + ".Size"; + std::string positionUri = "Scene." + _identifier + ".Translation.Position"; + std::string rotationUri = "Scene." + _identifier + ".Rotation.Rotation"; + std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; + glm::dvec3 position = image.position3d * distanceconstants::Parsec; + // Calculate the size of the plane with trigonometry + // Calculate in equatorial coordinate system since the FOV is from Earth + // /| + // /_| Adjacent is the horizontal line, opposite the vertical + // \ | Calculate for half the triangle first, then multiply with 2 + // \| + glm::dvec3 j2000 = skybrowser::galacticToEquatorial(position); + double adjacent = glm::length(j2000); + double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); + + // Calculate rotation to make the plane face the solar system barycenter + glm::dvec3 normal = glm::normalize(-position); + glm::dvec3 newRight = glm::normalize( + glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) + ); + glm::dvec3 newUp = glm::cross(normal, newRight); + // Face the Solar System Barycenter + glm::dmat3 rotation = glm::dmat3(1.0); + rotation[0] = newRight; + rotation[1] = newUp; + rotation[2] = normal; + + std::string setValue = "openspace.setPropertyValueSingle('"; + + openspace::global::scriptEngine->queueScript( + setValue + sizeUri + "', " + std::to_string(opposite) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + setValue + positionUri + "', " + ghoul::to_string(position) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( + setValue + rotationUri + "', " + ghoul::to_string(rotation) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + + std::deque& RenderableSkyBrowser::getSelectedImages() { return _selectedImages; } - void RenderableSkyBrowser::setImageLayerOrder(int i, int order, int version) { + void RenderableSkyBrowser::setImageLayerOrder(int i, int order) { // Remove from selected list auto current = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); auto target = std::begin(_selectedImages) + order; @@ -266,7 +316,7 @@ namespace openspace { int reverseOrder = _selectedImages.size() - order - 1; ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), - reverseOrder, version); + reverseOrder); sendMessageToWwt(message); } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 2ebcce44e7..1eb1ddb010 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -66,7 +66,7 @@ namespace { std::optional targetId; // [[codegen::verbatim(BorderColorInfo.description)]] - std::optional borderColor; + std::optional borderColor; }; #include "screenspaceskybrowser_codegen.cpp" @@ -78,7 +78,7 @@ namespace openspace { : ScreenSpaceBrowser(dictionary) , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0), glm::ivec2(300)) , _verticalFov(VerticalFovInfo, 10.f, 0.1f, 70.f) - , _borderColor(BorderColorInfo, glm::vec3(rand() % 256, rand() % 256, rand() % 256)) + , _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)) , _skyTargetId(TargetIdInfo) { // Make the color property display a color picker in the GUI @@ -139,7 +139,7 @@ namespace openspace { // Make sure the RGB color at least is 50% brightness // By making each channel 50% bright in general // 222 = sqrt(3*(0.5*256)^2) - while (glm::length(_borderColor.value()) < 222) { + while (glm::length(glm::vec3(_borderColor.value())) < 222.f) { _borderColor = glm::vec3(rand() % 256, rand() % 256, rand() % 256); } } @@ -162,6 +162,18 @@ namespace openspace { executeJavascript("setId('" + identifier() + "')"); } + void ScreenSpaceSkyBrowser::highlight(glm::ivec3 addition) + { + glm::ivec3 color = glm::ivec3(_borderColor.value()); + setWebpageBorderColor( color + addition ); + } + + void ScreenSpaceSkyBrowser::removeHighlight(glm::ivec3 removal) + { + glm::ivec3 color = glm::ivec3(_borderColor.value()); + setWebpageBorderColor( color - removal ); + } + void ScreenSpaceSkyBrowser::initializeBrowser() { // If the camera is already synced, the browser is already initialized if (!_syncViewWithWwt) { @@ -177,6 +189,21 @@ namespace openspace { } } + glm::dvec2 ScreenSpaceSkyBrowser::fineTuneTarget(glm::dvec2 drag) { + // Fine tuning of target + glm::dvec2 wwtFov = fieldsOfView(); + glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); + + glm::dvec2 browserDim = screenSpaceDimensions(); + glm::dvec2 angleResult = wwtFov * (drag / browserDim); + glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; + + // Convert to screen space coordinate system + glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; + glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; + return result; + } + bool ScreenSpaceSkyBrowser::deinitializeGL() { // Set flag to false so the thread can exit _syncViewWithWwt = false; @@ -244,6 +271,14 @@ namespace openspace { return _verticalFov.value(); } + glm::dvec2 ScreenSpaceSkyBrowser::fieldsOfView() { + glm::dvec2 browserDim = screenSpaceDimensions(); + double browserRatio = browserDim.x / browserDim.y; + glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio, verticalFov()); + + return browserFov; + } + void ScreenSpaceSkyBrowser::setWebpageBorderColor(glm::ivec3 color) { std::string stringColor = std::to_string(color.x) + "," + std::to_string(color.y) + "," + std::to_string(color.z); @@ -292,6 +327,7 @@ namespace openspace { // Make sure coordinate is on browser if (!coordIsInsideCornersScreenSpace(screenSpaceCoord)) return resizePosition; + // TO DO: turn this into a vector and use prettier vector arithmetic float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; @@ -359,7 +395,7 @@ namespace openspace { return _selectedImages; } - void ScreenSpaceSkyBrowser::addSelectedImage(ImageData& image, int i) { + void ScreenSpaceSkyBrowser::addSelectedImage(const ImageData& image, int i) { // Ensure there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); bool found = it != std::end(_selectedImages); @@ -372,7 +408,7 @@ namespace openspace { } } - void ScreenSpaceSkyBrowser::removeSelectedImage(ImageData& image, int i) { + void ScreenSpaceSkyBrowser::removeSelectedImage(const ImageData& image, int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); bool found = it != std::end(_selectedImages); @@ -382,7 +418,7 @@ namespace openspace { } } - void ScreenSpaceSkyBrowser::setImageOrder(int i, int order, int version) { + void ScreenSpaceSkyBrowser::setImageOrder(int i, int order) { // Find the selected image auto selected = std::find( @@ -408,8 +444,7 @@ namespace openspace { int reverseOrder = _selectedImages.size() - order - 1; ghoul::Dictionary message = wwtmessage::setLayerOrder( std::to_string(i), - reverseOrder, - version + reverseOrder ); sendMessageToWwt(message); } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index d422b6cbcd..f22c86b4d4 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -34,7 +34,7 @@ namespace { constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = { - "BrowserID", + "BrowserId", "Browser Identifier", "The identifier of the corresponding sky browser." }; @@ -55,16 +55,39 @@ namespace { "be rendered in the target." }; + constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = + { + "AnimationSpeed", + "Animation Speed", + "The factor which is multiplied with the animation speed of the target." + }; + + constexpr const openspace::properties::Property::PropertyInfo AnimationThresholdInfo = + { + "AnimationThreshold", + "Animation Threshold", + "The threshold for when the target is determined to have appeared at its " + "destination. Angle in radians between the destination and the target position in" + "equatorial Cartesian coordinate system." + }; + struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { // [[codegen::verbatim(BrowserIDInfo.description)]] - std::optional browserID; + std::optional browserId; // [[codegen::verbatim(CrosshairThresholdInfo.description)]] std::optional crosshairThreshold; // [[codegen::verbatim(RectangleThresholdInfo.description)]] std::optional rectangleThreshold; + + // [[codegen::verbatim(RectangleThresholdInfo.description)]] + std::optional animationSpeed; + + // [[codegen::verbatim(RectangleThresholdInfo.description)]] + std::optional animationThreshold; + }; #include "screenspaceskytarget_codegen.cpp" @@ -78,17 +101,23 @@ namespace openspace { , _skyBrowser(nullptr) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) + , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 1.0) + , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _color(220, 220, 220) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _skyBrowserId = p.browserID.value_or(_skyBrowserId); + _skyBrowserId = p.browserId.value_or(_skyBrowserId); _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); + _stopAnimationThreshold = p.crosshairThreshold.value_or(_stopAnimationThreshold); + _animationSpeed = p.animationSpeed.value_or(_animationSpeed); addProperty(_skyBrowserId); addProperty(_showCrosshairThreshold); addProperty(_showRectangleThreshold); + addProperty(_stopAnimationThreshold); + addProperty(_animationSpeed); // If the ID changes for the corresponding browser, update _skyBrowserId.onChange([&]() { @@ -201,8 +230,13 @@ namespace openspace { void ScreenSpaceSkyTarget::render() { - bool showCrosshair = _skyBrowser->verticalFov() < _showCrosshairThreshold; - bool showRectangle = _skyBrowser->verticalFov() > _showRectangleThreshold; + bool showCrosshair = false; + bool showRectangle = true; + if (_skyBrowser) { + showCrosshair = _skyBrowser->verticalFov() < _showCrosshairThreshold; + showRectangle = _skyBrowser->verticalFov() > _showRectangleThreshold; + } + glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() }; glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); @@ -245,15 +279,12 @@ namespace openspace { // Update the scale of the target (the height of the target in relation to the // OpenSpace window) void ScreenSpaceSkyTarget::setScale(float verticalFov) { - - // Calculate the vertical field of view of the OpenSpace window - float hFovOs = global::windowDelegate->getHorizFieldOfView(); - glm::vec2 windowRatio = glm::vec2(global::windowDelegate->currentWindowSize()); - float vFovOs = hFovOs * windowRatio.y / windowRatio.x; + + glm::dvec2 fovs = skybrowser::fovWindow(); // Cap the scale at small scales so it is still visible - float heightRatio = verticalFov / vFovOs; - float smallestHeightRatio = _showRectangleThreshold.value() / vFovOs; + float heightRatio = verticalFov / fovs.y; + float smallestHeightRatio = _showRectangleThreshold.value() / fovs.y; _scale = std::max(heightRatio, smallestHeightRatio); } @@ -275,8 +306,7 @@ namespace openspace { // Start a thread to enable user interactions while locking target _lockTarget = std::thread([&] { while (_isLocked) { - glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace(_lockedCoordinates); - _cartesianPosition = coordsScreen; + _cartesianPosition = skybrowser::equatorialToScreenSpace(_lockedCoordinates); } }); } @@ -288,22 +318,27 @@ namespace openspace { glm::dvec3 ScreenSpaceSkyTarget::targetDirectionEquatorial() const { // Calculate the galactic coordinate of the target direction // projected onto the celestial sphere - return skybrowser::screenSpaceToEquatorial(_cartesianPosition.value()); + return skybrowser::localCameraToEquatorial(_cartesianPosition.value()); } void ScreenSpaceSkyTarget::animateToCoordinate(double deltaTime) { + if (_isAnimated) { + // Find smallest angle between the two vectors - double smallestAngle = std::acos(glm::dot(_animationStart, _animationEnd) / (glm::length(_animationStart) * glm::length(_animationEnd))); + double smallestAngle = skybrowser::angleVector(_animationStart, _animationEnd); // Only keep animating when target is not at final position - if (abs(smallestAngle) > 0.0005) { - // Calculate rotation this frame - double rotationAngle = smallestAngle * deltaTime * 5.0; - // Create the rotation matrix - glm::dvec3 rotationAxis = glm::normalize(glm::cross(_animationStart, _animationEnd)); - glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis); + if (smallestAngle > _stopAnimationThreshold) { + glm::dmat4 rotMat; + skybrowser::incrementalAnimationMatrix( + rotMat, + _animationStart, + _animationEnd, + deltaTime, + _animationSpeed + ); // Rotate target direction - glm::dvec3 newDir = rotmat * glm::dvec4(_animationStart, 1.0); + glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); // Convert to screen space _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); // Update position @@ -346,6 +381,16 @@ namespace openspace { return true; } + void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) + { + _color += addition; + } + + void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal) + { + _color -= removal; + } + void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfterwards) { // Save the Cartesian celestial coordinates for animation diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index b83ba06a44..406f9f6639 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -5,11 +5,11 @@ #include #include // For atan2 #include // For printing glm data +#include +#include #define _USE_MATH_DEFINES #include - - namespace openspace::skybrowser { glm::dvec3 sphericalToCartesian(glm::dvec2 coords) { @@ -49,7 +49,7 @@ namespace openspace::skybrowser { glm::dvec3 galacticToScreenSpace(glm::dvec3 coords) { - glm::dvec3 localCameraSpace = galacticToCameraLocal(coords); + glm::dvec3 localCameraSpace = galacticToLocalCamera(coords); // Ensure that if the coord is behind the camera, // the converted coordinate will be there too double zCoord = localCameraSpace.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ; @@ -63,7 +63,7 @@ namespace openspace::skybrowser { return screenSpace; } - glm::dvec3 screenSpaceToGalactic(glm::dvec3 coords) { + glm::dvec3 localCameraToGalactic(glm::dvec3 coords) { glm::dmat4 rotation = glm::inverse( global::navigationHandler->camera()->viewRotationMatrix()); glm::dvec4 position = glm::dvec4(coords, 1.0); @@ -71,16 +71,16 @@ namespace openspace::skybrowser { return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius; } - glm::dvec3 screenSpaceToEquatorial(glm::dvec3 coords) { + glm::dvec3 localCameraToEquatorial(glm::dvec3 coords) { // Calculate the galactic coordinate of the target direction // projected onto the celestial sphere glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 galactic = camPos + skybrowser::screenSpaceToGalactic(coords); + glm::dvec3 galactic = camPos + skybrowser::localCameraToGalactic(coords); return skybrowser::galacticToEquatorial(galactic); } - glm::dvec3 galacticToCameraLocal(glm::dvec3 coords) { + glm::dvec3 galacticToLocalCamera(glm::dvec3 coords) { // Transform vector to camera's local coordinate system glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); @@ -125,6 +125,66 @@ namespace openspace::skybrowser { return galCoord; } + + float windowRatio() { + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + return windowRatio.x / windowRatio.y; + } + + bool coordinateIsOutsideView(glm::dvec3 equatorial) { + // Check if image coordinate is within current FOV + glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial); + double r = static_cast(windowRatio()); + + bool coordIsWithinView = (abs(coordsScreen.x) < r && + abs(coordsScreen.y) < 1.f && coordsScreen.z < 0); + bool coordIsBehindCamera = coordsScreen.z > 0; + // If the coordinate is not in view, rotate camera + return !coordIsWithinView || coordIsBehindCamera; + } + + // Transforms a pixel coordinate to a screen space coordinate + glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate) { + glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); + // Change origin to middle of the window + glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f); + // Ensure the upper right corner is positive on the y axis + screenSpacePos *= glm::vec2(1.0f, -1.0f); + // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] + screenSpacePos /= (0.5f * size.y); + return screenSpacePos; + } + + // The horizontal and vertical fov of the OpenSpace window + glm::dvec2 fovWindow() { + // OpenSpace FOV + glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize()); + double windowRatio = windowDim.y / windowDim.x; + double hFov = global::windowDelegate->getHorizFieldOfView(); + glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio); + return OpenSpaceFOV; + } + + double angleVector(glm::dvec3 start, glm::dvec3 end) { + + // Find smallest angle between the two vectors + double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); + return std::acos(cos); + } + + void incrementalAnimationMatrix(glm::dmat4& rotation, glm::dvec3 start, + glm::dvec3 end, double deltaTime, + double speedFactor) { + + double smallestAngle = angleVector(start, end); + // Calculate rotation this frame + double rotationAngle = smallestAngle * deltaTime * speedFactor; + + // Create the rotation matrix for local camera space + glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end)); + rotation = glm::rotate(rotationAngle, rotationAxis); + } + } // WWT messages @@ -206,7 +266,7 @@ namespace openspace::wwtmessage { return msg; } - ghoul::Dictionary setLayerOrder(const std::string& id, int order, int version) { + ghoul::Dictionary setLayerOrder(const std::string& id, int order) { // The lower the layer order, the more towards the back the image is placed // 0 is the background using namespace std::string_literals; @@ -214,7 +274,9 @@ namespace openspace::wwtmessage { msg.setValue("event", "image_layer_order"s); msg.setValue("id", id); msg.setValue("order", order); - msg.setValue("version", version); + msg.setValue("version", messageCounter); + + messageCounter++; return msg; } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index f08a4b10bd..ff10da4abd 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -1,8 +1,9 @@ #include +#include #include // For downloading files from url -#include // To iterate through files in directory #include #include +#include // To iterate through files in directory #include #include #include @@ -20,25 +21,21 @@ namespace { namespace openspace { - bool hasAttribute(tinyxml2::XMLElement* element, std::string name) { + bool hasAttribute(const tinyxml2::XMLElement* element, const std::string& name) { return element->FindAttribute(name.c_str()); } - std::string getAttribute(tinyxml2::XMLElement* element, std::string name) { + std::string getAttribute(const tinyxml2::XMLElement* element, const std::string& name) { if (hasAttribute(element, name)) { return element->FindAttribute(name.c_str())->Value(); } else { - return ""; + return wwt::Undefined; } } - WwtDataHandler::~WwtDataHandler() { - // Call destructor of all allocated xmls - _xmls.clear(); - } - - bool WwtDataHandler::downloadFile(std::string& url, std::string& fileDestination) { + // Parsing and downloading of wtml files + bool downloadFile(const std::string& url, const std::string& fileDestination) { // Get the web page and save to file HttpRequest::RequestOptions opt{ 5 }; SyncHttpFileDownload wtml_root( @@ -48,62 +45,7 @@ namespace openspace { return wtml_root.hasSucceeded(); } - bool WwtDataHandler::loadWtmlCollectionsFromUrl(std::string directory, - std::string url, std::string fileName) - { - // Look for WWT image data folder - if (!directoryExists(directory)) { - std::string newDir = directory; - newDir.pop_back(); - LINFO("Creating directory WWTimagedata"); - std::filesystem::create_directory(newDir); - } - - // Get file - std::string file = directory + fileName + ".aspx"; - if (!downloadFile(url, file)) { - LINFO("Couldn't download file " + url); - return false; - } - // Parse to XML - using namespace tinyxml2; - tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - doc->LoadFile(file.c_str()); - - XMLElement* root = doc->RootElement(); - XMLElement* element = root->FirstChildElement(std::string("Folder").c_str()); - - // If there are no folders, or there are folder but without urls, stop recursion - bool folderExists = element; - bool folderContainNoUrls = folderExists && !hasAttribute(element, "Url"); - - if (!folderExists || folderContainNoUrls) { - // Save the url - if (hasAttribute(root, "Name")) { - std::string collectionName = getAttribute(root, "Name"); - ImageCollection newCollection{ collectionName, url }; - _imageUrls.push_back(newCollection); - } - _xmls.push_back(doc); - LINFO("Saving " + url); - - return true; - } - // Iterate through all the folders - while (element && std::string(element->Value()) == "Folder") { - - // Get all attributes for the - if (hasAttribute(element, "Url") && hasAttribute(element, "Name")) { - std::string subUrl = getAttribute(element, "Url"); - std::string subName = getAttribute(element, "Name"); - loadWtmlCollectionsFromUrl(directory, subUrl, subName); - } - element = element->NextSiblingElement(); - } - } - - - bool WwtDataHandler::directoryExists(std::string& path) + bool directoryExists(const std::string& path) { struct stat info; @@ -111,13 +53,13 @@ namespace openspace { if (statRC != 0) { // something along the path does not exist - if (errno == ENOENT) { - return false; - } + if (errno == ENOENT) { + return false; + } // something in path prefix is not a dir - if (errno == ENOTDIR) { - return false; - } + if (errno == ENOTDIR) { + return false; + } return false; } @@ -126,48 +68,201 @@ namespace openspace { return directoryExists; } - bool WwtDataHandler::loadWtmlCollectionsFromDirectory(std::string directory) { - - if (!directoryExists(directory)) return false; + std::string createSearchableString(std::string str) { + // Remove white spaces and all special characters + str.erase(std::remove_if(std::begin(str), std::end(str), [](char c) { + bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); + return !isNumberOrLetter; + }), + std::end(str)); + // Make the word lower case + std::transform(std::begin(str), std::end(str), std::begin(str), [](char c) { + return std::tolower(c); + }); + return str; + } + std::unordered_map + loadSpeckData(const speck::Dataset& dataset) { + // Create map + std::unordered_map positions3d; + + for (speck::Dataset::Entry entry : dataset.entries) { + if (entry.comment.has_value()) { + std::string name = createSearchableString(entry.comment.value()); + positions3d[name] = std::move(entry.position); + } + } + return positions3d; + } + + tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, + const std::string& name) { + while (node && node->Name() != name) { + node = node->FirstChildElement(); + } + return node; + } + + tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, + const std::string& name) { + + tinyxml2::XMLElement* child = node->FirstChildElement(); + tinyxml2::XMLElement* imageSet = nullptr; + + // Traverse the children and look at all their first child to find ImageSet + while (child) { + imageSet = getDirectChildNode(child, name); + // Found + if (imageSet) { + break; + } + child = child->NextSiblingElement(); + } + return imageSet; + } + + std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, + const std::string& elementName) { + // Find the thumbnail image url + // The thumbnail is the last node so traverse backwards for speed + tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement( + elementName.c_str() + ); + + if (imageSetChild && imageSetChild->GetText()) { + return imageSetChild->GetText(); + } + else { + return wwt::Undefined; + } + } + + std::string getUrlFromPlace(tinyxml2::XMLElement* place) { + + // If the place has a thumbnail url, return it + if (hasAttribute(place, wwt::Thumbnail)) { + return getAttribute(place, wwt::Thumbnail); + } + + // If the place doesn't have a thumbnail url data attribute, + // Load the image set it stores instead + tinyxml2::XMLElement* imageSet = getChildNode(place, wwt::ImageSet); + + // If there is an imageSet, collect thumbnail url + if (imageSet) { + return getChildNodeContentFromImageSet(imageSet, wwt::ThumbnailUrl); + } + else { + // If it doesn't contain an ImageSet, it doesn't have an url + return wwt::Undefined; + } + } + + + void parseWtmlsFromDisc(std::vector& _xmls, + const std::string& directory) { for (const auto& entry : std::filesystem::directory_iterator(directory)) { - + tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument(); std::string path = entry.path().u8string(); tinyxml2::XMLError successCode = document->LoadFile(path.c_str()); - bool fileIsLoaded = successCode == tinyxml2::XMLError::XML_SUCCESS; - if (fileIsLoaded) { - tinyxml2::XMLElement* root = document->RootElement(); - - if (hasAttribute(root, "Name")) { - std::string collectionName = getAttribute(root, "Name"); - ImageCollection newCollection{ collectionName, path }; - _imageUrls.push_back(newCollection); - } + if (successCode == tinyxml2::XMLError::XML_SUCCESS) { _xmls.push_back(document); } } - return true; } - std::ostream& operator<<(std::ostream& os, const ImageData& img) { - os << "Name: " << img.name << " Coords: ra: " << img.celestialCoords.x - << " dec: " << img.celestialCoords.y << std::endl; - os << "Thumbnail: " << img.thumbnailUrl << std::endl; - os << "Collection: " << img.collection << std::endl << std::endl; - return os; + bool downloadAndParseWtmlFilesFromUrl(std::vector& _xmls, + const std::string& directory, const std::string& url, + const std::string& fileName) + { + // Look for WWT image data folder, create folder if it doesn't exist + if (!directoryExists(directory)) { + std::string newDir = directory; + // Remove the '/' at the end + newDir.pop_back(); + LINFO("Creating directory WWTimagedata"); + std::filesystem::create_directory(newDir); + } + + // Download file from url + std::string file = directory.c_str() + fileName + ".aspx"; + if (!downloadFile(url, file)) { + LINFO("Couldn't download file " + url); + return false; + } + + // Parse file to XML + using namespace tinyxml2; + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + doc->LoadFile(file.c_str()); + + // Search XML file for folders with urls + XMLElement* root = doc->RootElement(); + XMLElement* element = root->FirstChildElement(wwt::Folder.c_str()); + bool folderExists = element; + bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url); + + // If the file contains no folders, or there are folders but without urls, + // stop recursion + if (!folderExists || folderContainNoUrls) { + _xmls.push_back(doc); + LINFO("Saving " + url); + + return true; + } + + // Iterate through all the folders in the XML file + while (element && std::string(element->Value()) == wwt::Folder) { + + // If folder contains urls, download and parse those urls + if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) { + std::string url = getAttribute(element, wwt::Url); + std::string fileName = getAttribute(element, wwt::Name); + downloadAndParseWtmlFilesFromUrl(_xmls, directory, url, fileName); + } + element = element->NextSiblingElement(); + } + } + WwtDataHandler::~WwtDataHandler() { + // Call destructor of all allocated xmls + _xmls.clear(); + } - int WwtDataHandler::loadImagesFromLoadedXmls() { + void WwtDataHandler::loadImages(const std::string& root, const std::string& directory, + std::vector& speckFiles) { + + // Load 3D data from speck files + for (std::filesystem::path& path : speckFiles) { + speck::Dataset speck = speck::loadSpeckFile(path); + _3dPositions = loadSpeckData(speck); + LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + + " entries!"); + } + + // Collect the wtml files, either by reading from disc or from a url + if (directoryExists(directory)) { + parseWtmlsFromDisc(_xmls, directory); + LINFO("Loading images from directory"); + } + else { + downloadAndParseWtmlFilesFromUrl(_xmls, directory, root, "root"); + LINFO("Loading images from url"); + } + + // Traverse through the collected wtml documents and collect the images for (tinyxml2::XMLDocument* doc : _xmls) { tinyxml2::XMLElement* root = doc->FirstChildElement(); - std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : ""; - loadImagesFromXml(root, collectionName); + std::string collectionName = getAttribute(root, wwt::Name); + saveImagesFromXml(root, collectionName); } + // Sort images in alphabetical order - std::sort(_images.begin(), _images.end(), [](ImageData a, ImageData b) { + std::sort(_images.begin(), _images.end(), [](ImageData& a, ImageData& b) { // If the first character in the names are lowercase, make it upper case if (std::islower(a.name[0])) { // convert string to upper case @@ -178,184 +273,139 @@ namespace openspace { } return a.name < b.name; }); - LINFO(std::to_string(_nImagesWith3dPositions) + " 3D positions were matched in the speck files!"); + LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope " + "images."); + + LINFO(std::to_string(_nMatched3dPositions) + " 3D positions were matched in " + "the speck files!"); + } + + int WwtDataHandler::nLoadedImages() const + { return _images.size(); } - const std::vector& WwtDataHandler::getAllImageCollectionUrls() const { - return _imageUrls; + const ImageData& WwtDataHandler::getImage(const int i) const + { + assert(i < _images.size(), "Index outside of image vector boundaries!"); + return _images[i]; } - void WwtDataHandler::loadImagesFromXml(tinyxml2::XMLElement* node, std::string collectionName) { - // Get direct child of node called "Place" - using namespace tinyxml2; - XMLElement* ptr = node->FirstChildElement(); + void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, + std::string collection) { - // Go through all siblings of ptr and open folders recursively - // Iterate through all siblings at same level and load - while (ptr) { - // If node is an image or place, load it - if (std::string(ptr->Name()) == "ImageSet" || std::string(ptr->Name()) == "Place") { - loadImageFromXmlNode(ptr, collectionName); - } - // If node is another folder, open recursively - else if (std::string(ptr->Name()) == "Folder") { - std::string newCollectionName = collectionName + "/"; - if (ptr->FindAttribute("Name")) { - newCollectionName += std::string(ptr->FindAttribute("Name")->Value()); - } - loadImagesFromXml(ptr, newCollectionName); - } + // Collect the image set of the node. The structure is different depending on if + // it is a Place or an ImageSet + std::string thumbnailUrl = { wwt::Undefined }; + tinyxml2::XMLElement* imageSet{ nullptr }; + std::string type = std::string(node->Name()); - ptr = ptr->NextSiblingElement(); - } - - } - - int WwtDataHandler::loadImageFromXmlNode(tinyxml2::XMLElement* node, std::string collectionName) { - // Only load "Sky" type images - if (std::string(node->FindAttribute("DataSetType")->Value()) != "Sky") - return -1; - - std::string thumbnailUrl; - std::string credits; - std::string creditsUrl; - std::string imageUrl; - tinyxml2::XMLElement* imageSet = nullptr; - // Get url. The thumbnail can be located either in the Place or the ImageSet - if (std::string(node->Name()) == "ImageSet") { - thumbnailUrl = getChildNodeContentFromImageSet(node, "ThumbnailUrl"); + if (type == wwt::ImageSet) { + thumbnailUrl = getChildNodeContentFromImageSet(node, wwt::ThumbnailUrl); imageSet = node; - } - else if (std::string(node->Name()) == "Place") { + } // Place + else if (type == wwt::Place) { thumbnailUrl = getUrlFromPlace(node); - imageSet = getChildNode(node, "ImageSet"); + imageSet = getChildNode(node, wwt::ImageSet); } - else { - return -1; - } - - // Only load images that have a thumbnail image url - if (thumbnailUrl == "" || !imageSet) { - return -1; - } - // Only load images that contain a image url - if (!imageSet->FindAttribute("Url")) { - return -1; - } - // The credits and image url are always children nodes of ImageSet - credits = getChildNodeContentFromImageSet(imageSet, "Credits"); - creditsUrl = getChildNodeContentFromImageSet(imageSet, "CreditsUrl"); - imageUrl = imageSet->FindAttribute("Url")->Value(); - ImageData image{}; - setImageDataValues(node, credits, creditsUrl, thumbnailUrl, collectionName, imageUrl, image); + // Only collect the images that have a thumbnail image, that are sky images and + // that have an image + bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined; + bool isSkyImage = getAttribute(node, wwt::DataSetType) == wwt::Sky; + bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false; + + if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) { + return; + } + + // Collect name, image url and credits + std::string name = getAttribute(node, wwt::Name); + std::string imageUrl = getAttribute(imageSet, wwt::Url); + std::string credits = getChildNodeContentFromImageSet(imageSet, wwt::Credits); + std::string creditsUrl = getChildNodeContentFromImageSet( + imageSet, wwt::CreditsUrl + ); + + // Collect equatorial coordinates. All-sky surveys do not have this kind of + // coordinate + bool hasCelestialCoords = hasAttribute(node, wwt::RA) && + hasAttribute(node, wwt::Dec); + glm::dvec2 equatorialSpherical{ 0.0 }; + glm::dvec3 equatorialCartesian{ 0.0 }; + + if (hasCelestialCoords) { + // The RA from WWT is in the unit hours: + // to convert to degrees, multiply with 360 (deg) /24 (h) = 15 + double ra = 15.0 * std::stod(getAttribute(node, wwt::RA)); + double dec = std::stod(getAttribute(node, wwt::Dec)); + equatorialSpherical = { ra, dec }; + equatorialCartesian = skybrowser::sphericalToCartesian( + equatorialSpherical + ); + } + + // Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6 + float fov{ 0.f }; + if (hasAttribute(node, wwt::ZoomLevel)) { + fov = std::stof(getAttribute(node, wwt::ZoomLevel)) / 6.0; + } + + // Find 3D position by matching with speck file + bool has3dCoords{ false }; + glm::dvec3 position3d{ 0.0 }; + auto it = _3dPositions.find(createSearchableString(name)); + if (it != _3dPositions.end()) { + position3d = it->second; + has3dCoords = true; + _nMatched3dPositions++; + } + + ImageData image = { + name, + thumbnailUrl, + imageUrl, + credits, + creditsUrl, + collection, + hasCelestialCoords, + has3dCoords, + fov, + equatorialSpherical, + equatorialCartesian, + position3d + }; _images.push_back(image); - // Return index of image in vector - return _images.size(); } - std::string WwtDataHandler::getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName) { - // FInd the thumbnail image url - // The thumbnail is the last node so traverse backwards for speed - tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement(elementName.c_str()); - return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : ""; - } + void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root, + std::string collection) { - std::string WwtDataHandler::getUrlFromPlace(tinyxml2::XMLElement* place) { - // Get thumbnail attribute, if there is one - std::string url = place->FindAttribute("Thumbnail") ? place->FindAttribute("Thumbnail")->Value() : ""; - // Url found! Return it - if (url != "") return url; + // Get direct child of node called Place + using namespace tinyxml2; + XMLElement* node = root->FirstChildElement(); - // If the place doesn't have a thumbnail url data attribute, - // Load the image set it stores instead - tinyxml2::XMLElement* imageSet = getChildNode(place, "ImageSet"); - // If it doesn't contain an ImageSet, it doesn't have an url -> return empty string - // If there is an imageSet, collect thumbnail url - return imageSet ? getChildNodeContentFromImageSet(imageSet, "ThumbnailUrl") : ""; - } - - tinyxml2::XMLElement* WwtDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) { - while (node && std::string(node->Name()) != name) { - node = node->FirstChildElement(); - } - return node; - } - - tinyxml2::XMLElement* WwtDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) { - // Traverse the children and look at all their first child to find ImageSet - tinyxml2::XMLElement* child = node->FirstChildElement(); - tinyxml2::XMLElement* imageSet = nullptr; - while (child) { - imageSet = getDirectChildNode(child, name); - if (imageSet) break; - child = child->NextSiblingElement(); - } - return imageSet; - } - - void WwtDataHandler::setImageDataValues(tinyxml2::XMLElement* node, - std::string credits, - std::string creditsUrl, - std::string thumbnail, - std::string collectionName, - std::string imageUrl, - ImageData& img) { - // Get attributes for the image - img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : ""; - img.hasCelestialCoords = node->FindAttribute("RA") && node->FindAttribute("Dec"); - if (img.hasCelestialCoords) { - // The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h) = 15 - img.celestialCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value()); - img.celestialCoords.y = std::stof(node->FindAttribute("Dec")->Value()); - } - img.collection = collectionName; - img.thumbnailUrl = thumbnail; - // In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6 - img.fov = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) / 6: 0.f; - img.credits = credits; - img.creditsUrl = creditsUrl; - img.imageUrl = imageUrl; - // Look for 3D position in the data loaded from speck files - std::string str = createSearchableString(img.name); - // Look for 3D coordinate - auto it = _3dPositions.find(str); - if (it != _3dPositions.end()) { - img.position3d = it->second; - img.has3dCoords = true; - _nImagesWith3dPositions++; - } - } - - std::vector& WwtDataHandler::getLoadedImages() { - return _images; - } - - void WwtDataHandler::loadSpeckData(speck::Dataset& dataset) { - for (speck::Dataset::Entry entry : dataset.entries) { - if (entry.comment.has_value()) { - std::string name = createSearchableString(entry.comment.value()); - _3dPositions[name] = std::move(entry.position); + // Iterate through all siblings of node. If sibling is folder, open recursively. + // If sibling is image, save it. + while (node) { + const std::string name = node->Name(); + // If node is an image or place, load it + if (name == wwt::ImageSet || name == wwt::Place) { + saveImageFromNode(node, collection); } + // If node is another folder, open recursively + else if (name == wwt::Folder) { + std::string newCollectionName = collection + "/"; + newCollectionName += getAttribute(node, wwt::Name); + + saveImagesFromXml(node, newCollectionName); + } + node = node->NextSiblingElement(); } - LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + " entries!"); } - std::string WwtDataHandler::createSearchableString(std::string str) { - // Remove white spaces and all special characters - str.erase(std::remove_if(str.begin(), str.end(), [](char c) { - bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); - return !isNumberOrLetter; - }), - str.end()); - // Make the word lower case - std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return std::tolower(c); }); - return str; - } } // Loading of speck files From b64fc94599523ac476b5bfe72061d0f8736294fe Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 3 Nov 2021 10:37:40 -0400 Subject: [PATCH 132/251] Add class Pair for skybrowser + skytarget pair --- modules/skybrowser/CMakeLists.txt | 6 ++-- modules/skybrowser/skybrowsermodule.cpp | 7 ++-- modules/skybrowser/skybrowsermodule.h | 37 +-------------------- modules/skybrowser/skybrowsermodule_lua.inl | 28 ++++++++-------- 4 files changed, 22 insertions(+), 56 deletions(-) diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index f792be4c41..7c45c9431d 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -30,9 +30,10 @@ set(HEADER_FILES include/screenspaceskybrowser.h include/screenspaceskytarget.h include/wwtdatahandler.h - tinyxml2/tinyxml2.h include/utility.h include/renderableskybrowser.h + include/pair.h + tinyxml2/tinyxml2.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -44,9 +45,10 @@ set(SOURCE_FILES src/screenspaceskybrowser.cpp src/screenspaceskytarget.cpp src/wwtdatahandler.cpp - tinyxml2/tinyxml2.cpp src/utility.cpp src/renderableskybrowser.cpp + src/pair.cpp + tinyxml2/tinyxml2.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index d70c9b5527..6240f20a12 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "skybrowsermodule_lua.inl" #include @@ -391,7 +392,7 @@ SkyBrowserModule::SkyBrowserModule() double deltaTime = global::windowDelegate->deltaTime(); // Fade out or in browser & target - for (SkyBrowserModule::Pair pair : _targetsBrowsers) { + for (Pair pair : _targetsBrowsers) { ScreenSpaceSkyBrowser* browser = pair.getBrowser(); // If outside solar system and browser is visible if (!_cameraInSolarSystem && browser->isEnabled()) { @@ -668,12 +669,12 @@ const WwtDataHandler* SkyBrowserModule::getWWTDataHandler() { return _dataHandler; } -std::vector& SkyBrowserModule::getPairs() +std::vector& SkyBrowserModule::getPairs() { return _targetsBrowsers; } -SkyBrowserModule::Pair* SkyBrowserModule::getPair(std::string id) +Pair* SkyBrowserModule::getPair(std::string id) { auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&](Pair& pair) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index f8fec8fb67..b9bb517dd7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -43,11 +43,11 @@ namespace openspace { class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; class RenderableSkyBrowser; -class ScreenSpaceRenderable; class ScreenSpaceImageLocal; class WwtDataHandler; class SceneGraphNode; class ImageData; +class Pair; class SkyBrowserModule : public OpenSpaceModule { @@ -55,41 +55,6 @@ public: constexpr static const char* Name = "SkyBrowser"; - class Pair { - public: - - Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) - : _target(target), _browser(browser) {} - - Pair(Pair const&) = default; - - Pair& operator=(Pair other) - { - std::swap(_target, other._target); - std::swap(_browser, other._browser); - return *this; - } - - ScreenSpaceSkyTarget* getTarget() { - return _target; - } - - ScreenSpaceSkyBrowser* getBrowser() { - return _browser; - } - - friend bool operator==(const Pair& lhs, const Pair& rhs) { - return lhs._target == rhs._target && lhs._browser == rhs._browser; - } - friend bool operator!=(const Pair& lhs, const Pair& rhs) { - return !(lhs == rhs); - } - - private: - ScreenSpaceSkyTarget* _target{ nullptr }; - ScreenSpaceSkyBrowser* _browser{ nullptr }; - }; - // Constructor & destructor SkyBrowserModule(); virtual ~SkyBrowserModule(); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 2b6a7239ce..f22f6cd827 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -75,8 +76,7 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { - SkyBrowserModule::Pair* pair = module->getPair(id); - pair->getTarget()->lock(); + module->getPair(id)->lock(); } return 0; } @@ -86,8 +86,7 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { - SkyBrowserModule::Pair* pair = module->getPair(id); - pair->getTarget()->unlock(); + module->getPair(id)->unlock(); } return 0; } @@ -101,8 +100,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { - SkyBrowserModule::Pair* pair = module->getPair(id); - pair->getBrowser()->setImageOrder(i, order); + module->getPair(id)->setImageOrder(i, order); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( @@ -153,8 +151,8 @@ namespace openspace::skybrowser::luascriptfunctions { // Send out ID's to the browsers SkyBrowserModule* module = global::moduleEngine->module(); - std::vector pairs = module->getPairs(); - for (SkyBrowserModule::Pair pair : pairs) { + std::vector pairs = module->getPairs(); + for (Pair pair : pairs) { pair.getBrowser()->sendIdToBrowser(); } SceneGraphNode* node = module->get3dBrowser(); @@ -362,9 +360,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Pass data for all the browsers and the corresponding targets if (module->cameraInSolarSystem()) { - std::vector pairs = module->getPairs(); + std::vector pairs = module->getPairs(); - for (SkyBrowserModule::Pair pair : pairs) { + for (Pair pair : pairs) { ScreenSpaceSkyBrowser* browser = pair.getBrowser(); ScreenSpaceSkyTarget* target = pair.getTarget(); std::string id = browser->identifier(); @@ -461,7 +459,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); if(module->cameraInSolarSystem() && module->getPair(id)) { - SkyBrowserModule::Pair* pair = module->getPair(id); + Pair* pair = module->getPair(id); module->startRotation(pair->getTarget()->targetDirectionGalactic()); } else if (!module->cameraInSolarSystem() && module->get3dBrowser()) { @@ -475,7 +473,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - SkyBrowserModule::Pair* pair = module->getPair(id); + Pair* pair = module->getPair(id); if (pair && module->get3dBrowser()) { RenderableSkyBrowser* browser3d = dynamic_cast( @@ -502,7 +500,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::Dictionary message = wwtmessage::setImageOpacity(i, opacity); if (module->getPair(id)) { - SkyBrowserModule::Pair* pair = module->getPair(id); + Pair* pair = module->getPair(id); pair->getBrowser()->sendMessageToWwt(message); } else if (module->get3dBrowser() != nullptr) { @@ -518,7 +516,7 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - SkyBrowserModule::Pair* pair = module->getPair(id); + Pair* pair = module->getPair(id); if (pair) { // Animate the target to the center of the screen pair->getTarget()->unlock(); @@ -591,7 +589,7 @@ namespace openspace::skybrowser::luascriptfunctions { if (module->getPair(id)) { - SkyBrowserModule::Pair* pair = module->getPair(id); + Pair* pair = module->getPair(id); // Remove image pair->getBrowser()->removeSelectedImage(image, i); } From 2b1de9eebbee3775d661a2ed053fdb7e7517d5b2 Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 5 Nov 2021 10:07:30 -0400 Subject: [PATCH 133/251] Use Pair class to communicate with the target and browser --- data/assets/skyBrowserTargetPair.asset | 5 +- .../include/screenspaceskybrowser.h | 15 +- .../skybrowser/include/screenspaceskytarget.h | 19 +- modules/skybrowser/include/utility.h | 4 +- modules/skybrowser/skybrowsermodule.cpp | 270 ++++++++---------- modules/skybrowser/skybrowsermodule.h | 18 +- modules/skybrowser/skybrowsermodule_lua.inl | 108 +++---- .../skybrowser/src/renderableskybrowser.cpp | 2 +- .../skybrowser/src/screenspaceskybrowser.cpp | 39 ++- .../skybrowser/src/screenspaceskytarget.cpp | 128 ++++----- modules/skybrowser/src/utility.cpp | 8 +- 11 files changed, 288 insertions(+), 328 deletions(-) diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset index 4a741655da..5e4857f3b1 100644 --- a/data/assets/skyBrowserTargetPair.asset +++ b/data/assets/skyBrowserTargetPair.asset @@ -26,10 +26,9 @@ local target = { asset.onInitialize(function () openspace.addScreenSpaceRenderable(browser) openspace.addScreenSpaceRenderable(target) - openspace.skybrowser.connectBrowserTarget(browserId) - openspace.skybrowser.connectBrowserTarget(targetId) openspace.skybrowser.addPairToSkyBrowserModule(targetId,browserId) - openspace.skybrowser.setSelectedBrowser(browserId) + openspace.skybrowser.connectBrowserTarget(browserId) + openspace.skybrowser.setSelectedBrowser(browserId) end) asset.onDeinitialize(function () diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 9b81cfd5d2..f73e8e66cd 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -25,8 +25,12 @@ namespace openspace { // Target - browser connection bool connectToSkyTarget(); - void initializeBrowser(); - glm::dvec2 fineTuneTarget(glm::dvec2 drag); + bool isAnimated(); + void startFovAnimation(float fov); + void incrementallyAnimateToFov(float deltaTime); + + void startSyncingWithWwt(); + glm::dvec2 fineTuneVector(glm::dvec2 drag); // Getters returning values bool hasLoadedImages() const; @@ -37,7 +41,7 @@ namespace openspace { // Getters returning references ScreenSpaceSkyTarget* getSkyTarget(); - std::deque& getSelectedImages(); + const std::deque& getSelectedImages(); properties::FloatProperty& getOpacity(); // Setters @@ -58,7 +62,7 @@ namespace openspace { // Communication with WorldWide Telescope void addSelectedImage(const ImageData& image, int i); - void removeSelectedImage(const ImageData& image, int i); + void removeSelectedImage(int i); void setImageOrder(int i, int order); void sendMessageToWwt(const ghoul::Dictionary& msg); void syncWwtView(); @@ -87,6 +91,9 @@ namespace openspace { // Flags bool _hasLoadedImages{ false }; bool _syncViewWithWwt{ false }; + bool _fovIsAnimated{ false }; + float _endVfov{ 0.f }; + float _fovDiff{ 0.01f }; // Resizing of browser glm::vec2 _originalDimensions; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index f42484986b..f1c6d0ec67 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -26,6 +26,7 @@ namespace openspace { // ScreenSpaceRenderable inherited functions bool initializeGL() override; + bool deinitializeGL() override; bool isReady() const override; void render() override; glm::mat4 scaleMatrix() override; @@ -48,19 +49,18 @@ namespace openspace { void setOpacity(float opacity); // Target directions - glm::dvec3 targetDirectionGalactic() const; - glm::dvec3 targetDirectionEquatorial() const; + glm::dvec3 directionGalactic() const; + glm::dvec3 directionEquatorial() const; // Locking functionality void lock(); void unlock(); bool isLocked(); - - // Animations - void startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfter = true); - void animateToCoordinate(double deltaTime); - bool animateToFov(float endFOV, float deltaTime); + // Animation + bool isAnimated(); + void startAnimation(glm::dvec3 end, bool lockAfter); + void animateToCoordinate(float deltaTime); // Display void highlight(glm::ivec3 addition); void removeHighlight(glm::ivec3 removal); @@ -74,9 +74,9 @@ namespace openspace { properties::DoubleProperty _animationSpeed; // Flags + bool _isLocked{ false }; bool _isAnimated{ false }; bool _lockAfterAnimation{ false }; - bool _isLocked{ false }; // Shader UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, dimensions, lineColor) _uniformCache; @@ -91,11 +91,8 @@ namespace openspace { glm::dvec3 _lockedCoordinates; // Spherical celestial coordinates std::thread _lockTarget; - // Animation of target glm::dvec3 _animationEnd; // Cartesian celestial coordinates glm::dvec3 _animationStart; // Cartesian celestial coordinates - double _animationTime = 1.0; - float _vfovEndAnimation; }; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index bf7627aa19..a869fd753d 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -42,7 +42,7 @@ namespace openspace { // Camera roll and direction // Camera roll is with respect to the equatorial North Pole - bool coordinateIsOutsideView(glm::dvec3 equatorial); + bool coordinateIsInView(glm::dvec3 equatorial); float windowRatio(); double cameraRoll(); glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate); @@ -50,7 +50,7 @@ namespace openspace { glm::dvec3 cameraDirectionGalactic(); glm::dvec3 cameraDirectionEquatorial(); double angleVector(glm::dvec3 start, glm::dvec3 end); - void incrementalAnimationMatrix(glm::dmat4& rotation, glm::dvec3 start, + glm::dmat4 incrementalAnimationMatrix(glm::dvec3 start, glm::dvec3 end, double deltaTime, double speedFactor = 1.0); } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 6240f20a12..cbd04b1d41 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include "skybrowsermodule_lua.inl" #include #include // For printing glm data @@ -288,7 +290,7 @@ SkyBrowserModule::SkyBrowserModule() } // If you start dragging around the target, it should unlock else { - _mouseOnPair->getTarget()->unlock(); + _mouseOnPair->unlock(); } _isDragging = true; @@ -296,7 +298,7 @@ SkyBrowserModule::SkyBrowserModule() } else if (_isBrowser && button == MouseButton::Right) { // If you start dragging around on the browser, the target should unlock - _mouseOnPair->getTarget()->unlock(); + _mouseOnPair->unlock(); // Change view (by moving target) within browser if right mouse click on browser _startMousePosition = _mousePosition; _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); @@ -338,8 +340,8 @@ SkyBrowserModule::SkyBrowserModule() if (_isResizing) { // Calculate scaling factor glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); - glm::vec2 scalingVector = mouseDragVector * _resizeDirection; - glm::vec2 newSizeRelToOld = (_startBrowserSize + (scalingVector)) / _startBrowserSize; + glm::vec2 scaling = mouseDragVector * _resizeDirection; + glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / _startBrowserSize; // Scale the browser _mouseOnPair->getBrowser()->setScale(newSizeRelToOld); @@ -358,7 +360,7 @@ SkyBrowserModule::SkyBrowserModule() } } else if (_fineTuneMode) { - glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneTarget(translation); + glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneVector(translation); _mouseOnPair->getTarget()->translate(fineTune, _startDragPosition); } // If there is no dragging or resizing, look for new objects @@ -385,41 +387,41 @@ SkyBrowserModule::SkyBrowserModule() global::callback::preSync->emplace_back([this]() { + // Disable browser and targets when camera is outside of solar system - double cameraSSBDistance = glm::length( - global::navigationHandler->camera()->positionVec3()); - _cameraInSolarSystem = cameraSSBDistance < _solarSystemRadius; + glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); double deltaTime = global::windowDelegate->deltaTime(); + bool camWasInSolarSystem = _cameraInSolarSystem; + _cameraInSolarSystem = glm::length(cameraPos) < _solarSystemRadius; - // Fade out or in browser & target - for (Pair pair : _targetsBrowsers) { - ScreenSpaceSkyBrowser* browser = pair.getBrowser(); - // If outside solar system and browser is visible - if (!_cameraInSolarSystem && browser->isEnabled()) { - bool fadingIsFinished = fadeBrowserAndTarget(true, _fadingTime, deltaTime); + // Fading flags + bool fadeIsFinished{ false }; + if (_cameraInSolarSystem != camWasInSolarSystem) { + _isTransitioningVizMode = true; - if (fadingIsFinished) { - pair.getBrowser()->property("Enabled")->set(false); - // Select the 3D browser when moving out of the solar system - if (_browser3d != nullptr) { - _selectedBrowser = _browser3d->renderable()->identifier(); - } - } + // Select the 3D browser when moving out of the solar system + if (!_cameraInSolarSystem && _browser3d != nullptr) { + _selectedBrowser = _browser3d->renderable()->identifier(); } - // If within solar system and browser is not visible - else if (_cameraInSolarSystem && !browser->isEnabled()) { - pair.getBrowser()->property("Enabled")->set(true); - // Select the first 2D browser when moving into the solar system - if (_targetsBrowsers.size() != 0) { - _selectedBrowser = std::begin(_targetsBrowsers)->getBrowser()->identifier(); - } - } - // If within solar system and browser is visible - if (_cameraInSolarSystem && browser->isEnabled()) { - fadeBrowserAndTarget(false, _fadingTime, deltaTime); + } - pair.getTarget()->animateToCoordinate(deltaTime); + // Fade pairs if the camera moved in or out the solar system + if (_isTransitioningVizMode) { + if (_cameraInSolarSystem) { + fadeIsFinished = fadeBrowserTargetsToOpaque(deltaTime); } + else { + fadeIsFinished = fadeBrowserTargetsToTransparent(deltaTime); + } + + // The transition is over when the fade is finished + if (fadeIsFinished) { + _isTransitioningVizMode = false; + } + } + + if (_cameraInSolarSystem) { + animateTargets(deltaTime); } if (_cameraIsRotating) { rotateCamera(deltaTime); @@ -431,7 +433,6 @@ SkyBrowserModule::SkyBrowserModule() } SkyBrowserModule::~SkyBrowserModule() { - delete _dataHandler; } void SkyBrowserModule::internalDeinitialize() { @@ -455,7 +456,7 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { fRenderable->registerClass("RenderableSkyBrowser"); // Create data handler dynamically to avoid the linking error that // came up when including the include file in the module header file - _dataHandler = new WwtDataHandler(); + _dataHandler = std::make_unique(); } void SkyBrowserModule::setSelectedObject() @@ -464,46 +465,52 @@ void SkyBrowserModule::setSelectedObject() Pair* lastObj = _mouseOnPair; // Find and save what mouse is currently hovering on - auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers),[&](Pair &pair) { + auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + [&] (Pair &pair) { bool onBrowser = pair.getBrowser()->coordIsInsideCornersScreenSpace(_mousePosition); bool onTarget = pair.getTarget()->coordIsInsideCornersScreenSpace(_mousePosition); - if (onBrowser || onTarget) { - _mouseOnPair = &pair; - _isBrowser = onBrowser; - return true; + if (onBrowser) { + _selectedBrowser = pair.getBrowser()->identifier(); } - return false; + _isBrowser = onBrowser; + + return onBrowser || onTarget; }); if (it == std::end(_targetsBrowsers)) { _mouseOnPair = nullptr; } - + else { + _mouseOnPair = &(*it); + } // Selection has changed if (lastObj != _mouseOnPair) { // Remove highlight if (lastObj) { - lastObj->getBrowser()->removeHighlight(_highlightAddition); - lastObj->getTarget()->removeHighlight(_highlightAddition); + lastObj->removeHighlight(_highlightAddition); } // Add highlight to new selection if (_mouseOnPair) { - _mouseOnPair->getBrowser()->highlight(_highlightAddition); - _mouseOnPair->getTarget()->highlight(_highlightAddition); - std::string id = _mouseOnPair->getBrowser()->identifier(); - std::string info = "Currently selected browser is " + id; - LINFO(info + id); + _mouseOnPair->highlight(_highlightAddition); } } } -void SkyBrowserModule::addTargetBrowserPair(ScreenSpaceSkyTarget* newTarget, ScreenSpaceSkyBrowser* newBrowser) { +void SkyBrowserModule::addTargetBrowserPair(std::string targetId, std::string browserId) { + + ScreenSpaceSkyTarget* target = dynamic_cast( + global::renderEngine->screenSpaceRenderable(targetId) + ); + ScreenSpaceSkyBrowser* browser = dynamic_cast( + global::renderEngine->screenSpaceRenderable(browserId) + ); + // Assert pair to have both target and browser - if (newBrowser && newTarget) { - Pair newPair(newBrowser, newTarget); + if (browser && target) { + Pair newPair(browser, target); _targetsBrowsers.push_back(newPair); } } @@ -546,21 +553,17 @@ void SkyBrowserModule::createTargetBrowserPair() { scripting::ScriptEngine::RemoteScripting::Yes ); + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + + idBrowser + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + openspace::global::scriptEngine->queueScript( "openspace.skybrowser.connectBrowserTarget('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes ); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.connectBrowserTarget('" + idTarget + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes @@ -576,11 +579,10 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { auto it = std::remove(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), *found); - std::string browserId = found->getBrowser()->identifier(); std::string targetId = found->getTarget()->identifier(); // Remove from engine openspace::global::scriptEngine->queueScript( - "openspace.removeScreenSpaceRenderable('" + browserId + "');", + "openspace.removeScreenSpaceRenderable('" + found->browserId() + "');", scripting::ScriptEngine::RemoteScripting::Yes ); @@ -606,37 +608,40 @@ void SkyBrowserModule::selectImage2dBrowser(int i) const ImageData& image = _dataHandler->getImage(i); // Load image into browser LINFO("Loading image " + image.name); - selected->getBrowser()->addSelectedImage(image, i); - - // If the image has coordinates, move the target + selected->selectImage(image, i); + + bool isInView = skybrowser::coordinateIsInView(image.equatorialCartesian); + // If the coordinate is not in view, rotate camera if (image.hasCelestialCoords) { - - // Animate the target to the image coordinate position - selected->getTarget()->unlock(); - selected->getTarget()->startAnimation(image.equatorialCartesian, image.fov); - - // If the coordinate is not in view, rotate camera - if (skybrowser::coordinateIsOutsideView(image.equatorialCartesian)) { - glm::dvec3 galactic = skybrowser::equatorialToGalactic(image.equatorialCartesian); - startRotation(galactic); + if(!isInView) { + rotateCamera(skybrowser::equatorialToGalactic(image.equatorialCartesian)); } } } } - void SkyBrowserModule::selectImage3dBrowser(int i) { - const ImageData& image = _dataHandler->getImage(i); - if (_browser3d) { - RenderableSkyBrowser* browser3d = dynamic_cast( - _browser3d->renderable()); - if (browser3d) { - browser3d->displayImage(image, i); - } + if (!_browser3d) { + return; } + RenderableSkyBrowser* renderable = dynamic_cast( + _browser3d->renderable()); + if (renderable) { + const ImageData& image = _dataHandler->getImage(i); + renderable->displayImage(image, i); + } + } +void SkyBrowserModule::lookAtTarget(std::string id) +{ + Pair* pair = getPair(id); + if (pair) { + rotateCamera(pair->targetDirectionGalactic()); + } +} + void SkyBrowserModule::moveHoverCircle(int i) { const ImageData& image = _dataHandler->getImage(i); @@ -665,7 +670,7 @@ int SkyBrowserModule::nLoadedImages() return _dataHandler->nLoadedImages(); } -const WwtDataHandler* SkyBrowserModule::getWWTDataHandler() { +const std::unique_ptr& SkyBrowserModule::getWWTDataHandler() { return _dataHandler; } @@ -678,8 +683,8 @@ Pair* SkyBrowserModule::getPair(std::string id) { auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&](Pair& pair) { - bool foundBrowser = pair.getBrowser()->identifier() == id; - bool foundTarget = pair.getTarget()->identifier() == id; + bool foundBrowser = pair.browserId() == id; + bool foundTarget = pair.targetId() == id; return foundBrowser || foundTarget; }); return &(*it); @@ -690,6 +695,9 @@ SceneGraphNode* SkyBrowserModule::get3dBrowser() { } void SkyBrowserModule::lookAt3dBrowser() { + if (!_browser3d) { + return; + } std::string id = _browser3d->identifier(); // Target camera on the 3D sky browser openspace::global::scriptEngine->queueScript( @@ -709,7 +717,7 @@ void SkyBrowserModule::lookAt3dBrowser() { ); } -void SkyBrowserModule::startRotation(glm::dvec3 endAnimation) { +void SkyBrowserModule::rotateCamera(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates _endAnimation = endAnimation; _startAnimation = skybrowser::cameraDirectionGalactic(); @@ -721,11 +729,9 @@ void SkyBrowserModule::rotateCamera(double deltaTime) { // Find smallest angle between the two vectors double smallestAngle = skybrowser::angleVector(_startAnimation, _endAnimation); - if(smallestAngle > _threshold) { + if(smallestAngle > _stopAnimationThreshold) { - glm::dmat4 rotMat; - skybrowser::incrementalAnimationMatrix( - rotMat, + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( _startAnimation, _endAnimation, deltaTime, @@ -743,61 +749,39 @@ void SkyBrowserModule::rotateCamera(double deltaTime) { } } -bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTime, - double deltaTime) { - float opacityDelta = static_cast(deltaTime / fadeTime); - float highTreshold = 0.99f; - float lowThreshold = 0.01f; - float transparent = 0.0; - float opaque = 1.0; - - if (makeTransparent) { - opacityDelta *= -1.f; - } - bool finished = true; - +bool SkyBrowserModule::fadeBrowserTargetsToTransparent(double deltaTime) +{ + bool fadeIsFinished{ false }; for (Pair pair : _targetsBrowsers) { - ScreenSpaceSkyBrowser* browser = pair.getBrowser(); - ScreenSpaceSkyTarget* target = pair.getTarget(); - - bool targetFinished = true; - bool browserFinished = true; - - if (target) { - target->setOpacity(target->opacity() + opacityDelta); - float opacityTarget = abs(target->opacity()); - - if (makeTransparent) { - targetFinished = opacityTarget < lowThreshold; - } - else { - targetFinished = opacityTarget > highTreshold; - } - if (targetFinished) { - float newOpacity = makeTransparent ? transparent : opaque; - target->setOpacity(newOpacity); + if (pair.isEnabled()) { + bool finished = pair.fadeToTransparent(_fadingTime, deltaTime); + if (finished) { + pair.disable(); } + fadeIsFinished &= finished; + } + } + return fadeIsFinished; +} + +bool SkyBrowserModule::fadeBrowserTargetsToOpaque(double deltaTime) +{ + bool fadeIsFinished{ false }; + for (Pair pair : _targetsBrowsers) { + if (pair.isEnabled()) { + fadeIsFinished &= pair.fadeToOpaque(_fadingTime, deltaTime); + } + } + return fadeIsFinished; +} + +void SkyBrowserModule::animateTargets(double deltaTime) +{ + for (Pair pair : _targetsBrowsers) { + if (pair.isEnabled()) { + pair.animateToCoordinate(deltaTime); } - // Keep fading the browsers until all are finished - browser->getOpacity() = browser->getOpacity().value() + opacityDelta; - float opacityBrowser = abs(browser->getOpacity().value()); - - if (makeTransparent) { - browserFinished = opacityBrowser < lowThreshold; - } - else { - browserFinished = opacityBrowser > highTreshold; - } - - if (browserFinished && targetFinished) { - browser->getOpacity() = makeTransparent ? transparent : opaque; - } - else { - finished = false; - } - } - return finished; } void SkyBrowserModule::setSelectedBrowser(ScreenSpaceSkyBrowser* browser) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index b9bb517dd7..716b2fcafe 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -63,7 +63,7 @@ public: std::vector& getPairs(); Pair* getPair(std::string id); SceneGraphNode* get3dBrowser(); - const WwtDataHandler* getWWTDataHandler(); + const std::unique_ptr& getWWTDataHandler(); std::string selectedBrowserId(); // Setters @@ -74,9 +74,12 @@ public: void selectImage3dBrowser(int i); // Rotation and animation - void startRotation(glm::dvec3 endAnimation); // Pass in galactic coordinate + + void lookAtTarget(std::string id); void rotateCamera(double deltaTime); - bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime); + bool fadeBrowserTargetsToTransparent(double deltaTime); + bool fadeBrowserTargetsToOpaque(double deltaTime); + void animateTargets(double deltaTime); void lookAt3dBrowser(); // Boolean functions @@ -85,7 +88,7 @@ public: // Managing the browsers void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); - void addTargetBrowserPair(ScreenSpaceSkyTarget* target, ScreenSpaceSkyBrowser* browser); + void addTargetBrowserPair(std::string targetId, std::string browserId); void moveHoverCircle(int i); // Image collection handling @@ -105,6 +108,8 @@ protected: void internalDeinitialize() override; private: + + void rotateCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate // The browsers and targets std::vector _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; @@ -124,6 +129,7 @@ private: bool _isDragging{ false }; bool _cameraInSolarSystem{ true }; bool _cameraIsRotating = false; + bool _isTransitioningVizMode{ false }; // Mouse interaction - dragging and resizing glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers @@ -136,11 +142,11 @@ private: // Animation of rotation of camera to look at coordinate galactic coordinates glm::dvec3 _startAnimation; glm::dvec3 _endAnimation; - double _threshold{ 0.0005 }; + double _stopAnimationThreshold{ 0.0005 }; double _speed{ 1.0 }; // Data handler for the image collections - WwtDataHandler* _dataHandler; + std::unique_ptr _dataHandler; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index f22f6cd827..4d16cd934f 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include @@ -120,12 +118,11 @@ namespace openspace::skybrowser::luascriptfunctions { // Load the collections here because here we know that the browser can execute javascript std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - - ScreenSpaceSkyBrowser* browser = dynamic_cast( - global::renderEngine->screenSpaceRenderable(id)); - if (browser && !browser->hasLoadedImages()) { - browser->sendMessageToWwt(wwtmessage::loadCollection(root)); - browser->setHasLoadedImages(true); + + SkyBrowserModule* module = global::moduleEngine->module(); + + if (module->getPair(id)) { + module->getPair(id)->loadImages(root); } else { SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); @@ -153,7 +150,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); std::vector pairs = module->getPairs(); for (Pair pair : pairs) { - pair.getBrowser()->sendIdToBrowser(); + pair.sendIdToBrowser(); } SceneGraphNode* node = module->get3dBrowser(); if(node) { @@ -169,20 +166,12 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::connectBrowserTarget"); const std::string id = ghoul::lua::value(L, 1); - // Find the ScreenSpaceRenderable that has the id - ScreenSpaceRenderable* found = global::renderEngine->screenSpaceRenderable(id); - ScreenSpaceSkyBrowser* browser = dynamic_cast(found); - ScreenSpaceSkyTarget* target = dynamic_cast(found); + // Connect the target and browser to each other + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(id)) { + module->getPair(id)->connectPair(); + } - // Connect it to its corresponding target / browser - if (browser) { - - browser->connectToSkyTarget(); - } - else if (target) { - - target->findSkyBrowser(); - } return 0; } @@ -190,15 +179,11 @@ namespace openspace::skybrowser::luascriptfunctions { // Initialize browser with ID and its corresponding target ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowser"); const std::string id = ghoul::lua::value(L, 1); - ScreenSpaceSkyBrowser* browser = dynamic_cast( - global::renderEngine->screenSpaceRenderable(id)); + LINFO("Initializing sky browser " + id); - if (browser) { - browser->initializeBrowser(); - ScreenSpaceSkyTarget* target = browser->getSkyTarget(); - if (target) { - target->findSkyBrowser(); - } + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(id)) { + module->getPair(id)->synchronizeWithWwt(); } else { SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); @@ -240,15 +225,7 @@ namespace openspace::skybrowser::luascriptfunctions { LINFO("Add browser " + browserId + " to sky browser module."); LINFO("Add target " + targetId + " to sky browser module."); - ScreenSpaceSkyTarget* target = dynamic_cast( - global::renderEngine->screenSpaceRenderable(targetId) - ); - ScreenSpaceSkyBrowser* browser = dynamic_cast( - global::renderEngine->screenSpaceRenderable(browserId) - ); - - - module->addTargetBrowserPair(target, browser); + module->addTargetBrowserPair(targetId, browserId); return 0; } @@ -363,22 +340,20 @@ namespace openspace::skybrowser::luascriptfunctions { std::vector pairs = module->getPairs(); for (Pair pair : pairs) { - ScreenSpaceSkyBrowser* browser = pair.getBrowser(); - ScreenSpaceSkyTarget* target = pair.getTarget(); - std::string id = browser->identifier(); + std::string id = pair.browserId(); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - std::deque selectedImages = browser->getSelectedImages(); + const std::deque selectedImages = pair.getSelectedImages(); std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) { selectedImagesVector.push_back(i); }); - glm::dvec3 celestialCart = target->targetDirectionEquatorial(); + glm::dvec3 celestialCart = pair.targetDirectionEquatorial(); glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; // Convert color to vector so ghoul can read it - glm::ivec3 color = browser->borderColor(); + glm::ivec3 color = pair.borderColor(); std::vector colorVec = { color.r, color.g, color.b }; ghoul::lua::push(L, id); @@ -386,9 +361,9 @@ namespace openspace::skybrowser::luascriptfunctions { // Push ("Key", value) ghoul::lua::push(L, "id", id); lua_settable(L, -3); - ghoul::lua::push(L, "name", browser->guiName()); + ghoul::lua::push(L, "name", pair.browserGuiName()); lua_settable(L, -3); - ghoul::lua::push(L, "FOV", browser->verticalFov()); + ghoul::lua::push(L, "FOV", pair.verticalFov()); lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); @@ -400,7 +375,7 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); - ghoul::lua::push(L, "isLocked", target->isLocked()); + ghoul::lua::push(L, "isLocked", pair.isLocked()); lua_settable(L, -3); // Set table for the current target @@ -408,7 +383,7 @@ namespace openspace::skybrowser::luascriptfunctions { } } - else { + else if(module->get3dBrowser()){ SceneGraphNode* node = module->get3dBrowser(); RenderableSkyBrowser* browser3d = dynamic_cast( node->renderable()); @@ -458,11 +433,10 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if(module->cameraInSolarSystem() && module->getPair(id)) { - Pair* pair = module->getPair(id); - module->startRotation(pair->getTarget()->targetDirectionGalactic()); + if(module->cameraInSolarSystem()) { + module->lookAtTarget(id); } - else if (!module->cameraInSolarSystem() && module->get3dBrowser()) { + else { module->lookAt3dBrowser(); } @@ -481,8 +455,8 @@ namespace openspace::skybrowser::luascriptfunctions { // Empty 3D browser selection browser3d->getSelectedImages().clear(); // Copy 2D selection of images to 3D browser - std::deque images = pair->getBrowser()->getSelectedImages(); - std::for_each(std::begin(images), std::end(images), [&](int i) { + const std::deque images = pair->getSelectedImages(); + std::for_each(std::begin(images), std::end(images), [&](const int i) { const ImageData& image = module->getWWTDataHandler()->getImage(i); browser3d->displayImage(image, i); }); @@ -494,14 +468,14 @@ namespace openspace::skybrowser::luascriptfunctions { int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); const std::string id = ghoul::lua::value(L, 1); - const std::string i = std::to_string(ghoul::lua::value(L, 2)); + const int i = ghoul::lua::value(L, 2); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - ghoul::Dictionary message = wwtmessage::setImageOpacity(i, opacity); + ghoul::Dictionary message = wwtmessage::setImageOpacity(std::to_string(i), opacity); if (module->getPair(id)) { - Pair* pair = module->getPair(id); - pair->getBrowser()->sendMessageToWwt(message); + module->getPair(id)->setImageOpacity(i, opacity); + } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( @@ -518,13 +492,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); Pair* pair = module->getPair(id); if (pair) { - // Animate the target to the center of the screen - pair->getTarget()->unlock(); - // Get camera direction in celestial spherical coordinates - glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); - // Keep the current fov - float currentFov = pair->getBrowser()->verticalFov(); - pair->getTarget()->startAnimation(viewDirection, currentFov, false); + pair->centerTargetOnScreen(); } return 0; @@ -587,11 +555,9 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& image = module->getWWTDataHandler()->getImage(i); - - if (module->getPair(id)) { - Pair* pair = module->getPair(id); - // Remove image - pair->getBrowser()->removeSelectedImage(image, i); + Pair* pair = module->getPair(id); + if (pair) { + pair->removeSelectedImage(i); } else if (module->get3dBrowser() != nullptr) { RenderableSkyBrowser* browser3d = dynamic_cast( diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 58dd3c1325..5654660a67 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -190,7 +190,7 @@ namespace openspace { return true; } - void RenderableSkyBrowser::displayImage(const ImageData& image, int i) { + void RenderableSkyBrowser::displayImage(const ImageData& image, const int i) { sendMessageToWwt(wwtmessage::moveCamera(image.equatorialSpherical, image.fov, 0.0)); _verticalFov = image.fov; // Add to selected images if there are no duplicates diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 1eb1ddb010..f8292ce6a6 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -174,22 +174,18 @@ namespace openspace { setWebpageBorderColor( color - removal ); } - void ScreenSpaceSkyBrowser::initializeBrowser() { - // If the camera is already synced, the browser is already initialized + void ScreenSpaceSkyBrowser::startSyncingWithWwt() { + // If the camera is already synced, the browser is already syncing if (!_syncViewWithWwt) { _syncViewWithWwt = true; // Set border color setWebpageBorderColor(_borderColor.value()); - // Connect to target if they haven't been connected - if (!_skyTarget) { - connectToSkyTarget(); - } // Track target syncWwtView(); } } - glm::dvec2 ScreenSpaceSkyBrowser::fineTuneTarget(glm::dvec2 drag) { + glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) { // Fine tuning of target glm::dvec2 wwtFov = fieldsOfView(); glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); @@ -220,6 +216,29 @@ namespace openspace { return _skyTarget; } + bool ScreenSpaceSkyBrowser::isAnimated() + { + return _fovIsAnimated; + } + + void ScreenSpaceSkyBrowser::startAnimation(float fov) + { + _fovIsAnimated = true; + _endVfov = fov; + } + + void ScreenSpaceSkyBrowser::animateToFov(float deltaTime) + { + // If distance is small enough, stop animating + float diff = verticalFov() - _endVfov; + if (abs(diff) > _fovDiff) { + setVerticalFovWithScroll(diff); + } + else { + _fovIsAnimated = false; + } + } + ScreenSpaceSkyTarget* ScreenSpaceSkyBrowser::getSkyTarget() { return _skyTarget; } @@ -299,7 +318,7 @@ namespace openspace { while (_syncViewWithWwt) { if (_skyTarget) { // Message WorldWide Telescope current view - glm::dvec3 cartesian = _skyTarget->targetDirectionEquatorial(); + glm::dvec3 cartesian = _skyTarget->directionEquatorial(); ghoul::Dictionary message = wwtmessage::moveCamera( skybrowser::cartesianToSpherical(cartesian), @@ -391,7 +410,7 @@ namespace openspace { return _opacity; } - std::deque& ScreenSpaceSkyBrowser::getSelectedImages() { + const std::deque& ScreenSpaceSkyBrowser::getSelectedImages() { return _selectedImages; } @@ -408,7 +427,7 @@ namespace openspace { } } - void ScreenSpaceSkyBrowser::removeSelectedImage(const ImageData& image, int i) { + void ScreenSpaceSkyBrowser::removeSelectedImage(int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); bool found = it != std::end(_selectedImages); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index f22c86b4d4..78d8d25756 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -188,6 +188,14 @@ namespace openspace { return isReady(); } + bool ScreenSpaceSkyTarget::deinitializeGL() + { + if (isLocked()) { + unlock(); + } + return ScreenSpaceRenderable::deinitializeGL(); + } + glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { // To ensure the plane has the right ratio // The _scale us how much of the windows height the browser covers: e.g. a browser @@ -268,7 +276,7 @@ namespace openspace { _objectSize = dimensions; } - glm::dvec3 ScreenSpaceSkyTarget::targetDirectionGalactic() const { + glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { glm::dmat4 rotation = glm::inverse( global::navigationHandler->camera()->viewRotationMatrix()); glm::dvec4 position = glm::dvec4(_cartesianPosition.value(), 1.0); @@ -301,7 +309,7 @@ namespace openspace { unlock(); } _isLocked = true; - _lockedCoordinates = targetDirectionEquatorial(); + _lockedCoordinates = directionEquatorial(); // Start a thread to enable user interactions while locking target _lockTarget = std::thread([&] { @@ -315,71 +323,56 @@ namespace openspace { return _isLocked; } - glm::dvec3 ScreenSpaceSkyTarget::targetDirectionEquatorial() const { + bool ScreenSpaceSkyTarget::isAnimated() + { + return _isAnimated; + } + + void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 end, bool lockAfter) + { + _animationStart = glm::normalize(directionEquatorial()); + _animationEnd = glm::normalize(end); + _lockAfterAnimation = lockAfter; + _isAnimated = true; + } + + void ScreenSpaceSkyTarget::animateToCoordinate(float deltaTime) + { + // Find smallest angle between the two vectors + double smallestAngle = skybrowser::angleVector(_animationStart, _animationEnd); + // Only keep animating when target is not at final position + if (smallestAngle <= _stopAnimationThreshold) { + // Set the exact target position + _cartesianPosition = skybrowser::equatorialToScreenSpace(_animationEnd); + _isAnimated = false; + // Lock target when it first arrives to the position + if (!isLocked() && _lockAfterAnimation) { + lock(); + } + + return; + } + + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( + _animationStart, + _animationEnd, + deltaTime, + _animationSpeed + ); + // Rotate target direction + glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); + // Convert to screen space + _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); + // Update position + _animationStart = glm::normalize(newDir); + } + + glm::dvec3 ScreenSpaceSkyTarget::directionEquatorial() const { // Calculate the galactic coordinate of the target direction // projected onto the celestial sphere return skybrowser::localCameraToEquatorial(_cartesianPosition.value()); } - void ScreenSpaceSkyTarget::animateToCoordinate(double deltaTime) { - - if (_isAnimated) { - - // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleVector(_animationStart, _animationEnd); - // Only keep animating when target is not at final position - if (smallestAngle > _stopAnimationThreshold) { - glm::dmat4 rotMat; - skybrowser::incrementalAnimationMatrix( - rotMat, - _animationStart, - _animationEnd, - deltaTime, - _animationSpeed - ); - // Rotate target direction - glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); - // Convert to screen space - _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); - // Update position - _animationStart = glm::normalize(newDir); - } - else { - // Set the exact target position - _cartesianPosition = skybrowser::equatorialToScreenSpace(_animationEnd); - // Lock target when it first arrives to the position - if (!_isLocked && _lockAfterAnimation) { - lock(); - } - // When target is in position, animate the FOV until it has finished - if(animateToFov(_vfovEndAnimation, deltaTime)) { - _isAnimated = false; - } - } - } - } - - bool ScreenSpaceSkyTarget::animateToFov(float endFOV, float deltaTime) { - if (!_skyBrowser) { - findSkyBrowser(); - } - if (_skyBrowser) { - double distance = static_cast(_skyBrowser->verticalFov()) - endFOV; - - // If distance is too large, keep animating - if (abs(distance) > 0.01) { - _skyBrowser->setVerticalFovWithScroll(distance); - return false; - } - // Animation is finished - return true; - } - else { - LINFO("Target can't connect to browser!"); - } - - return true; - } void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) { @@ -391,17 +384,6 @@ namespace openspace { _color -= removal; } - void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 coordsEnd, float FOVEnd, - bool lockAfterwards) { - // Save the Cartesian celestial coordinates for animation - // The coordinates are Cartesian to avoid wrap-around issues - _animationEnd = glm::normalize(coordsEnd); - _animationStart = glm::normalize(targetDirectionEquatorial()); - _vfovEndAnimation = FOVEnd; - _isAnimated = true; - _lockAfterAnimation = lockAfterwards; - } - float ScreenSpaceSkyTarget::opacity() const { return _opacity.value(); } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 406f9f6639..6a0e418c83 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -131,7 +131,7 @@ namespace openspace::skybrowser { return windowRatio.x / windowRatio.y; } - bool coordinateIsOutsideView(glm::dvec3 equatorial) { + bool coordinateIsInView(glm::dvec3 equatorial) { // Check if image coordinate is within current FOV glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial); double r = static_cast(windowRatio()); @@ -140,7 +140,7 @@ namespace openspace::skybrowser { abs(coordsScreen.y) < 1.f && coordsScreen.z < 0); bool coordIsBehindCamera = coordsScreen.z > 0; // If the coordinate is not in view, rotate camera - return !coordIsWithinView || coordIsBehindCamera; + return coordIsWithinView; } // Transforms a pixel coordinate to a screen space coordinate @@ -172,7 +172,7 @@ namespace openspace::skybrowser { return std::acos(cos); } - void incrementalAnimationMatrix(glm::dmat4& rotation, glm::dvec3 start, + glm::dmat4 incrementalAnimationMatrix(glm::dvec3 start, glm::dvec3 end, double deltaTime, double speedFactor) { @@ -182,7 +182,7 @@ namespace openspace::skybrowser { // Create the rotation matrix for local camera space glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end)); - rotation = glm::rotate(rotationAngle, rotationAxis); + return glm::rotate(rotationAngle, rotationAxis); } } From 1e4f4dc19a49d1c599fda860e00bdaa9e1e61359 Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 5 Nov 2021 11:15:47 -0400 Subject: [PATCH 134/251] Make max width 90 columns --- .../include/screenspaceskybrowser.h | 5 +- .../skybrowser/include/screenspaceskytarget.h | 9 ++- modules/skybrowser/skybrowsermodule.cpp | 71 +++++++++++++------ modules/skybrowser/skybrowsermodule.h | 6 +- modules/skybrowser/skybrowsermodule_lua.inl | 68 +++++++++++------- .../skybrowser/src/renderableskybrowser.cpp | 25 +++++-- .../skybrowser/src/screenspaceskybrowser.cpp | 33 +++++---- .../skybrowser/src/screenspaceskytarget.cpp | 4 +- 8 files changed, 145 insertions(+), 76 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index f73e8e66cd..1699f968ae 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -52,8 +52,6 @@ namespace openspace { void setScale(float scalingFactor); void setWebpageBorderColor(glm::ivec3 color); - // Communication with the web page - void executeJavascript(std::string script); void sendIdToBrowser(); // Display @@ -82,6 +80,9 @@ namespace openspace { //void translate(glm::vec2 translation); private: + // Communication with the web page + void executeJavascript(std::string script); + // Properties properties::FloatProperty _verticalFov; properties::StringProperty _skyTargetId; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index f1c6d0ec67..a064fd498d 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -79,7 +79,14 @@ namespace openspace { bool _lockAfterAnimation{ false }; // Shader - UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, dimensions, lineColor) _uniformCache; + UniformCache( + modelTransform, + viewProj, + showCrosshair, + showRectangle, + lineWidth, + dimensions, + lineColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index cbd04b1d41..1e38c9bde5 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -274,16 +274,25 @@ SkyBrowserModule::SkyBrowserModule() if (button == MouseButton::Left) { _cameraIsRotating = false; _startMousePosition = _mousePosition; - _startDragPosition = _isBrowser ? _mouseOnPair->getBrowser()->screenSpacePosition() - : _mouseOnPair->getTarget()->screenSpacePosition(); + if (_isBrowser) { + _startDragPosition = _mouseOnPair->getBrowser()-> + screenSpacePosition(); + } + else { + _startDragPosition = _mouseOnPair->getTarget()-> + screenSpacePosition(); + } // If current object is browser, check for resizing if (_isBrowser) { // Resize browser if mouse is over resize button - _resizeDirection = _mouseOnPair->getBrowser()->isOnResizeArea(_mousePosition); + _resizeDirection = _mouseOnPair->getBrowser()->isOnResizeArea( + _mousePosition + ); if (_resizeDirection != glm::vec2{ 0 }) { _mouseOnPair->getBrowser()->saveResizeStartSize(); - _startBrowserSize = _mouseOnPair->getBrowser()->screenSpaceDimensions(); + _startBrowserSize = _mouseOnPair->getBrowser()-> + screenSpaceDimensions(); _isResizing = true; return true; } @@ -297,9 +306,10 @@ SkyBrowserModule::SkyBrowserModule() return true; } else if (_isBrowser && button == MouseButton::Right) { - // If you start dragging around on the browser, the target should unlock + // If you start dragging around on the browser, the target unlocks _mouseOnPair->unlock(); - // Change view (by moving target) within browser if right mouse click on browser + // Change view (by moving target) within browser if right mouse + // click on browser _startMousePosition = _mousePosition; _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); _fineTuneMode = true; @@ -339,28 +349,37 @@ SkyBrowserModule::SkyBrowserModule() if (_isDragging || _isResizing) { if (_isResizing) { // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); + glm::vec2 mouseDragVector = (_mousePosition-_startMousePosition); glm::vec2 scaling = mouseDragVector * _resizeDirection; - glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / _startBrowserSize; + glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / + _startBrowserSize; // Scale the browser _mouseOnPair->getBrowser()->setScale(newSizeRelToOld); - // For dragging functionality, translate so it looks like the browser - // isn't moving. Make sure the browser doesn't move in directions it's - // not supposed to + // For dragging functionality, translate so it looks like the + // browser isn't moving. Make sure the browser doesn't move in + // directions it's not supposed to translation = mouseDragVector * abs(_resizeDirection) / 2.f; } // Translate if (_isBrowser) { - _mouseOnPair->getBrowser()->translate(translation, _startDragPosition); + _mouseOnPair->getBrowser()->translate( + translation, + _startDragPosition + ); } else { - _mouseOnPair->getTarget()->translate(translation, _startDragPosition); + _mouseOnPair->getTarget()->translate( + translation, + _startDragPosition + ); } } else if (_fineTuneMode) { - glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneVector(translation); + glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneVector( + translation + ); _mouseOnPair->getTarget()->translate(fineTune, _startDragPosition); } // If there is no dragging or resizing, look for new objects @@ -377,7 +396,9 @@ SkyBrowserModule::SkyBrowserModule() // If mouse is on browser or target, apply zoom if (_mouseOnPair) { - _mouseOnPair->getBrowser()->setVerticalFovWithScroll(static_cast(scroll)); + _mouseOnPair->getBrowser()->setVerticalFovWithScroll( + static_cast(scroll) + ); return true; } @@ -424,7 +445,7 @@ SkyBrowserModule::SkyBrowserModule() animateTargets(deltaTime); } if (_cameraIsRotating) { - rotateCamera(deltaTime); + incrementallyRotateCamera(deltaTime); } }); @@ -467,8 +488,12 @@ void SkyBrowserModule::setSelectedObject() // Find and save what mouse is currently hovering on auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&] (Pair &pair) { - bool onBrowser = pair.getBrowser()->coordIsInsideCornersScreenSpace(_mousePosition); - bool onTarget = pair.getTarget()->coordIsInsideCornersScreenSpace(_mousePosition); + bool onBrowser = pair.getBrowser()->coordIsInsideCornersScreenSpace( + _mousePosition + ); + bool onTarget = pair.getTarget()->coordIsInsideCornersScreenSpace( + _mousePosition + ); if (onBrowser) { _selectedBrowser = pair.getBrowser()->identifier(); } @@ -614,7 +639,9 @@ void SkyBrowserModule::selectImage2dBrowser(int i) // If the coordinate is not in view, rotate camera if (image.hasCelestialCoords) { if(!isInView) { - rotateCamera(skybrowser::equatorialToGalactic(image.equatorialCartesian)); + startRotatingCamera( + skybrowser::equatorialToGalactic(image.equatorialCartesian) + ); } } } @@ -638,7 +665,7 @@ void SkyBrowserModule::lookAtTarget(std::string id) { Pair* pair = getPair(id); if (pair) { - rotateCamera(pair->targetDirectionGalactic()); + startRotatingCamera(pair->targetDirectionGalactic()); } } @@ -717,14 +744,14 @@ void SkyBrowserModule::lookAt3dBrowser() { ); } -void SkyBrowserModule::rotateCamera(glm::dvec3 endAnimation) { +void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates _endAnimation = endAnimation; _startAnimation = skybrowser::cameraDirectionGalactic(); _cameraIsRotating = true; } -void SkyBrowserModule::rotateCamera(double deltaTime) { +void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { // Find smallest angle between the two vectors double smallestAngle = skybrowser::angleVector(_startAnimation, _endAnimation); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 716b2fcafe..3ed58e7fae 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -76,7 +76,7 @@ public: // Rotation and animation void lookAtTarget(std::string id); - void rotateCamera(double deltaTime); + void incrementallyRotateCamera(double deltaTime); bool fadeBrowserTargetsToTransparent(double deltaTime); bool fadeBrowserTargetsToOpaque(double deltaTime); void animateTargets(double deltaTime); @@ -109,7 +109,7 @@ protected: private: - void rotateCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate + void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate // The browsers and targets std::vector _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; @@ -142,7 +142,7 @@ private: // Animation of rotation of camera to look at coordinate galactic coordinates glm::dvec3 _startAnimation; glm::dvec3 _endAnimation; - double _stopAnimationThreshold{ 0.0005 }; + double _stopAnimationThreshold{ 0.05 }; double _speed{ 1.0 }; // Data handler for the image collections diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4d16cd934f..a2049272d0 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -116,8 +116,10 @@ namespace openspace::skybrowser::luascriptfunctions { LINFO("Connection established to WorldWide Telescope application in " + id); LINFO("Loading image collections to " + id); - // Load the collections here because here we know that the browser can execute javascript - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; + // Load the collections here because here we know that the browser can execute + // javascript + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" + "wwt-web-client/master/assets/webclient-explore-root.wtml"; SkyBrowserModule* module = global::moduleEngine->module(); @@ -238,8 +240,10 @@ namespace openspace::skybrowser::luascriptfunctions { // If no data has been loaded yet, download the data from the web! if (module->nLoadedImages() == 0) { - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; - //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" + "wwt-web-client/master/assets/webclient-explore-root.wtml"; + //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/" + //"catalog.aspx?W=hubble"; std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); // 3D images @@ -249,7 +253,10 @@ namespace openspace::skybrowser::luascriptfunctions { // Load speck files for 3D positions std::filesystem::path globularClusters = absPath(http + globular); std::filesystem::path openClusters = absPath(http + open); - std::vector specks = { openClusters, globularClusters }; + std::vector specks = { + openClusters, + globularClusters + }; module->loadImages(root, directory, specks); } @@ -259,11 +266,11 @@ namespace openspace::skybrowser::luascriptfunctions { for (int i = 0; i < module->nLoadedImages(); i++) { const ImageData& img = module->getWWTDataHandler()->getImage(i); - glm::dvec3 cartCoords = img.equatorialCartesian; + glm::dvec3 coords = img.equatorialCartesian; glm::dvec3 position = img.position3d; // Conversions for ghoul - std::vector cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z }; + std::vector cartCoordsVec = { coords.x, coords.y, coords.z }; std::vector position3d = { position.x, position.y, position.z }; // Index for current ImageData @@ -310,10 +317,10 @@ namespace openspace::skybrowser::luascriptfunctions { // Add the window data for OpenSpace ghoul::lua::push(L, "OpenSpace"); lua_newtable(L); - glm::dvec3 cartesianJ2000 = skybrowser::cameraDirectionEquatorial(); - glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000); + glm::dvec3 cartesian = skybrowser::cameraDirectionEquatorial(); + glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); // Convert to vector so ghoul can read it - std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; + std::vector viewDirCelestVec = { cartesian.x, cartesian.y, cartesian.z }; // Calculate the smallest FOV of vertical and horizontal @@ -324,9 +331,9 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); lua_settable(L, -3); - ghoul::lua::push(L, "ra", sphericalJ2000.x); + ghoul::lua::push(L, "ra", spherical.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", sphericalJ2000.y); + ghoul::lua::push(L, "dec", spherical.y); lua_settable(L, -3); ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); lua_settable(L, -3); @@ -348,10 +355,14 @@ namespace openspace::skybrowser::luascriptfunctions { selectedImagesVector.push_back(i); }); - glm::dvec3 celestialCart = pair.targetDirectionEquatorial(); - glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); + glm::dvec3 cartesian = pair.targetDirectionEquatorial(); + glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); - std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; + std::vector cartesianVec = { + cartesian.x, + cartesian.y, + cartesian.z + }; // Convert color to vector so ghoul can read it glm::ivec3 color = pair.borderColor(); std::vector colorVec = { color.r, color.g, color.b }; @@ -367,11 +378,11 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", celestialCartVec); + ghoul::lua::push(L, "cartesianDirection", cartesianVec); lua_settable(L, -3); - ghoul::lua::push(L, "ra", celestialSpherical.x); + ghoul::lua::push(L, "ra", spherical.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", celestialSpherical.y); + ghoul::lua::push(L, "dec", spherical.y); lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); @@ -393,10 +404,14 @@ namespace openspace::skybrowser::luascriptfunctions { std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { selectedImagesVector.push_back(index); }); - glm::dvec3 worldPosition = node->position(); - glm::dvec3 celestialCart = skybrowser::galacticToEquatorial(worldPosition); - glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart); - std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; + glm::dvec3 position3dBrowser = node->position(); + glm::dvec3 cartesian = skybrowser::galacticToEquatorial(position3dBrowser); + glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); + std::vector celestialCartVec = { + cartesian.x, + cartesian.y, + cartesian.z + }; // Convert color to vector so ghoul can read it //glm::ivec3 color = browser->_borderColor.value(); std::vector colorVec = { 200, 200, 200 }; @@ -414,9 +429,9 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", celestialCartVec); lua_settable(L, -3); - ghoul::lua::push(L, "ra", celestialSpherical.x); + ghoul::lua::push(L, "ra", spherical.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", celestialSpherical.y); + ghoul::lua::push(L, "dec", spherical.y); lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); @@ -471,7 +486,10 @@ namespace openspace::skybrowser::luascriptfunctions { const int i = ghoul::lua::value(L, 2); double opacity = ghoul::lua::value(L, 3); SkyBrowserModule* module = global::moduleEngine->module(); - ghoul::Dictionary message = wwtmessage::setImageOpacity(std::to_string(i), opacity); + ghoul::Dictionary message = wwtmessage::setImageOpacity( + std::to_string(i), + opacity + ); if (module->getPair(id)) { module->getPair(id)->setImageOpacity(i, opacity); diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 5654660a67..48a49b1d4c 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -178,7 +178,9 @@ namespace openspace { void RenderableSkyBrowser::executeJavascript(std::string script) const { //LINFOC(_loggerCat, "Executing javascript " + script); - if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) { + bool isBrowserReady = _browserInstance && _browserInstance->getBrowser(); + bool isMainFrameReady = _browserInstance->getBrowser()->GetMainFrame(); + if (isBrowserReady && isMainFrameReady) { CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); frame->ExecuteJavaScript(script, frame->GetURL(), 0); } @@ -191,7 +193,12 @@ namespace openspace { } void RenderableSkyBrowser::displayImage(const ImageData& image, const int i) { - sendMessageToWwt(wwtmessage::moveCamera(image.equatorialSpherical, image.fov, 0.0)); + ghoul::Dictionary msg = wwtmessage::moveCamera( + image.equatorialSpherical, + image.fov, + 0.0 + ); + sendMessageToWwt(msg); _verticalFov = image.fov; // Add to selected images if there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); @@ -232,8 +239,12 @@ namespace openspace { glm::dvec2 aim{ 0.0 }; // Send a message just to establish contact - ghoul::Dictionary message = wwtmessage::moveCamera(aim, _verticalFov, 0.0); - sendMessageToWwt(message); + ghoul::Dictionary msg = wwtmessage::moveCamera( + aim, + _verticalFov, + 0.0 + ); + sendMessageToWwt(msg); // Sleep so we don't bombard WWT with too many messages std::this_thread::sleep_for(std::chrono::milliseconds(500)); @@ -305,7 +316,11 @@ namespace openspace { void RenderableSkyBrowser::setImageLayerOrder(int i, int order) { // Remove from selected list - auto current = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + auto current = std::find( + std::begin(_selectedImages), + std::end(_selectedImages), + i + ); auto target = std::begin(_selectedImages) + order; // Make sure the image was found in the list diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index f8292ce6a6..e4376f0ae4 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -76,7 +76,12 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) - , _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0), glm::ivec2(300)) + , _browserDimensions( + BrowserDimensionInfo, + _dimensions, + glm::ivec2(0), + glm::ivec2(300) + ) , _verticalFov(VerticalFovInfo, 10.f, 0.1f, 70.f) , _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)) , _skyTargetId(TargetIdInfo) @@ -221,13 +226,13 @@ namespace openspace { return _fovIsAnimated; } - void ScreenSpaceSkyBrowser::startAnimation(float fov) + void ScreenSpaceSkyBrowser::startFovAnimation(float fov) { _fovIsAnimated = true; _endVfov = fov; } - void ScreenSpaceSkyBrowser::animateToFov(float deltaTime) + void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { // If distance is small enough, stop animating float diff = verticalFov() - _endVfov; @@ -334,26 +339,20 @@ namespace openspace { }); } - - // - //void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) { - // glm::vec3 position = _cartesianPosition; - // _cartesianPosition =glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f); - //} - glm::vec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 screenSpaceCoord) { + glm::vec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { glm::vec2 resizePosition = glm::vec2{ 0 }; // Make sure coordinate is on browser - if (!coordIsInsideCornersScreenSpace(screenSpaceCoord)) return resizePosition; + if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; // TO DO: turn this into a vector and use prettier vector arithmetic float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; - bool isOnTop = screenSpaceCoord.y > upperRightCornerScreenSpace().y - resizeAreaY; - bool isOnBottom = screenSpaceCoord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; - bool isOnRight = screenSpaceCoord.x > upperRightCornerScreenSpace().x - resizeAreaX; - bool isOnLeft = screenSpaceCoord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; + bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; + bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; + bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; + bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; resizePosition.x = isOnRight ? 1.f : isOnLeft ? -1.f : 0.f; resizePosition.y = isOnTop ? 1.f : isOnBottom ? -1.f : 0.f; @@ -379,8 +378,8 @@ namespace openspace { // browser covers: e.g. a browser that covers 0.25 of the // height of the window will have scale = 0.25 - float textureRatio = - static_cast(_texture->dimensions().x) / static_cast(_texture->dimensions().y); + float textureRatio = static_cast(_texture->dimensions().x) / + static_cast(_texture->dimensions().y); glm::mat4 scale = glm::scale( glm::mat4(1.f), diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 78d8d25756..388308fdc7 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -314,7 +314,9 @@ namespace openspace { // Start a thread to enable user interactions while locking target _lockTarget = std::thread([&] { while (_isLocked) { - _cartesianPosition = skybrowser::equatorialToScreenSpace(_lockedCoordinates); + _cartesianPosition = skybrowser::equatorialToScreenSpace( + _lockedCoordinates + ); } }); } From 89e483c748ea1fca123f9d35b913c137f8c81f93 Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 5 Nov 2021 12:03:38 -0400 Subject: [PATCH 135/251] Simplify fading functions --- modules/skybrowser/include/pair.h | 98 +++++++++ modules/skybrowser/skybrowsermodule.cpp | 56 ++--- modules/skybrowser/skybrowsermodule.h | 7 +- modules/skybrowser/src/pair.cpp | 276 ++++++++++++++++++++++++ 4 files changed, 401 insertions(+), 36 deletions(-) create mode 100644 modules/skybrowser/include/pair.h create mode 100644 modules/skybrowser/src/pair.cpp diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h new file mode 100644 index 0000000000..2a025691bc --- /dev/null +++ b/modules/skybrowser/include/pair.h @@ -0,0 +1,98 @@ +/***************************************************************************************** + * * + * 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_SKYBROWSER___PAIR___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ + +#include +#include + +namespace openspace { + +class ScreenSpaceSkyBrowser; +class ScreenSpaceSkyTarget; +class ImageData; + +class Pair { +public: + + constexpr static const float AcceptableDiff = 0.01f; + + Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); + Pair(Pair const&) = default; + + Pair& operator=(Pair other); + + void lock(); + void unlock(); + void setImageOrder(int i, int order); + void connectPair(); + void synchronizeWithWwt(); + void removeHighlight(glm::ivec3 color); + void highlight(glm::ivec3 color); + void enable(); + void disable(); + + void startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool shouldLockAfter = true); + void centerTargetOnScreen(); + void incrementallyAnimateToCoordinate(double deltaTime); + void incrementallyFade(float goalState, float fadeTime, float deltaTime); + bool isFinishedFading(float goalState); + bool isCoordOnPair(glm::vec2 mousePosition); + bool isEnabled(); + bool isLocked(); + + glm::ivec3 borderColor(); + glm::dvec3 targetDirectionEquatorial(); + glm::dvec3 targetDirectionGalactic(); + std::string browserGuiName(); + std::string browserId(); + std::string targetId(); + float verticalFov(); + const std::deque& getSelectedImages(); + void selectImage(const ImageData& image, const int i); + void removeSelectedImage(const int i); + void loadImages(std::string collection); + void setImageOpacity(const int i, float opacity); + void sendIdToBrowser(); + + ScreenSpaceSkyTarget* getTarget(); + ScreenSpaceSkyBrowser* getBrowser(); + + friend bool operator==(const Pair& lhs, const Pair& rhs); + friend bool operator!=(const Pair& lhs, const Pair& rhs); + +private: + + static std::string _selected; + bool isTargetFadeFinished(float goalState); + bool isBrowserFadeFinished(float goalState); + + ScreenSpaceSkyTarget* _target{ nullptr }; + ScreenSpaceSkyBrowser* _browser{ nullptr }; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1e38c9bde5..a4e9b46fb1 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -416,7 +416,6 @@ SkyBrowserModule::SkyBrowserModule() _cameraInSolarSystem = glm::length(cameraPos) < _solarSystemRadius; // Fading flags - bool fadeIsFinished{ false }; if (_cameraInSolarSystem != camWasInSolarSystem) { _isTransitioningVizMode = true; @@ -429,20 +428,15 @@ SkyBrowserModule::SkyBrowserModule() // Fade pairs if the camera moved in or out the solar system if (_isTransitioningVizMode) { if (_cameraInSolarSystem) { - fadeIsFinished = fadeBrowserTargetsToOpaque(deltaTime); + incrementallyFadeBrowserTargets(Transparency::Opaque, deltaTime); } else { - fadeIsFinished = fadeBrowserTargetsToTransparent(deltaTime); - } - - // The transition is over when the fade is finished - if (fadeIsFinished) { - _isTransitioningVizMode = false; + incrementallyFadeBrowserTargets(Transparency::Transparent, deltaTime); } } if (_cameraInSolarSystem) { - animateTargets(deltaTime); + incrementallyAnimateTargets(deltaTime); } if (_cameraIsRotating) { incrementallyRotateCamera(deltaTime); @@ -776,33 +770,29 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { } } -bool SkyBrowserModule::fadeBrowserTargetsToTransparent(double deltaTime) +void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float deltaTime) { - bool fadeIsFinished{ false }; - for (Pair pair : _targetsBrowsers) { - if (pair.isEnabled()) { - bool finished = pair.fadeToTransparent(_fadingTime, deltaTime); - if (finished) { - pair.disable(); - } - fadeIsFinished &= finished; - } - } - return fadeIsFinished; -} - -bool SkyBrowserModule::fadeBrowserTargetsToOpaque(double deltaTime) -{ - bool fadeIsFinished{ false }; + float transparency = static_cast(goal); + bool isAllFinished{ false }; for (Pair pair : _targetsBrowsers) { - if (pair.isEnabled()) { - fadeIsFinished &= pair.fadeToOpaque(_fadingTime, deltaTime); - } - } - return fadeIsFinished; + if (pair.isEnabled()) { + pair.incrementallyFade(transparency, _fadingTime, deltaTime); + bool isPairFinished = pair.isFinishedFading(transparency); + + if (isPairFinished && goal == Transparency::Transparent) { + pair.disable(); + } + isAllFinished &= isPairFinished; + } + } + + // The transition is over when the fade is finished + if (isAllFinished) { + _isTransitioningVizMode = false; + } } -void SkyBrowserModule::animateTargets(double deltaTime) +void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) { for (Pair pair : _targetsBrowsers) { if (pair.isEnabled()) { @@ -825,8 +815,6 @@ std::string SkyBrowserModule::selectedBrowserId() { return _selectedBrowser; } - - bool SkyBrowserModule::cameraInSolarSystem() { return _cameraInSolarSystem; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 3ed58e7fae..377b76d86a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -49,6 +49,10 @@ class SceneGraphNode; class ImageData; class Pair; +enum class Transparency { + Transparent = 0, + Opaque = 1 +}; class SkyBrowserModule : public OpenSpaceModule { public: @@ -77,8 +81,7 @@ public: void lookAtTarget(std::string id); void incrementallyRotateCamera(double deltaTime); - bool fadeBrowserTargetsToTransparent(double deltaTime); - bool fadeBrowserTargetsToOpaque(double deltaTime); + void fadeBrowserTargets(Transparency goal, float deltaTime); void animateTargets(double deltaTime); void lookAt3dBrowser(); diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp new file mode 100644 index 0000000000..7a568ff2a8 --- /dev/null +++ b/modules/skybrowser/src/pair.cpp @@ -0,0 +1,276 @@ +/***************************************************************************************** + * * + * 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 + +namespace openspace { + + std::string Pair::_selected = ""; // Define the static variable in the global scope + + Pair::Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) + : _target(target), _browser(browser) + { + assert(browser != nullptr, "Sky browser is null pointer!"); + assert(target != nullptr, "Sky target is null pointer!"); + } + + Pair& Pair::operator=(Pair other) + { + std::swap(_target, other._target); + std::swap(_browser, other._browser); + return *this; + } + + void Pair::lock() { + _target->lock(); + } + + void Pair::unlock() { + _target->unlock(); + } + + void Pair::setImageOrder(int i, int order) { + _browser->setImageOrder(i, order); + } + + void Pair::connectPair() + { + _browser->connectToSkyTarget(); + _target->findSkyBrowser(); + } + + void Pair::synchronizeWithWwt() + { + _browser->startSyncingWithWwt(); + } + + void Pair::removeHighlight(glm::ivec3 color) + { + _target->removeHighlight(color); + _browser->removeHighlight(color); + } + + void Pair::highlight(glm::ivec3 color) + { + _browser->highlight(color); + _target->highlight(color); + } + + bool Pair::isTargetFadeFinished(float goalState) + { + // Is fading finished? + float targetDiff = abs(_target->opacity() - goalState); + + return targetDiff < AcceptableDiff; + } + + bool Pair::isBrowserFadeFinished(float goalState) + { + float browserDiff = abs(_browser->getOpacity().value() - goalState); + return browserDiff < AcceptableDiff; + } + + bool Pair::isCoordOnPair(glm::vec2 mousePosition) + { + bool onBrowser = _browser->coordIsInsideCornersScreenSpace(mousePosition); + bool onTarget = _target->coordIsInsideCornersScreenSpace(mousePosition); + if (onBrowser) { + _selected = _browser->identifier(); + } + else if (onTarget) { + _selected = _target->identifier(); + } + + return onBrowser || onTarget; + } + + void Pair::enable() + { + _browser->property("Enabled")->set(true); + _target->property("Enabled")->set(true); + } + + void Pair::disable() + { + _browser->property("Enabled")->set(false); + _target->property("Enabled")->set(false); + } + + bool Pair::isEnabled() + { + return _target->isEnabled() && _browser->isEnabled(); + } + + bool Pair::isLocked() + { + return _target->isLocked(); + } + + glm::ivec3 Pair::borderColor() + { + return _browser->borderColor(); + } + + glm::dvec3 Pair::targetDirectionEquatorial() + { + return _target->directionEquatorial(); + } + + glm::dvec3 Pair::targetDirectionGalactic() + { + return _target->directionGalactic(); + } + + std::string Pair::browserGuiName() + { + return _browser->guiName(); + } + + std::string Pair::browserId() + { + return _browser->identifier(); + } + + std::string Pair::targetId() + { + return _target->identifier(); + } + + float Pair::verticalFov() + { + return _browser->verticalFov(); + } + + const std::deque& Pair::getSelectedImages() + { + return _browser->getSelectedImages(); + } + + void Pair::selectImage(const ImageData& image, int i) + { + // Load image into browser + _browser->addSelectedImage(image, i); + + // If the image has coordinates, move the target + if (image.hasCelestialCoords) { + + // Animate the target to the image coordinate position + unlock(); + startAnimation(image.equatorialCartesian, image.fov); + } + } + + void Pair::removeSelectedImage(const int i) + { + _browser->removeSelectedImage(i); + } + + void Pair::loadImages(std::string collection) + { + _browser->sendMessageToWwt(wwtmessage::loadCollection(collection)); + _browser->setHasLoadedImages(true); + } + + void Pair::setImageOpacity(const int i, float opacity) + { + ghoul::Dictionary msg = wwtmessage::setImageOpacity(std::to_string(i), opacity); + _browser->sendMessageToWwt(msg); + } + + void Pair::sendIdToBrowser() + { + _browser->sendIdToBrowser(); + } + + void Pair::incrementallyAnimateToCoordinate(double deltaTime) + { + if (_target->isAnimated()) { + _target->animateToCoordinate(deltaTime); + } + else if (_browser->isAnimated()) { + _browser->incrementallyAnimateToFov(deltaTime); + } + } + + void Pair::startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfter) + { + _target->startAnimation(coordsEnd, lockAfter); + _browser->startFovAnimation(FOVEnd); + } + + void Pair::centerTargetOnScreen() + { + // Animate the target to the center of the screen + unlock(); + // Get camera direction in celestial spherical coordinates + glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); + // Keep the current fov + float currentFov = verticalFov(); + startAnimation(viewDirection, currentFov, false); + } + + bool Pair::isFinishedFading(float goalState) + { + return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); + } + + ScreenSpaceSkyTarget* Pair::getTarget() { + return _target; + } + + ScreenSpaceSkyBrowser* Pair::getBrowser() { + return _browser; + } + + void Pair::incrementallyFade(float goalState, float fadeTime, float deltaTime) + { + float opacityDelta = static_cast(deltaTime / fadeTime); + + if (!isTargetFadeFinished(goalState)) { + _target->setOpacity(_target->opacity() + opacityDelta); + } + else { + _target->setOpacity(goalState); + } + + if (!isBrowserFadeFinished(goalState)) { + _browser->getOpacity() = _browser->getOpacity().value() + opacityDelta; + } + else { + _browser->getOpacity() = goalState; + } + } + + bool operator==(const Pair& lhs, const Pair& rhs) { + return lhs._target == rhs._target && lhs._browser == rhs._browser; + } + bool operator!=(const Pair & lhs, const Pair & rhs) { + return !(lhs == rhs); + } + +} // namespace openspace From 206fc43f742f2d58daa3244d19c55b929d85a99b Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 10 Nov 2021 09:33:30 -0500 Subject: [PATCH 136/251] Rename boolean functions and variables to adhere to code style --- modules/skybrowser/include/pair.h | 7 +-- .../skybrowser/include/renderableskybrowser.h | 2 +- .../include/screenspaceskybrowser.h | 4 +- .../skybrowser/include/screenspaceskytarget.h | 8 +-- modules/skybrowser/include/utility.h | 4 +- modules/skybrowser/skybrowsermodule.cpp | 10 ++-- modules/skybrowser/skybrowsermodule.h | 4 +- modules/skybrowser/src/pair.cpp | 22 +++---- .../skybrowser/src/renderableskybrowser.cpp | 10 ++-- .../skybrowser/src/screenspaceskybrowser.cpp | 28 +++++---- .../skybrowser/src/screenspaceskytarget.cpp | 57 +++++++++++-------- modules/skybrowser/src/utility.cpp | 6 +- 12 files changed, 83 insertions(+), 79 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 2a025691bc..d4973c93ff 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -40,9 +40,6 @@ public: constexpr static const float AcceptableDiff = 0.01f; Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); - Pair(Pair const&) = default; - - Pair& operator=(Pair other); void lock(); void unlock(); @@ -54,11 +51,11 @@ public: void enable(); void disable(); - void startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool shouldLockAfter = true); + void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); void centerTargetOnScreen(); void incrementallyAnimateToCoordinate(double deltaTime); void incrementallyFade(float goalState, float fadeTime, float deltaTime); - bool isFinishedFading(float goalState); + bool hasFinishedFading(float goalState); bool isCoordOnPair(glm::vec2 mousePosition); bool isEnabled(); bool isLocked(); diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 56d27923e6..735237f596 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -98,7 +98,7 @@ namespace openspace { // Flags bool _isUrlDirty = false; bool _isDimensionsDirty = false; - bool _syncViewWithWwt; + bool _isSyncedWithWwt; float _verticalFov; std::thread _threadWwtMessages; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 1699f968ae..69fe0f559d 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -91,8 +91,8 @@ namespace openspace { // Flags bool _hasLoadedImages{ false }; - bool _syncViewWithWwt{ false }; - bool _fovIsAnimated{ false }; + bool _isSyncedWithWwt{ false }; + bool _isFovAnimated{ false }; float _endVfov{ 0.f }; float _fovDiff{ 0.01f }; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index a064fd498d..c3f1d3d7c5 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -34,7 +34,7 @@ namespace openspace { void createShaders(); // Sky browser functionality - bool findSkyBrowser(); + bool connectoToSkyBrowser(); void matchAppearanceToSkyBrowser(); // Getters @@ -59,8 +59,8 @@ namespace openspace { // Animation bool isAnimated(); - void startAnimation(glm::dvec3 end, bool lockAfter); - void animateToCoordinate(float deltaTime); + void startAnimation(glm::dvec3 end, bool shouldLockAfter); + void incrementallyAnimateToCoordinate(float deltaTime); // Display void highlight(glm::ivec3 addition); void removeHighlight(glm::ivec3 removal); @@ -76,7 +76,7 @@ namespace openspace { // Flags bool _isLocked{ false }; bool _isAnimated{ false }; - bool _lockAfterAnimation{ false }; + bool _shouldLockAfterAnimation{ false }; // Shader UniformCache( diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index a869fd753d..e5805dfc96 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -42,7 +42,7 @@ namespace openspace { // Camera roll and direction // Camera roll is with respect to the equatorial North Pole - bool coordinateIsInView(glm::dvec3 equatorial); + bool isCoordinateInView(glm::dvec3 equatorial); float windowRatio(); double cameraRoll(); glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate); @@ -58,7 +58,7 @@ namespace openspace { namespace wwtmessage { inline int messageCounter{ 0 }; ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, - const double fov, const double roll, const bool moveInstantly = true); + const double fov, const double roll, const bool shouldMoveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); ghoul::Dictionary addImage(const std::string& id, const std::string& url); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index a4e9b46fb1..a8999ff1be 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -629,7 +629,7 @@ void SkyBrowserModule::selectImage2dBrowser(int i) LINFO("Loading image " + image.name); selected->selectImage(image, i); - bool isInView = skybrowser::coordinateIsInView(image.equatorialCartesian); + bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); // If the coordinate is not in view, rotate camera if (image.hasCelestialCoords) { if(!isInView) { @@ -774,10 +774,10 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float { float transparency = static_cast(goal); bool isAllFinished{ false }; - for (Pair pair : _targetsBrowsers) { + for (Pair& pair : _targetsBrowsers) { if (pair.isEnabled()) { pair.incrementallyFade(transparency, _fadingTime, deltaTime); - bool isPairFinished = pair.isFinishedFading(transparency); + bool isPairFinished = pair.hasFinishedFading(transparency); if (isPairFinished && goal == Transparency::Transparent) { pair.disable(); @@ -794,9 +794,9 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) { - for (Pair pair : _targetsBrowsers) { + for (Pair& pair : _targetsBrowsers) { if (pair.isEnabled()) { - pair.animateToCoordinate(deltaTime); + pair.incrementallyAnimateToCoordinate(deltaTime); } } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 377b76d86a..f05276e7cb 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -81,8 +81,8 @@ public: void lookAtTarget(std::string id); void incrementallyRotateCamera(double deltaTime); - void fadeBrowserTargets(Transparency goal, float deltaTime); - void animateTargets(double deltaTime); + void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); + void incrementallyAnimateTargets(double deltaTime); void lookAt3dBrowser(); // Boolean functions diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 7a568ff2a8..d0470e2086 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -38,14 +38,7 @@ namespace openspace { assert(browser != nullptr, "Sky browser is null pointer!"); assert(target != nullptr, "Sky target is null pointer!"); } - - Pair& Pair::operator=(Pair other) - { - std::swap(_target, other._target); - std::swap(_browser, other._browser); - return *this; - } - + void Pair::lock() { _target->lock(); } @@ -61,7 +54,7 @@ namespace openspace { void Pair::connectPair() { _browser->connectToSkyTarget(); - _target->findSkyBrowser(); + _target->connectoToSkyBrowser(); } void Pair::synchronizeWithWwt() @@ -206,21 +199,22 @@ namespace openspace { { _browser->sendIdToBrowser(); } - +#pragma optimize("", off) void Pair::incrementallyAnimateToCoordinate(double deltaTime) { + // Animate the target before the field of view starts to animate if (_target->isAnimated()) { - _target->animateToCoordinate(deltaTime); + _target->incrementallyAnimateToCoordinate(deltaTime); } else if (_browser->isAnimated()) { _browser->incrementallyAnimateToFov(deltaTime); } } - void Pair::startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfter) + void Pair::startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool lockAfter) { _target->startAnimation(coordsEnd, lockAfter); - _browser->startFovAnimation(FOVEnd); + _browser->startFovAnimation(fovEnd); } void Pair::centerTargetOnScreen() @@ -234,7 +228,7 @@ namespace openspace { startAnimation(viewDirection, currentFov, false); } - bool Pair::isFinishedFading(float goalState) + bool Pair::hasFinishedFading(float goalState) { return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 48a49b1d4c..4671e7ed58 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -71,7 +71,7 @@ namespace openspace { , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) , _reload(ReloadInfo) , _verticalFov(70.f) - , _syncViewWithWwt(false) + , _isSyncedWithWwt(false) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -231,11 +231,11 @@ namespace openspace { void RenderableSkyBrowser::syncWwtView() { // If the camera is already synced, the browser is already initialized - if (!_syncViewWithWwt) { - _syncViewWithWwt = true; + if (!_isSyncedWithWwt) { + _isSyncedWithWwt = true; // Start a thread to enable user interaction while sending the calls to WWT _threadWwtMessages = std::thread([&] { - while (_syncViewWithWwt) { + while (_isSyncedWithWwt) { glm::dvec2 aim{ 0.0 }; // Send a message just to establish contact @@ -255,7 +255,7 @@ namespace openspace { } void RenderableSkyBrowser::stopSyncingWwtView() { - _syncViewWithWwt = false; + _isSyncedWithWwt = false; if (_threadWwtMessages.joinable()) { _threadWwtMessages.join(); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index e4376f0ae4..4a122533a4 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -151,7 +151,7 @@ namespace openspace { ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { // Set flag to false so the thread can exit - _syncViewWithWwt = false; + _isSyncedWithWwt = false; if (_threadWwtMessages.joinable()) { _threadWwtMessages.join(); LINFO("Joined thread"); @@ -181,8 +181,8 @@ namespace openspace { void ScreenSpaceSkyBrowser::startSyncingWithWwt() { // If the camera is already synced, the browser is already syncing - if (!_syncViewWithWwt) { - _syncViewWithWwt = true; + if (!_isSyncedWithWwt) { + _isSyncedWithWwt = true; // Set border color setWebpageBorderColor(_borderColor.value()); // Track target @@ -204,10 +204,14 @@ namespace openspace { glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; return result; } - + /* + void ScreenSpaceBrowser::setXCallback(std::function callback) { + _originalDimensions.onChange(std::move(callback)); + } + */ bool ScreenSpaceSkyBrowser::deinitializeGL() { // Set flag to false so the thread can exit - _syncViewWithWwt = false; + _isSyncedWithWwt = false; if (_threadWwtMessages.joinable()) { _threadWwtMessages.join(); LINFO("Joined thread"); @@ -223,24 +227,26 @@ namespace openspace { bool ScreenSpaceSkyBrowser::isAnimated() { - return _fovIsAnimated; + return _isFovAnimated; } void ScreenSpaceSkyBrowser::startFovAnimation(float fov) { - _fovIsAnimated = true; + _isFovAnimated = true; _endVfov = fov; } void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { - // If distance is small enough, stop animating + // If distance too large, keep animating. Else, stop animation float diff = verticalFov() - _endVfov; - if (abs(diff) > _fovDiff) { + bool shouldAnimate = abs(diff) > _fovDiff; + + if (shouldAnimate) { setVerticalFovWithScroll(diff); } else { - _fovIsAnimated = false; + _isFovAnimated = false; } } @@ -320,7 +326,7 @@ namespace openspace { // Start a thread to enable user interaction while sending the calls to WWT _threadWwtMessages = std::thread([&] { - while (_syncViewWithWwt) { + while (_isSyncedWithWwt) { if (_skyTarget) { // Message WorldWide Telescope current view glm::dvec3 cartesian = _skyTarget->directionEquatorial(); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 388308fdc7..c5228746fa 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -121,7 +121,7 @@ namespace openspace { // If the ID changes for the corresponding browser, update _skyBrowserId.onChange([&]() { - findSkyBrowser(); + connectoToSkyBrowser(); }); // Always make sure that the target and browser are visible together @@ -160,7 +160,7 @@ namespace openspace { } - bool ScreenSpaceSkyTarget::findSkyBrowser() { + bool ScreenSpaceSkyTarget::connectoToSkyBrowser() { _skyBrowser = dynamic_cast( global::renderEngine->screenSpaceRenderable(_skyBrowserId.value())); matchAppearanceToSkyBrowser(); @@ -277,8 +277,10 @@ namespace openspace { } glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { + glm::dmat4 rotation = glm::inverse( - global::navigationHandler->camera()->viewRotationMatrix()); + global::navigationHandler->camera()->viewRotationMatrix() + ); glm::dvec4 position = glm::dvec4(_cartesianPosition.value(), 1.0); return glm::normalize(rotation * position); @@ -330,43 +332,48 @@ namespace openspace { return _isAnimated; } - void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 end, bool lockAfter) + void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 end, bool shouldLockAfter) { _animationStart = glm::normalize(directionEquatorial()); _animationEnd = glm::normalize(end); - _lockAfterAnimation = lockAfter; + _shouldLockAfterAnimation = shouldLockAfter; _isAnimated = true; } - void ScreenSpaceSkyTarget::animateToCoordinate(float deltaTime) + void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { // Find smallest angle between the two vectors double smallestAngle = skybrowser::angleVector(_animationStart, _animationEnd); - // Only keep animating when target is not at final position - if (smallestAngle <= _stopAnimationThreshold) { + bool shouldAnimate = smallestAngle > _stopAnimationThreshold; + + // Only keep animating when target is not at goal position + if (shouldAnimate) { + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( + _animationStart, + _animationEnd, + deltaTime, + _animationSpeed + ); + + // Rotate target direction + glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); + + // Convert to screen space + _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); + + // Update position + _animationStart = glm::normalize(newDir); + } + else { // Set the exact target position _cartesianPosition = skybrowser::equatorialToScreenSpace(_animationEnd); _isAnimated = false; + // Lock target when it first arrives to the position - if (!isLocked() && _lockAfterAnimation) { + if (!isLocked() && _shouldLockAfterAnimation) { lock(); } - - return; - } - - glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( - _animationStart, - _animationEnd, - deltaTime, - _animationSpeed - ); - // Rotate target direction - glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); - // Convert to screen space - _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); - // Update position - _animationStart = glm::normalize(newDir); + } } glm::dvec3 ScreenSpaceSkyTarget::directionEquatorial() const { diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 6a0e418c83..44333769b3 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -131,7 +131,7 @@ namespace openspace::skybrowser { return windowRatio.x / windowRatio.y; } - bool coordinateIsInView(glm::dvec3 equatorial) { + bool isCoordinateInView(glm::dvec3 equatorial) { // Check if image coordinate is within current FOV glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial); double r = static_cast(windowRatio()); @@ -191,7 +191,7 @@ namespace openspace::skybrowser { namespace openspace::wwtmessage { // WWT messages ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, - const double roll, const bool moveInstantly) { + const double roll, const bool shouldMoveInstantly) { using namespace std::string_literals; ghoul::Dictionary msg; @@ -201,7 +201,7 @@ namespace openspace::wwtmessage { msg.setValue("dec", celestCoords.y); msg.setValue("fov", fov); msg.setValue("roll", roll); - msg.setValue("instant", moveInstantly); + msg.setValue("instant", shouldMoveInstantly); return msg; } From 7bcdd7db219bc1d9ae523c31a8c7006974096ae8 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 10 Nov 2021 09:52:07 -0500 Subject: [PATCH 137/251] Give utility functions better names --- .../skybrowser/include/renderableskybrowser.h | 2 +- modules/skybrowser/include/utility.h | 36 ++++++++------- modules/skybrowser/skybrowsermodule.cpp | 44 +++++++++---------- modules/skybrowser/skybrowsermodule.h | 14 +++--- modules/skybrowser/skybrowsermodule_lua.inl | 8 ++-- modules/skybrowser/src/pair.cpp | 8 ++-- .../skybrowser/src/renderableskybrowser.cpp | 7 ++- .../skybrowser/src/screenspaceskybrowser.cpp | 25 +++++------ .../skybrowser/src/screenspaceskytarget.cpp | 10 ++--- modules/skybrowser/src/utility.cpp | 22 +++++----- modules/skybrowser/src/wwtdatahandler.cpp | 16 +++---- 11 files changed, 97 insertions(+), 95 deletions(-) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 735237f596..6ca64539c8 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -59,7 +59,7 @@ namespace openspace { // WorldWide Telescope communication void displayImage(const ImageData& image, int i); void removeSelectedImage(const ImageData& image, int i); - bool sendMessageToWwt(const ghoul::Dictionary& msg); + void sendMessageToWwt(const ghoul::Dictionary& msg); void syncWwtView(); void stopSyncingWwtView(); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index e5805dfc96..dc9db21d21 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -31,34 +31,38 @@ namespace openspace { // Conversion J2000 equatorial <-> galactic glm::dvec3 galacticToEquatorial(glm::dvec3 coords); - glm::dvec3 galacticToLocalCamera(glm::dvec3 coords); glm::dvec3 equatorialToGalactic(glm::dvec3 coords); - // Conversion J2000 equatorial / galactic <-> screen space - glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords); - glm::dvec3 galacticToScreenSpace(glm::dvec3 coords); + // Conversion to screen space from J2000 equatorial / galactic / pixels + glm::dvec3 equatorialToScreenSpace3d(glm::dvec3 coords); + glm::dvec3 galacticToScreenSpace3d(glm::dvec3 coords); + glm::vec2 pixelToScreenSpace2d(glm::vec2& mouseCoordinate); + + // Conversion local camera space <-> galactic / equatorial + glm::dvec3 galacticToLocalCamera(glm::dvec3 coords); glm::dvec3 localCameraToGalactic(glm::dvec3 coords); glm::dvec3 localCameraToEquatorial(glm::dvec3 coords); // Camera roll and direction - // Camera roll is with respect to the equatorial North Pole - bool isCoordinateInView(glm::dvec3 equatorial); - float windowRatio(); - double cameraRoll(); - glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate); - glm::dvec2 fovWindow(); + double cameraRoll(); // Camera roll is with respect to the equatorial North Pole glm::dvec3 cameraDirectionGalactic(); glm::dvec3 cameraDirectionEquatorial(); - double angleVector(glm::dvec3 start, glm::dvec3 end); - glm::dmat4 incrementalAnimationMatrix(glm::dvec3 start, - glm::dvec3 end, double deltaTime, - double speedFactor = 1.0); + + // Window and field of view + float windowRatio(); + glm::dvec2 fovWindow(); + bool isCoordinateInView(glm::dvec3 equatorial); + + // Animation for target and camera + double angleBetweenVectors(glm::dvec3 start, glm::dvec3 end); + glm::dmat4 incrementalAnimationMatrix(glm::dvec3 start, glm::dvec3 end, + double deltaTime, double speedFactor = 1.0); } // WorldWide Telescope messages namespace wwtmessage { inline int messageCounter{ 0 }; - ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, - const double fov, const double roll, const bool shouldMoveInstantly = true); + ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, + const double roll, const bool shouldMoveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); ghoul::Dictionary addImage(const std::string& id, const std::string& url); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index a8999ff1be..ce1da74d0f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -272,7 +272,7 @@ SkyBrowserModule::SkyBrowserModule() setSelectedBrowser(_mouseOnPair->getBrowser()); if (button == MouseButton::Left) { - _cameraIsRotating = false; + _isCameraRotating = false; _startMousePosition = _mousePosition; if (_isBrowser) { _startDragPosition = _mouseOnPair->getBrowser()-> @@ -312,7 +312,7 @@ SkyBrowserModule::SkyBrowserModule() // click on browser _startMousePosition = _mousePosition; _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); - _fineTuneMode = true; + _isFineTuneMode = true; return true; } @@ -323,8 +323,8 @@ SkyBrowserModule::SkyBrowserModule() return true; } - if (_fineTuneMode) { - _fineTuneMode = false; + if (_isFineTuneMode) { + _isFineTuneMode = false; return true; } if (_isResizing) { @@ -341,9 +341,9 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mousePosition->emplace_back( [&](double x, double y) { - if (_cameraInSolarSystem) { + if (_isCameraInSolarSystem) { glm::vec2 pixel{ static_cast(x), static_cast(y) }; - _mousePosition = skybrowser::pixelToScreenSpace(pixel); + _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); glm::vec2 translation = _mousePosition - _startMousePosition; if (_isDragging || _isResizing) { @@ -376,7 +376,7 @@ SkyBrowserModule::SkyBrowserModule() ); } } - else if (_fineTuneMode) { + else if (_isFineTuneMode) { glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneVector( translation ); @@ -412,22 +412,22 @@ SkyBrowserModule::SkyBrowserModule() // Disable browser and targets when camera is outside of solar system glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); double deltaTime = global::windowDelegate->deltaTime(); - bool camWasInSolarSystem = _cameraInSolarSystem; - _cameraInSolarSystem = glm::length(cameraPos) < _solarSystemRadius; + bool camWasInSolarSystem = _isCameraInSolarSystem; + _isCameraInSolarSystem = glm::length(cameraPos) < SolarSystemRadius; // Fading flags - if (_cameraInSolarSystem != camWasInSolarSystem) { + if (_isCameraInSolarSystem != camWasInSolarSystem) { _isTransitioningVizMode = true; // Select the 3D browser when moving out of the solar system - if (!_cameraInSolarSystem && _browser3d != nullptr) { + if (!_isCameraInSolarSystem && _browser3d != nullptr) { _selectedBrowser = _browser3d->renderable()->identifier(); } } // Fade pairs if the camera moved in or out the solar system if (_isTransitioningVizMode) { - if (_cameraInSolarSystem) { + if (_isCameraInSolarSystem) { incrementallyFadeBrowserTargets(Transparency::Opaque, deltaTime); } else { @@ -435,10 +435,10 @@ SkyBrowserModule::SkyBrowserModule() } } - if (_cameraInSolarSystem) { + if (_isCameraInSolarSystem) { incrementallyAnimateTargets(deltaTime); } - if (_cameraIsRotating) { + if (_isCameraRotating) { incrementallyRotateCamera(deltaTime); } }); @@ -668,12 +668,12 @@ void SkyBrowserModule::moveHoverCircle(int i) const ImageData& image = _dataHandler->getImage(i); // Only move and show circle if the image has coordinates - if (_hoverCircle && image.hasCelestialCoords && _cameraInSolarSystem) { + if (_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem) { // Make circle visible _hoverCircle->property("Enabled")->set(true); // Calculate coords for the circle and translate - glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace( + glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace3d( image.equatorialCartesian ); _hoverCircle->property("CartesianPosition")->set(coordsScreen); @@ -742,13 +742,13 @@ void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates _endAnimation = endAnimation; _startAnimation = skybrowser::cameraDirectionGalactic(); - _cameraIsRotating = true; + _isCameraRotating = true; } void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleVector(_startAnimation, _endAnimation); + double smallestAngle = skybrowser::angleBetweenVectors(_startAnimation, _endAnimation); if(smallestAngle > _stopAnimationThreshold) { @@ -756,7 +756,7 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { _startAnimation, _endAnimation, deltaTime, - _speed + _animationSpeed ); // Rotate @@ -766,7 +766,7 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { _startAnimation = skybrowser::cameraDirectionGalactic(); } else { - _cameraIsRotating = false; + _isCameraRotating = false; } } @@ -815,8 +815,8 @@ std::string SkyBrowserModule::selectedBrowserId() { return _selectedBrowser; } -bool SkyBrowserModule::cameraInSolarSystem() { - return _cameraInSolarSystem; +bool SkyBrowserModule::isCameraInSolarSystem() { + return _isCameraInSolarSystem; } //std::vector SkyBrowserModule::documentations() const { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index f05276e7cb..44acace181 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -58,6 +58,7 @@ class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; + const double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; // Constructor & destructor SkyBrowserModule(); @@ -86,7 +87,7 @@ public: void lookAt3dBrowser(); // Boolean functions - bool cameraInSolarSystem(); + bool isCameraInSolarSystem(); // Managing the browsers void createTargetBrowserPair(); @@ -122,16 +123,15 @@ private: SceneGraphNode* _browser3d{ nullptr }; std::string _selectedBrowser{ "" }; // Currently selected browser (2D or 3D) - // 2D vs 3D visualization mode - double _solarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; + // Fading double _fadingTime = 2.0; // Flags - bool _fineTuneMode{ false }; + bool _isFineTuneMode{ false }; bool _isResizing{ false }; bool _isDragging{ false }; - bool _cameraInSolarSystem{ true }; - bool _cameraIsRotating = false; + bool _isCameraInSolarSystem{ true }; + bool _isCameraRotating = false; bool _isTransitioningVizMode{ false }; // Mouse interaction - dragging and resizing @@ -146,7 +146,7 @@ private: glm::dvec3 _startAnimation; glm::dvec3 _endAnimation; double _stopAnimationThreshold{ 0.05 }; - double _speed{ 1.0 }; + double _animationSpeed{ 1.0 }; // Data handler for the image collections std::unique_ptr _dataHandler; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index a2049272d0..599bbf5028 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -38,7 +38,7 @@ namespace openspace::skybrowser::luascriptfunctions { const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->cameraInSolarSystem()) { + if (module->isCameraInSolarSystem()) { module->selectImage2dBrowser(i); } else { @@ -337,13 +337,13 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); lua_settable(L, -3); - ghoul::lua::push(L, "cameraInSolarSystem", module->cameraInSolarSystem()); + ghoul::lua::push(L, "cameraInSolarSystem", module->isCameraInSolarSystem()); lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); // Pass data for all the browsers and the corresponding targets - if (module->cameraInSolarSystem()) { + if (module->isCameraInSolarSystem()) { std::vector pairs = module->getPairs(); for (Pair pair : pairs) { @@ -448,7 +448,7 @@ namespace openspace::skybrowser::luascriptfunctions { const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if(module->cameraInSolarSystem()) { + if(module->isCameraInSolarSystem()) { module->lookAtTarget(id); } else { diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index d0470e2086..cea27224a4 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -90,8 +90,8 @@ namespace openspace { bool Pair::isCoordOnPair(glm::vec2 mousePosition) { - bool onBrowser = _browser->coordIsInsideCornersScreenSpace(mousePosition); - bool onTarget = _target->coordIsInsideCornersScreenSpace(mousePosition); + const bool onBrowser = _browser->coordIsInsideCornersScreenSpace(mousePosition); + const bool onTarget = _target->coordIsInsideCornersScreenSpace(mousePosition); if (onBrowser) { _selected = _browser->identifier(); } @@ -211,9 +211,9 @@ namespace openspace { } } - void Pair::startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool lockAfter) + void Pair::startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter) { - _target->startAnimation(coordsEnd, lockAfter); + _target->startAnimation(coordsEnd, shouldLockAfter); _browser->startFovAnimation(fovEnd); } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 4671e7ed58..6f209fd29e 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -178,18 +178,17 @@ namespace openspace { void RenderableSkyBrowser::executeJavascript(std::string script) const { //LINFOC(_loggerCat, "Executing javascript " + script); - bool isBrowserReady = _browserInstance && _browserInstance->getBrowser(); - bool isMainFrameReady = _browserInstance->getBrowser()->GetMainFrame(); + const bool isBrowserReady = _browserInstance && _browserInstance->getBrowser(); + const bool isMainFrameReady = _browserInstance->getBrowser()->GetMainFrame(); if (isBrowserReady && isMainFrameReady) { CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); frame->ExecuteJavaScript(script, frame->GetURL(), 0); } } - bool RenderableSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) { + void RenderableSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) { std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; executeJavascript(script); - return true; } void RenderableSkyBrowser::displayImage(const ImageData& image, const int i) { diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 4a122533a4..1893e74505 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -240,7 +240,7 @@ namespace openspace { { // If distance too large, keep animating. Else, stop animation float diff = verticalFov() - _endVfov; - bool shouldAnimate = abs(diff) > _fovDiff; + const bool shouldAnimate = abs(diff) > _fovDiff; if (shouldAnimate) { setVerticalFovWithScroll(diff); @@ -283,8 +283,8 @@ namespace openspace { void ScreenSpaceSkyBrowser::executeJavascript(std::string script) { // Make sure that the browser has a main frame - bool browserExists = _browserInstance && _browserInstance->getBrowser(); - bool frameIsLoaded = browserExists && + const bool browserExists = _browserInstance && _browserInstance->getBrowser(); + const bool frameIsLoaded = browserExists && _browserInstance->getBrowser()->GetMainFrame(); if (frameIsLoaded) { @@ -355,10 +355,10 @@ namespace openspace { float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; - bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; - bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; - bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; - bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; + const bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; + const bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; + const bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; + const bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; resizePosition.x = isOnRight ? 1.f : isOnLeft ? -1.f : 0.f; resizePosition.y = isOnTop ? 1.f : isOnBottom ? -1.f : 0.f; @@ -422,8 +422,7 @@ namespace openspace { void ScreenSpaceSkyBrowser::addSelectedImage(const ImageData& image, int i) { // Ensure there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - bool found = it != std::end(_selectedImages); - if (!found) { + if (it == std::end(_selectedImages)) { // Push newly selected image to front _selectedImages.push_front(i); // Index of image is used as layer ID as it is unique in the image data set @@ -435,8 +434,8 @@ namespace openspace { void ScreenSpaceSkyBrowser::removeSelectedImage(int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - bool found = it != std::end(_selectedImages); - if (found) { + + if (it != std::end(_selectedImages)) { _selectedImages.erase(it); sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); } @@ -455,8 +454,8 @@ namespace openspace { auto target = std::begin(_selectedImages) + order; // Make sure the selected and the target placement was found in the list - bool foundSelected = selected != std::end(_selectedImages); - bool foundTarget = target != std::end(_selectedImages); + const bool foundSelected = selected != std::end(_selectedImages); + const bool foundTarget = target != std::end(_selectedImages); if (foundSelected && foundTarget) { // Swap the two images diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index c5228746fa..91f9af06d6 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -316,7 +316,7 @@ namespace openspace { // Start a thread to enable user interactions while locking target _lockTarget = std::thread([&] { while (_isLocked) { - _cartesianPosition = skybrowser::equatorialToScreenSpace( + _cartesianPosition = skybrowser::equatorialToScreenSpace3d( _lockedCoordinates ); } @@ -343,8 +343,8 @@ namespace openspace { void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleVector(_animationStart, _animationEnd); - bool shouldAnimate = smallestAngle > _stopAnimationThreshold; + double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, _animationEnd); + const bool shouldAnimate = smallestAngle > _stopAnimationThreshold; // Only keep animating when target is not at goal position if (shouldAnimate) { @@ -359,14 +359,14 @@ namespace openspace { glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); // Convert to screen space - _cartesianPosition = skybrowser::equatorialToScreenSpace(newDir); + _cartesianPosition = skybrowser::equatorialToScreenSpace3d(newDir); // Update position _animationStart = glm::normalize(newDir); } else { // Set the exact target position - _cartesianPosition = skybrowser::equatorialToScreenSpace(_animationEnd); + _cartesianPosition = skybrowser::equatorialToScreenSpace3d(_animationEnd); _isAnimated = false; // Lock target when it first arrives to the position diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 44333769b3..7f55ff2cae 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -47,7 +47,7 @@ namespace openspace::skybrowser { return rGalactic * CelestialSphereRadius; } - glm::dvec3 galacticToScreenSpace(glm::dvec3 coords) { + glm::dvec3 galacticToScreenSpace3d(glm::dvec3 coords) { glm::dvec3 localCameraSpace = galacticToLocalCamera(coords); // Ensure that if the coord is behind the camera, @@ -90,11 +90,11 @@ namespace openspace::skybrowser { return glm::normalize(viewDirectionLocal); } - glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords) { + glm::dvec3 equatorialToScreenSpace3d(glm::dvec3 coords) { // Transform equatorial J2000 to galactic coord with infinite radius glm::dvec3 galactic = equatorialToGalactic(coords); // Transform galactic coord to screen space - return galacticToScreenSpace(galactic); + return galacticToScreenSpace3d(galactic); } double cameraRoll() { @@ -133,18 +133,18 @@ namespace openspace::skybrowser { bool isCoordinateInView(glm::dvec3 equatorial) { // Check if image coordinate is within current FOV - glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial); + glm::dvec3 coordsScreen = equatorialToScreenSpace3d(equatorial); double r = static_cast(windowRatio()); - bool coordIsWithinView = (abs(coordsScreen.x) < r && - abs(coordsScreen.y) < 1.f && coordsScreen.z < 0); - bool coordIsBehindCamera = coordsScreen.z > 0; + bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f && + coordsScreen.z < 0; + // If the coordinate is not in view, rotate camera - return coordIsWithinView; + return isCoordInView; } // Transforms a pixel coordinate to a screen space coordinate - glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate) { + glm::vec2 pixelToScreenSpace2d(glm::vec2& mouseCoordinate) { glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); // Change origin to middle of the window glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f); @@ -165,7 +165,7 @@ namespace openspace::skybrowser { return OpenSpaceFOV; } - double angleVector(glm::dvec3 start, glm::dvec3 end) { + double angleBetweenVectors(glm::dvec3 start, glm::dvec3 end) { // Find smallest angle between the two vectors double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); @@ -176,7 +176,7 @@ namespace openspace::skybrowser { glm::dvec3 end, double deltaTime, double speedFactor) { - double smallestAngle = angleVector(start, end); + double smallestAngle = angleBetweenVectors(start, end); // Calculate rotation this frame double rotationAngle = smallestAngle * deltaTime * speedFactor; diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index ff10da4abd..52e7c048b6 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -63,7 +63,7 @@ namespace openspace { return false; } - bool directoryExists = (info.st_mode & S_IFDIR); + const bool directoryExists = (info.st_mode & S_IFDIR); return directoryExists; } @@ -71,7 +71,7 @@ namespace openspace { std::string createSearchableString(std::string str) { // Remove white spaces and all special characters str.erase(std::remove_if(std::begin(str), std::end(str), [](char c) { - bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); + const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); return !isNumberOrLetter; }), std::end(str)); @@ -202,8 +202,8 @@ namespace openspace { // Search XML file for folders with urls XMLElement* root = doc->RootElement(); XMLElement* element = root->FirstChildElement(wwt::Folder.c_str()); - bool folderExists = element; - bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url); + const bool folderExists = element; + const bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url); // If the file contains no folders, or there are folders but without urls, // stop recursion @@ -312,9 +312,9 @@ namespace openspace { // Only collect the images that have a thumbnail image, that are sky images and // that have an image - bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined; - bool isSkyImage = getAttribute(node, wwt::DataSetType) == wwt::Sky; - bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false; + const bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined; + const bool isSkyImage = getAttribute(node, wwt::DataSetType) == wwt::Sky; + const bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false; if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) { return; @@ -330,7 +330,7 @@ namespace openspace { // Collect equatorial coordinates. All-sky surveys do not have this kind of // coordinate - bool hasCelestialCoords = hasAttribute(node, wwt::RA) && + const bool hasCelestialCoords = hasAttribute(node, wwt::RA) && hasAttribute(node, wwt::Dec); glm::dvec2 equatorialSpherical{ 0.0 }; glm::dvec3 equatorialCartesian{ 0.0 }; From 513cee87057961d00b2385af1a8a9c8a3f631ea1 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 11 Nov 2021 11:00:24 -0500 Subject: [PATCH 138/251] Clean up header files - remove unneccessary and sort --- modules/skybrowser/include/pair.h | 5 +-- .../skybrowser/include/renderableskybrowser.h | 14 ++++---- .../include/screenspaceskybrowser.h | 9 +++--- .../skybrowser/include/screenspaceskytarget.h | 6 +--- modules/skybrowser/include/utility.h | 13 +++----- modules/skybrowser/include/wwtdatahandler.h | 5 ++- modules/skybrowser/skybrowsermodule.cpp | 32 ++++--------------- modules/skybrowser/skybrowsermodule.h | 22 ++++--------- modules/skybrowser/skybrowsermodule_lua.inl | 29 ++++------------- modules/skybrowser/src/pair.cpp | 5 ++- .../skybrowser/src/renderableskybrowser.cpp | 21 ++++-------- .../skybrowser/src/screenspaceskybrowser.cpp | 26 ++++----------- .../skybrowser/src/screenspaceskytarget.cpp | 17 ++-------- modules/skybrowser/src/utility.cpp | 15 ++++----- modules/skybrowser/src/wwtdatahandler.cpp | 27 ++++++++-------- 15 files changed, 79 insertions(+), 167 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index d4973c93ff..983dacf312 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -25,14 +25,15 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ #define __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ +#include +//#include +#include #include #include namespace openspace { class ScreenSpaceSkyBrowser; -class ScreenSpaceSkyTarget; -class ImageData; class Pair { public: diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 6ca64539c8..942c130fb3 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -1,9 +1,12 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ +#include +#include +#include +#include #include #include -#include #include #include #include @@ -34,11 +37,6 @@ namespace openspace::documentation { struct Documentation; } namespace openspace { - class BrowserInstance; - class RenderHandler; - class WebKeyboardHandler; - class ImageData; - class RenderableSkyBrowser : public RenderablePlane { public: @@ -57,8 +55,8 @@ namespace openspace { void setIdInBrowser(std::string id); // WorldWide Telescope communication - void displayImage(const ImageData& image, int i); - void removeSelectedImage(const ImageData& image, int i); + void displayImage(const ImageData& image, const int i); + void removeSelectedImage(const ImageData& image, const int i); void sendMessageToWwt(const ghoul::Dictionary& msg); void syncWwtView(); void stopSyncingWwtView(); diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 69fe0f559d..06829d37ea 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -1,15 +1,16 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ +#include #include -#include -#include +#include #include +#include #include #include namespace openspace { - class ScreenSpaceSkyTarget; + //class ScreenSpaceSkyTarget; class ScreenSpaceSkyBrowser : public ScreenSpaceBrowser { @@ -59,7 +60,7 @@ namespace openspace { void removeHighlight(glm::ivec3 removal); // Communication with WorldWide Telescope - void addSelectedImage(const ImageData& image, int i); + void addSelectedImage(const std::string& url, int i); void removeSelectedImage(int i); void setImageOrder(int i, int order); void sendMessageToWwt(const ghoul::Dictionary& msg); diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index c3f1d3d7c5..ee4d9df3c5 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -1,15 +1,11 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ -#include #include #include #include #include -#include -#include -#include -#include +#include namespace openspace::documentation { struct Documentation; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index dc9db21d21..ba6061c5a2 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -1,12 +1,7 @@ -#include -#include -#include -#include -#include // For atan2 -#include // For printing glm data -#define _USE_MATH_DEFINES -#include +#ifndef __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ +#include namespace openspace { namespace skybrowser { @@ -73,7 +68,7 @@ namespace openspace { } } - +#endif // __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 97726c3512..ce9332fb42 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -1,11 +1,10 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ -#include #include +#include #include -#include -#include + // For speck loading #include #include diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index ce1da74d0f..647e77dfad 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -23,33 +23,16 @@ ****************************************************************************************/ -#include -#include -#include -#include -#include +#include + +#include +#include "skybrowsermodule_lua.inl" #include #include -#include -#include -#include #include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include "skybrowsermodule_lua.inl" -#include -#include // For printing glm data -#include -#include -#include // For atan2 -#include -#include - namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -57,9 +40,6 @@ namespace { }; #include "skybrowsermodule_codegen.cpp" - - - } // namespace namespace openspace { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 44acace181..16263e0cd5 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -25,29 +25,21 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ -#include +#include +#include +#include + //#include +#include #include -#include -#include -#include +#include +#include #include -#include -#include - -#include #include namespace openspace { class ScreenSpaceSkyBrowser; -class ScreenSpaceSkyTarget; -class RenderableSkyBrowser; -class ScreenSpaceImageLocal; -class WwtDataHandler; -class SceneGraphNode; -class ImageData; -class Pair; enum class Transparency { Transparent = 0, diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 599bbf5028..9396d9ac43 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -1,29 +1,14 @@ -#include -#include -#include + +#include + +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index cea27224a4..2d34a88f86 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -22,10 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include #include + #include -#include #include namespace openspace { @@ -167,7 +166,7 @@ namespace openspace { void Pair::selectImage(const ImageData& image, int i) { // Load image into browser - _browser->addSelectedImage(image, i); + _browser->addSelectedImage(image.imageUrl, i); // If the image has coordinates, move the target if (image.hasCelestialCoords) { diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 6f209fd29e..19f036a59a 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,25 +1,18 @@ -#include #include -#include + #include #include -#include -#include -#include -#include -#include #include -#include +#include #include -#include // formatJson -#include -#include -#include +#include +#include #include -#include #include +#include // formatJson #include + namespace { constexpr const char* _loggerCat = "RenderableSkyBrowser"; @@ -210,7 +203,7 @@ namespace openspace { } } - void RenderableSkyBrowser::removeSelectedImage(const ImageData& image, int i) { + void RenderableSkyBrowser::removeSelectedImage(const ImageData& image, const int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it != std::end(_selectedImages)) { diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 1893e74505..bf98160443 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -1,28 +1,14 @@ #include -#include -#include -#include -#include -#include + #include -#include +#include +#include #include -#include -#include #include -#include -#include -#include -#include // formatJson #include +#include // formatJson #include -#include -#include -#include -#include -#include // Milliseconds #include -#include // to adjust camera angle namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -419,14 +405,14 @@ namespace openspace { return _selectedImages; } - void ScreenSpaceSkyBrowser::addSelectedImage(const ImageData& image, int i) { + void ScreenSpaceSkyBrowser::addSelectedImage(const std::string& url, int i) { // Ensure there are no duplicates auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it == std::end(_selectedImages)) { // Push newly selected image to front _selectedImages.push_front(i); // Index of image is used as layer ID as it is unique in the image data set - sendMessageToWwt(wwtmessage::addImage(std::to_string(i), image.imageUrl)); + sendMessageToWwt(wwtmessage::addImage(std::to_string(i), url)); sendMessageToWwt(wwtmessage::setImageOpacity(std::to_string(i), 1.0)); } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 91f9af06d6..c248b73e17 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,28 +1,15 @@ #include + #include #include -#include #include #include -#include -#include #include #include -#include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#define _USE_MATH_DEFINES -#include +#include namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 7f55ff2cae..6d1510407f 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -1,14 +1,13 @@ - -#include -#include -#include #include -#include // For atan2 -#include // For printing glm data -#include + +#include #include +#include +#include +#include +#include // For atan2 #define _USE_MATH_DEFINES -#include +#include // For M_PI namespace openspace::skybrowser { diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 52e7c048b6..4042297490 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -1,12 +1,13 @@ #include + #include #include // For downloading files from url #include #include #include // To iterate through files in directory +#include #include #include -#include // For loading the speck files #include @@ -25,7 +26,7 @@ namespace openspace { return element->FindAttribute(name.c_str()); } - std::string getAttribute(const tinyxml2::XMLElement* element, const std::string& name) { + std::string attribute(const tinyxml2::XMLElement* element, const std::string& name) { if (hasAttribute(element, name)) { return element->FindAttribute(name.c_str())->Value(); } @@ -142,7 +143,7 @@ namespace openspace { // If the place has a thumbnail url, return it if (hasAttribute(place, wwt::Thumbnail)) { - return getAttribute(place, wwt::Thumbnail); + return attribute(place, wwt::Thumbnail); } // If the place doesn't have a thumbnail url data attribute, @@ -219,8 +220,8 @@ namespace openspace { // If folder contains urls, download and parse those urls if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) { - std::string url = getAttribute(element, wwt::Url); - std::string fileName = getAttribute(element, wwt::Name); + std::string url = attribute(element, wwt::Url); + std::string fileName = attribute(element, wwt::Name); downloadAndParseWtmlFilesFromUrl(_xmls, directory, url, fileName); } element = element->NextSiblingElement(); @@ -257,7 +258,7 @@ namespace openspace { // Traverse through the collected wtml documents and collect the images for (tinyxml2::XMLDocument* doc : _xmls) { tinyxml2::XMLElement* root = doc->FirstChildElement(); - std::string collectionName = getAttribute(root, wwt::Name); + std::string collectionName = attribute(root, wwt::Name); saveImagesFromXml(root, collectionName); } @@ -313,7 +314,7 @@ namespace openspace { // Only collect the images that have a thumbnail image, that are sky images and // that have an image const bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined; - const bool isSkyImage = getAttribute(node, wwt::DataSetType) == wwt::Sky; + const bool isSkyImage = attribute(node, wwt::DataSetType) == wwt::Sky; const bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false; if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) { @@ -321,8 +322,8 @@ namespace openspace { } // Collect name, image url and credits - std::string name = getAttribute(node, wwt::Name); - std::string imageUrl = getAttribute(imageSet, wwt::Url); + std::string name = attribute(node, wwt::Name); + std::string imageUrl = attribute(imageSet, wwt::Url); std::string credits = getChildNodeContentFromImageSet(imageSet, wwt::Credits); std::string creditsUrl = getChildNodeContentFromImageSet( imageSet, wwt::CreditsUrl @@ -338,8 +339,8 @@ namespace openspace { if (hasCelestialCoords) { // The RA from WWT is in the unit hours: // to convert to degrees, multiply with 360 (deg) /24 (h) = 15 - double ra = 15.0 * std::stod(getAttribute(node, wwt::RA)); - double dec = std::stod(getAttribute(node, wwt::Dec)); + double ra = 15.0 * std::stod(attribute(node, wwt::RA)); + double dec = std::stod(attribute(node, wwt::Dec)); equatorialSpherical = { ra, dec }; equatorialCartesian = skybrowser::sphericalToCartesian( equatorialSpherical @@ -349,7 +350,7 @@ namespace openspace { // Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6 float fov{ 0.f }; if (hasAttribute(node, wwt::ZoomLevel)) { - fov = std::stof(getAttribute(node, wwt::ZoomLevel)) / 6.0; + fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0; } // Find 3D position by matching with speck file @@ -398,7 +399,7 @@ namespace openspace { // If node is another folder, open recursively else if (name == wwt::Folder) { std::string newCollectionName = collection + "/"; - newCollectionName += getAttribute(node, wwt::Name); + newCollectionName += attribute(node, wwt::Name); saveImagesFromXml(node, newCollectionName); } From 21cdc9d5cb4e9858a40e2b634f608b971acde72b Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 15 Nov 2021 15:30:58 -0500 Subject: [PATCH 139/251] Clean up --- .../include/screenspaceskybrowser.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 99 +++++++++--- modules/skybrowser/skybrowsermodule.h | 27 ++-- modules/skybrowser/skybrowsermodule_lua.inl | 143 ++++++------------ modules/skybrowser/src/pair.cpp | 3 + .../skybrowser/src/screenspaceskybrowser.cpp | 10 +- 6 files changed, 153 insertions(+), 131 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 06829d37ea..291763d591 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -104,7 +104,7 @@ namespace openspace { // Target & images ScreenSpaceSkyTarget* _skyTarget{ nullptr }; - std::thread _threadWwtMessages; + std::thread _wwtMessages; std::deque _selectedImages; // Time variables diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 647e77dfad..c997dd7020 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -25,6 +25,7 @@ #include +#include #include #include "skybrowsermodule_lua.inl" #include @@ -243,6 +244,11 @@ namespace openspace { SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) { + // Find the hover circle + _hoverCircle = dynamic_cast( + global::renderEngine->screenSpaceRenderable("HoverCircle")); + + // Set callback functions global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { @@ -400,8 +406,8 @@ SkyBrowserModule::SkyBrowserModule() _isTransitioningVizMode = true; // Select the 3D browser when moving out of the solar system - if (!_isCameraInSolarSystem && _browser3d != nullptr) { - _selectedBrowser = _browser3d->renderable()->identifier(); + if (!_isCameraInSolarSystem && _browser3dNode) { + _selectedBrowser = _browser3dNode->renderable()->identifier(); } } @@ -423,8 +429,7 @@ SkyBrowserModule::SkyBrowserModule() } }); - _hoverCircle = dynamic_cast( - global::renderEngine->screenSpaceRenderable("HoverCircle")); + } SkyBrowserModule::~SkyBrowserModule() { @@ -594,9 +599,14 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { _mouseOnPair = nullptr; } - -void SkyBrowserModule::set3dBrowser(SceneGraphNode* node) { - _browser3d = node; +void SkyBrowserModule::set3dBrowser(const std::string& id) +{ + SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); + if (node) { + // Add to module + _browser3dNode = node; + _browser3d = dynamic_cast(_browser3dNode->renderable()); + } } void SkyBrowserModule::selectImage2dBrowser(int i) @@ -623,11 +633,11 @@ void SkyBrowserModule::selectImage2dBrowser(int i) void SkyBrowserModule::selectImage3dBrowser(int i) { - if (!_browser3d) { + if (!_browser3dNode) { return; } RenderableSkyBrowser* renderable = dynamic_cast( - _browser3d->renderable()); + _browser3dNode->renderable()); if (renderable) { const ImageData& image = _dataHandler->getImage(i); renderable->displayImage(image, i); @@ -660,6 +670,13 @@ void SkyBrowserModule::moveHoverCircle(int i) } } +void SkyBrowserModule::disableHoverCircle() +{ + if (_hoverCircle && _hoverCircle->isEnabled()) { + _hoverCircle->property("Enabled")->set(false); + } +} + void SkyBrowserModule::loadImages(const std::string& root, const std::string& directory, std::vector& speckFiles) { @@ -671,6 +688,23 @@ int SkyBrowserModule::nLoadedImages() return _dataHandler->nLoadedImages(); } +void SkyBrowserModule::add2dSelectedImagesTo3d(const std::string& pairId) +{ + Pair* pair = getPair(pairId); + + if (pair && get3dBrowser()) { + + // Empty 3D browser selection + get3dBrowser()->getSelectedImages().clear(); + // Copy 2D selection of images to 3D browser + const std::deque images = pair->getSelectedImages(); + std::for_each(std::begin(images), std::end(images), [&](const int i) { + const ImageData& image = _dataHandler->getImage(i); + get3dBrowser()->displayImage(image, i); + }); + } +} + const std::unique_ptr& SkyBrowserModule::getWWTDataHandler() { return _dataHandler; } @@ -691,15 +725,31 @@ Pair* SkyBrowserModule::getPair(std::string id) return &(*it); } -SceneGraphNode* SkyBrowserModule::get3dBrowser() { +SceneGraphNode* SkyBrowserModule::get3dBrowserNode() { + return _browser3dNode; +} + +RenderableSkyBrowser* SkyBrowserModule::get3dBrowser(const std::string& id) +{ + if (_browser3dNode->identifier() == id || _browser3d->identifier() == id) { + return _browser3d; + } + else { + return nullptr; + } + +} + +RenderableSkyBrowser* SkyBrowserModule::get3dBrowser() +{ return _browser3d; } void SkyBrowserModule::lookAt3dBrowser() { - if (!_browser3d) { + if (!_browser3dNode) { return; } - std::string id = _browser3d->identifier(); + std::string id = _browser3dNode->identifier(); // Target camera on the 3D sky browser openspace::global::scriptEngine->queueScript( "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." @@ -718,6 +768,18 @@ void SkyBrowserModule::lookAt3dBrowser() { ); } +void SkyBrowserModule::place3dBrowser(const ImageData& image, const int i) +{ + // If the image has a 3D position, add it to the scene graph + if (image.has3dCoords && get3dBrowser()) { + get3dBrowser()->displayImage(image, i); + get3dBrowser()->placeAt3dPosition(image); + } + else { + LINFO("Image has no 3D coordinate!"); + } +} + void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates _endAnimation = endAnimation; @@ -756,10 +818,11 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float bool isAllFinished{ false }; for (Pair& pair : _targetsBrowsers) { if (pair.isEnabled()) { - pair.incrementallyFade(transparency, _fadingTime, deltaTime); bool isPairFinished = pair.hasFinishedFading(transparency); - - if (isPairFinished && goal == Transparency::Transparent) { + if (!isPairFinished) { + pair.incrementallyFade(transparency, _fadingTime, deltaTime); + } + else if (isPairFinished && goal == Transparency::Transparent) { pair.disable(); } isAllFinished &= isPairFinished; @@ -787,8 +850,10 @@ void SkyBrowserModule::setSelectedBrowser(ScreenSpaceSkyBrowser* browser) { } } -void SkyBrowserModule::setSelectedBrowser(std::string id) { - _selectedBrowser = id; +void SkyBrowserModule::setSelectedBrowser(const std::string& id) { + if (getPair(id) || _browser3dNode->identifier() == id) { + _selectedBrowser = id; + } } std::string SkyBrowserModule::selectedBrowserId() { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 16263e0cd5..923174674c 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -40,6 +40,7 @@ namespace openspace { class ScreenSpaceSkyBrowser; +class RenderableSkyBrowser; enum class Transparency { Transparent = 0, @@ -59,46 +60,49 @@ public: // Getters std::vector& getPairs(); Pair* getPair(std::string id); - SceneGraphNode* get3dBrowser(); + SceneGraphNode* get3dBrowserNode(); + RenderableSkyBrowser* get3dBrowser(); + RenderableSkyBrowser* get3dBrowser(const std::string& id); const std::unique_ptr& getWWTDataHandler(); std::string selectedBrowserId(); // Setters + void set3dBrowser(const std::string& id); void setSelectedBrowser(ScreenSpaceSkyBrowser* ptr); - void setSelectedBrowser(std::string id); - void set3dBrowser(SceneGraphNode* node); + void setSelectedBrowser(const std::string& id); void selectImage2dBrowser(int i); void selectImage3dBrowser(int i); + void setSelectedObject(); // Manage mouse interactions - // Rotation and animation - + // Rotation, animation, placement void lookAtTarget(std::string id); void incrementallyRotateCamera(double deltaTime); void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); void incrementallyAnimateTargets(double deltaTime); void lookAt3dBrowser(); + void place3dBrowser(const ImageData& image, const int i); // Boolean functions bool isCameraInSolarSystem(); - // Managing the browsers + // Managing the target browser pairs void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); void addTargetBrowserPair(std::string targetId, std::string browserId); + + // Hover circle void moveHoverCircle(int i); + void disableHoverCircle(); // Image collection handling void loadImages(const std::string& root, const std::string& directory, std::vector& speckFiles); int nLoadedImages(); - - // Manage mouse interactions - void setSelectedObject(); + void add2dSelectedImagesTo3d(const std::string& pairId); scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; - protected: void internalInitialize(const ghoul::Dictionary& dict) override; void internalDeinitialize() override; @@ -112,7 +116,8 @@ private: Pair* _selectedPair{ nullptr }; bool _isBrowser{ false }; ScreenSpaceImageLocal* _hoverCircle{ nullptr }; - SceneGraphNode* _browser3d{ nullptr }; + SceneGraphNode* _browser3dNode{ nullptr }; + RenderableSkyBrowser* _browser3d{ nullptr }; std::string _selectedBrowser{ "" }; // Currently selected browser (2D or 3D) // Fading diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 9396d9ac43..8b2861b16c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -1,7 +1,6 @@ #include -#include #include #include #include @@ -45,11 +44,8 @@ namespace openspace::skybrowser::luascriptfunctions { int disableHoverCircle(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); - ScreenSpaceImageLocal* hoverCircle = dynamic_cast( - global::renderEngine->screenSpaceRenderable("HoverCircle")); - if (hoverCircle->isEnabled()) { - hoverCircle->property("Enabled")->set(false); - } + SkyBrowserModule* module = global::moduleEngine->module(); + module->disableHoverCircle(); return 0; } @@ -85,10 +81,8 @@ namespace openspace::skybrowser::luascriptfunctions { if (module->getPair(id)) { module->getPair(id)->setImageOrder(i, order); } - else if (module->get3dBrowser() != nullptr) { - RenderableSkyBrowser* browser3d = dynamic_cast( - module->get3dBrowser()->renderable()); - browser3d->setImageLayerOrder(i, order); + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->setImageLayerOrder(i, order); } return 0; @@ -111,19 +105,14 @@ namespace openspace::skybrowser::luascriptfunctions { if (module->getPair(id)) { module->getPair(id)->loadImages(root); } - else { - SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); - if (node) { - RenderableSkyBrowser* browser3d = dynamic_cast( - node->renderable()); - if (browser3d) { - // Load Image collections - browser3d->stopSyncingWwtView(); - LINFO("Load images to " + browser3d->identifier()); - browser3d->sendMessageToWwt(wwtmessage::loadCollection(root)); - LINFO("Image collection loaded in " + browser3d->identifier()); - } - } + else if (module->get3dBrowser(id)) { + + // Load Image collections + module->get3dBrowser(id)->stopSyncingWwtView(); + LINFO("Load images to " + module->get3dBrowser(id)->identifier()); + module->get3dBrowser(id)->sendMessageToWwt(wwtmessage::loadCollection(root)); + LINFO("Image collection loaded in " + module->get3dBrowser(id)->identifier()); + } return 0; @@ -139,12 +128,9 @@ namespace openspace::skybrowser::luascriptfunctions { for (Pair pair : pairs) { pair.sendIdToBrowser(); } - SceneGraphNode* node = module->get3dBrowser(); - if(node) { - std::string id = node->identifier(); - RenderableSkyBrowser* browsers3d = dynamic_cast( - node->renderable()); - browsers3d->setIdInBrowser(id); + if(module->get3dBrowser()) { + std::string id = module->get3dBrowserNode()->identifier(); + module->get3dBrowser()->setIdInBrowser(id); } return 0; } @@ -172,17 +158,10 @@ namespace openspace::skybrowser::luascriptfunctions { if (module->getPair(id)) { module->getPair(id)->synchronizeWithWwt(); } - else { - SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); - if (node) { - RenderableSkyBrowser* browser3d = dynamic_cast( - node->renderable()); - if (browser3d && id == node->identifier()) { - // Initialize - LINFO("Initializing 3D sky browsers"); - browser3d->syncWwtView(); - } - } + else if(module->get3dBrowser(id)) { + // Initialize + LINFO("Initializing 3D sky browsers"); + module->get3dBrowser()->syncWwtView(); } return 0; @@ -194,11 +173,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); LINFO("Add to sky browser module id " + id); - SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); - if (node) { - // Add to module - module->set3dBrowser(node); - } + module->set3dBrowser(id); return 0; } @@ -302,11 +277,14 @@ namespace openspace::skybrowser::luascriptfunctions { // Add the window data for OpenSpace ghoul::lua::push(L, "OpenSpace"); lua_newtable(L); - glm::dvec3 cartesian = skybrowser::cameraDirectionEquatorial(); - glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); + glm::dvec3 cartesianCam = skybrowser::cameraDirectionEquatorial(); + glm::dvec2 sphericalCam = skybrowser::cartesianToSpherical(cartesianCam); // Convert to vector so ghoul can read it - std::vector viewDirCelestVec = { cartesian.x, cartesian.y, cartesian.z }; - + std::vector viewDirCelestVec = { + cartesianCam.x, + cartesianCam.y, + cartesianCam.z + }; // Calculate the smallest FOV of vertical and horizontal glm::dvec2 fovs = skybrowser::fovWindow(); @@ -316,9 +294,9 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); lua_settable(L, -3); - ghoul::lua::push(L, "ra", spherical.x); + ghoul::lua::push(L, "ra", sphericalCam.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", spherical.y); + ghoul::lua::push(L, "dec", sphericalCam.y); lua_settable(L, -3); ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); lua_settable(L, -3); @@ -379,17 +357,14 @@ namespace openspace::skybrowser::luascriptfunctions { } } - else if(module->get3dBrowser()){ - SceneGraphNode* node = module->get3dBrowser(); - RenderableSkyBrowser* browser3d = dynamic_cast( - node->renderable()); + else if(module->get3dBrowser()){ // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - std::deque selectedImages = browser3d->getSelectedImages(); + std::deque selectedImages = module->get3dBrowser()->getSelectedImages(); std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { selectedImagesVector.push_back(index); }); - glm::dvec3 position3dBrowser = node->position(); + glm::dvec3 position3dBrowser = module->get3dBrowserNode()->position(); glm::dvec3 cartesian = skybrowser::galacticToEquatorial(position3dBrowser); glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); std::vector celestialCartVec = { @@ -401,14 +376,14 @@ namespace openspace::skybrowser::luascriptfunctions { //glm::ivec3 color = browser->_borderColor.value(); std::vector colorVec = { 200, 200, 200 }; - ghoul::lua::push(L, browser3d->identifier()); + ghoul::lua::push(L, module->get3dBrowser()->identifier()); lua_newtable(L); // Push ("Key", value) - ghoul::lua::push(L, "id", browser3d->identifier()); + ghoul::lua::push(L, "id", module->get3dBrowser()->identifier()); lua_settable(L, -3); - ghoul::lua::push(L, "name", node->guiName()); + ghoul::lua::push(L, "name", module->get3dBrowserNode()->guiName()); lua_settable(L, -3); - ghoul::lua::push(L, "FOV", browser3d->verticalFov()); + ghoul::lua::push(L, "FOV", module->get3dBrowser()->verticalFov()); lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); @@ -445,22 +420,9 @@ namespace openspace::skybrowser::luascriptfunctions { int set3dSelectedImagesAs2dSelection(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); - const std::string id = ghoul::lua::value(L, 1); + const std::string pairId = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); - - if (pair && module->get3dBrowser()) { - RenderableSkyBrowser* browser3d = dynamic_cast( - module->get3dBrowser()->renderable()); - // Empty 3D browser selection - browser3d->getSelectedImages().clear(); - // Copy 2D selection of images to 3D browser - const std::deque images = pair->getSelectedImages(); - std::for_each(std::begin(images), std::end(images), [&](const int i) { - const ImageData& image = module->getWWTDataHandler()->getImage(i); - browser3d->displayImage(image, i); - }); - } + module->add2dSelectedImagesTo3d(pairId); return 0; } @@ -480,10 +442,8 @@ namespace openspace::skybrowser::luascriptfunctions { module->getPair(id)->setImageOpacity(i, opacity); } - else if (module->get3dBrowser() != nullptr) { - RenderableSkyBrowser* browser3d = dynamic_cast( - module->get3dBrowser()->renderable()); - browser3d->sendMessageToWwt(message); + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->sendMessageToWwt(message); } return 0; @@ -505,9 +465,9 @@ namespace openspace::skybrowser::luascriptfunctions { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->setSelectedBrowser(id); - } + + module->setSelectedBrowser(id); + return 0; } @@ -535,16 +495,7 @@ namespace openspace::skybrowser::luascriptfunctions { SkyBrowserModule* module = global::moduleEngine->module(); const ImageData image = module->getWWTDataHandler()->getImage(i); - // If the image has a 3D position, add it to the scene graph - if (image.has3dCoords && module->get3dBrowser()) { - RenderableSkyBrowser* browser = dynamic_cast( - module->get3dBrowser()->renderable()); - browser->displayImage(image, i); - browser->placeAt3dPosition(image); - } - else { - LINFO("Image has no 3D coordinate!"); - } + module->place3dBrowser(image, i); return 0; } @@ -562,10 +513,8 @@ namespace openspace::skybrowser::luascriptfunctions { if (pair) { pair->removeSelectedImage(i); } - else if (module->get3dBrowser() != nullptr) { - RenderableSkyBrowser* browser3d = dynamic_cast( - module->get3dBrowser()->renderable()); - browser3d->removeSelectedImage(image, i); + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->removeSelectedImage(image, i); } return 0; } diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 2d34a88f86..886bbc0970 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -243,6 +243,9 @@ namespace openspace { void Pair::incrementallyFade(float goalState, float fadeTime, float deltaTime) { float opacityDelta = static_cast(deltaTime / fadeTime); + if (_target->opacity() > goalState) { + opacityDelta *= -1.f; + } if (!isTargetFadeFinished(goalState)) { _target->setOpacity(_target->opacity() + opacityDelta); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index bf98160443..7a5ef34f44 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -138,8 +138,8 @@ namespace openspace { ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { // Set flag to false so the thread can exit _isSyncedWithWwt = false; - if (_threadWwtMessages.joinable()) { - _threadWwtMessages.join(); + if (_wwtMessages.joinable()) { + _wwtMessages.join(); LINFO("Joined thread"); } } @@ -198,8 +198,8 @@ namespace openspace { bool ScreenSpaceSkyBrowser::deinitializeGL() { // Set flag to false so the thread can exit _isSyncedWithWwt = false; - if (_threadWwtMessages.joinable()) { - _threadWwtMessages.join(); + if (_wwtMessages.joinable()) { + _wwtMessages.join(); LINFO("Joined thread"); } return ScreenSpaceBrowser::deinitializeGL(); @@ -311,7 +311,7 @@ namespace openspace { void ScreenSpaceSkyBrowser::syncWwtView() { // Start a thread to enable user interaction while sending the calls to WWT - _threadWwtMessages = std::thread([&] { + _wwtMessages = std::thread([&] { while (_isSyncedWithWwt) { if (_skyTarget) { // Message WorldWide Telescope current view From 711ad51936717655f7e5f47b2827e7f91bbb9d97 Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 15 Nov 2021 15:31:19 -0500 Subject: [PATCH 140/251] Remove unneccessary property browser dimensions --- .../include/screenspaceskybrowser.h | 3 +- .../skybrowser/src/screenspaceskybrowser.cpp | 33 +++---------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 291763d591..5ec960475d 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -29,13 +29,13 @@ namespace openspace { bool isAnimated(); void startFovAnimation(float fov); void incrementallyAnimateToFov(float deltaTime); + glm::vec2 browserPixelDimensions(); void startSyncingWithWwt(); glm::dvec2 fineTuneVector(glm::dvec2 drag); // Getters returning values bool hasLoadedImages() const; - glm::vec2 browserPixelDimensions() const; glm::ivec3 borderColor() const; float verticalFov() const; glm::dvec2 fieldsOfView(); @@ -87,7 +87,6 @@ namespace openspace { // Properties properties::FloatProperty _verticalFov; properties::StringProperty _skyTargetId; - properties::Vec2Property _browserDimensions; properties::IVec3Property _borderColor; // Flags diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 7a5ef34f44..a9d736105e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -13,12 +13,6 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; - constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = - { - "BrowserDimensions", - "Browser Dimensions", - "The pixel dimensions of the sky browser." - }; constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = { "VerticalFieldOfView", @@ -42,9 +36,6 @@ namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - // [[codegen::verbatim(BrowserDimensionInfo.description)]] - std::optional browserDimensions; - // [[codegen::verbatim(VerticalFovInfo.description)]] std::optional verticalFov; @@ -62,12 +53,6 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceBrowser(dictionary) - , _browserDimensions( - BrowserDimensionInfo, - _dimensions, - glm::ivec2(0), - glm::ivec2(300) - ) , _verticalFov(VerticalFovInfo, 10.f, 0.1f, 70.f) , _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)) , _skyTargetId(TargetIdInfo) @@ -77,22 +62,15 @@ namespace openspace { // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _browserDimensions = p.browserDimensions.value_or(_browserDimensions); + _verticalFov = p.verticalFov.value_or(_verticalFov); _borderColor = p.borderColor.value_or(_borderColor); _skyTargetId = p.targetId.value_or(_skyTargetId); - addProperty(_browserDimensions); addProperty(_verticalFov); addProperty(_borderColor); addProperty(_skyTargetId); - _browserDimensions.onChange([&]() { - if (_skyTarget) { - glm::vec2 dim = browserPixelDimensions(); - _skyTarget->setDimensions(dim); - } - }); _verticalFov.onChange([&]() { if (_skyTarget) { _skyTarget->setScale(_verticalFov); @@ -211,6 +189,10 @@ namespace openspace { return _skyTarget; } + glm::vec2 ScreenSpaceSkyBrowser::browserPixelDimensions() { + return _dimensions.value(); + } + bool ScreenSpaceSkyBrowser::isAnimated() { return _isFovAnimated; @@ -361,7 +343,6 @@ namespace openspace { glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; _texture->setDimensions(glm::ivec3(newSize, 1)); _objectSize = _texture->dimensions(); - _browserDimensions = newSize; } glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { @@ -393,10 +374,6 @@ namespace openspace { _scale = _originalScale * scalingFactor; } - glm::vec2 ScreenSpaceSkyBrowser::browserPixelDimensions() const { - return _browserDimensions.value(); - } - properties::FloatProperty& ScreenSpaceSkyBrowser::getOpacity() { return _opacity; } From b3b2110aa32ea3c89b63c78da7d288757ac5010a Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 15 Nov 2021 15:33:43 -0500 Subject: [PATCH 141/251] Put external library in ext folder --- modules/skybrowser/{ => ext}/tinyxml2/tinyxml2.cpp | 0 modules/skybrowser/{ => ext}/tinyxml2/tinyxml2.h | 0 modules/skybrowser/include/wwtdatahandler.h | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename modules/skybrowser/{ => ext}/tinyxml2/tinyxml2.cpp (100%) rename modules/skybrowser/{ => ext}/tinyxml2/tinyxml2.h (100%) diff --git a/modules/skybrowser/tinyxml2/tinyxml2.cpp b/modules/skybrowser/ext/tinyxml2/tinyxml2.cpp similarity index 100% rename from modules/skybrowser/tinyxml2/tinyxml2.cpp rename to modules/skybrowser/ext/tinyxml2/tinyxml2.cpp diff --git a/modules/skybrowser/tinyxml2/tinyxml2.h b/modules/skybrowser/ext/tinyxml2/tinyxml2.h similarity index 100% rename from modules/skybrowser/tinyxml2/tinyxml2.h rename to modules/skybrowser/ext/tinyxml2/tinyxml2.h diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index ce9332fb42..2178e65b70 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -1,7 +1,7 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ -#include +#include #include #include From 4b81c76afe45235a69e98297384548c85a1348ed Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 15 Nov 2021 15:34:10 -0500 Subject: [PATCH 142/251] Make enum better for transparency choices --- modules/skybrowser/skybrowsermodule.cpp | 11 ++++++++++- modules/skybrowser/skybrowsermodule.h | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index c997dd7020..40be4b9431 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -814,7 +814,16 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float deltaTime) { - float transparency = static_cast(goal); + float transparency = [](Transparency goal) { + switch (goal) { + case Transparency::Transparent: + return 0.f; + + case Transparency::Opaque: + return 1.f; + } + }(goal); + bool isAllFinished{ false }; for (Pair& pair : _targetsBrowsers) { if (pair.isEnabled()) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 923174674c..e0aa098c4e 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -43,8 +43,8 @@ class ScreenSpaceSkyBrowser; class RenderableSkyBrowser; enum class Transparency { - Transparent = 0, - Opaque = 1 + Transparent, + Opaque }; class SkyBrowserModule : public OpenSpaceModule { From b9aaab22a52b8942fad1db4fe4e16419a9fb1bec Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 15 Nov 2021 15:34:35 -0500 Subject: [PATCH 143/251] Cleanup --- modules/skybrowser/skybrowsermodule.cpp | 8 +++++--- modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/src/pair.cpp | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 40be4b9431..510d768281 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -275,7 +275,7 @@ SkyBrowserModule::SkyBrowserModule() _resizeDirection = _mouseOnPair->getBrowser()->isOnResizeArea( _mousePosition ); - if (_resizeDirection != glm::vec2{ 0 }) { + if (_resizeDirection != glm::ivec2{ 0 }) { _mouseOnPair->getBrowser()->saveResizeStartSize(); _startBrowserSize = _mouseOnPair->getBrowser()-> screenSpaceDimensions(); @@ -336,7 +336,7 @@ SkyBrowserModule::SkyBrowserModule() if (_isResizing) { // Calculate scaling factor glm::vec2 mouseDragVector = (_mousePosition-_startMousePosition); - glm::vec2 scaling = mouseDragVector * _resizeDirection; + glm::vec2 scaling = mouseDragVector * glm::vec2(_resizeDirection); glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / _startBrowserSize; // Scale the browser @@ -345,7 +345,9 @@ SkyBrowserModule::SkyBrowserModule() // For dragging functionality, translate so it looks like the // browser isn't moving. Make sure the browser doesn't move in // directions it's not supposed to - translation = mouseDragVector * abs(_resizeDirection) / 2.f; + translation = 0.5f * mouseDragVector * abs( + glm::vec2(_resizeDirection) + ); } // Translate diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index e0aa098c4e..21f1733a73 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -137,7 +137,7 @@ private: glm::vec2 _startMousePosition; glm::vec2 _startDragPosition; glm::vec2 _startBrowserSize; - glm::vec2 _resizeDirection{ 0.f }; + glm::ivec2 _resizeDirection{ 0 }; // Animation of rotation of camera to look at coordinate galactic coordinates glm::dvec3 _startAnimation; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 886bbc0970..409ec3a978 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace openspace { @@ -34,8 +35,8 @@ namespace openspace { Pair::Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) : _target(target), _browser(browser) { - assert(browser != nullptr, "Sky browser is null pointer!"); - assert(target != nullptr, "Sky target is null pointer!"); + ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); + ghoul_assert(target != nullptr, "Sky target is null pointer!"); } void Pair::lock() { From 67a8dfb727120209cc7967488367ef26cd691de0 Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 15 Nov 2021 15:35:25 -0500 Subject: [PATCH 144/251] Add new classes for browsers --- modules/skybrowser/include/browser.h | 107 ++++++ .../include/screenspaceskybrowser2.h | 89 +++++ modules/skybrowser/include/wwtcommunicator.h | 87 +++++ modules/skybrowser/src/browser.cpp | 174 +++++++++ .../skybrowser/src/screenspaceskybrowser2.cpp | 335 ++++++++++++++++++ modules/skybrowser/src/wwtcommunicator.cpp | 183 ++++++++++ 6 files changed, 975 insertions(+) create mode 100644 modules/skybrowser/include/browser.h create mode 100644 modules/skybrowser/include/screenspaceskybrowser2.h create mode 100644 modules/skybrowser/include/wwtcommunicator.h create mode 100644 modules/skybrowser/src/browser.cpp create mode 100644 modules/skybrowser/src/screenspaceskybrowser2.cpp create mode 100644 modules/skybrowser/src/wwtcommunicator.cpp diff --git a/modules/skybrowser/include/browser.h b/modules/skybrowser/include/browser.h new file mode 100644 index 0000000000..a50fda6f2f --- /dev/null +++ b/modules/skybrowser/include/browser.h @@ -0,0 +1,107 @@ +/***************************************************************************************** + * * + * 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_SKYBROWSER___BROWSER___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___BROWSER___H__ + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4100) +#endif // _MSC_VER + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + +#include + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#ifdef _MSC_VER +#pragma warning (pop) +#endif // _MSC_VER + +namespace ghoul::opengl { class Texture; } + +namespace openspace { + + class BrowserInstance; + class RenderHandler; + class WebKeyboardHandler; + +class Browser { +public: + + Browser(const ghoul::Dictionary& dictionary); + Browser(Browser const&) = default; + ~Browser(); + + bool initializeGL(); + bool deinitializeGL(); + + void render(); + void update(); + bool isReady() const; + + glm::vec2 browserPixelDimensions() const; + + +protected: + properties::Vec2Property _dimensions; + properties::StringProperty _url; + properties::TriggerProperty _reload; + std::unique_ptr _browserInstance; + std::unique_ptr _texture; + + + class RenderHandler : public WebRenderHandler { + public: + void draw() override; + void render() override; + + void setTexture(GLuint t); + }; + +private: + void bindTexture(); + + CefRefPtr _renderHandler; + CefRefPtr _keyboardHandler; + + bool _isUrlDirty = false; + bool _isDimensionsDirty = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SKYBROWSER___BROWSER___H__ diff --git a/modules/skybrowser/include/screenspaceskybrowser2.h b/modules/skybrowser/include/screenspaceskybrowser2.h new file mode 100644 index 0000000000..4d88b2ba2c --- /dev/null +++ b/modules/skybrowser/include/screenspaceskybrowser2.h @@ -0,0 +1,89 @@ +#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace openspace { + class ScreenSpaceSkyTarget; + + class ScreenSpaceSkyBrowser2 : public ScreenSpaceRenderable, public WwtCommunicator + { + public: + // Constructor and destructor + ScreenSpaceSkyBrowser2(const ghoul::Dictionary& dictionary); + virtual ~ScreenSpaceSkyBrowser2(); + + // Inherited functions + bool initializeGL() override; + bool deinitializeGL() override; + glm::mat4 scaleMatrix() override; + void render() override; + void update() override; + + // Target - browser connection + bool connectToSkyTarget(); + bool isAnimated(); + void startFovAnimation(float fov); + void incrementallyAnimateToFov(float deltaTime); + glm::dvec2 fineTuneVector(glm::dvec2 drag); + + // Getters returning references + ScreenSpaceSkyTarget* getSkyTarget(); + properties::FloatProperty& getOpacity(); + + // Setters + void setVerticalFovWithScroll(float scroll); + void setScale(glm::vec2 scalingFactor); + void setScale(float scalingFactor); + + // Communication with WorldWide Telescope + void startSyncingWithWwt(); + + + // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in + // image if the mouse is on a side of the browser + // __1__ + // y| -1 |_____|1 + // |__x -1 + glm::ivec2 isOnResizeArea(glm::vec2 screenSpaceCoord); + + private: + void syncWwtView(); + void bindTexture() override; + + // Resize functions + void saveResizeStartSize(); + void updateBrowserSize(); + + // Properties + properties::StringProperty _skyTargetId; + + // Flags + bool _isSyncedWithWwt{ false }; + bool _isFovAnimated{ false }; + float _endVfov{ 0.f }; + float _fovDiff{ 0.01f }; + + // Resizing of browser + glm::vec2 _originalDimensions; + float _originalScale; + float _resizeAreaPercentage{ 0.1f }; + + // Target & images + ScreenSpaceSkyTarget* _skyTarget{ nullptr }; + std::thread _wwtMessages; + + // Time variables + // For capping the calls to change the zoom from scrolling + constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; + std::chrono::system_clock::time_point _lastUpdateTime; + }; +} + +#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h new file mode 100644 index 0000000000..cc6672f64d --- /dev/null +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -0,0 +1,87 @@ +/***************************************************************************************** + * * + * 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_SKYBROWSER___WWTCOMMUNICATOR___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___WWTCOMMUNICATOR___H__ + +#include +#include +#include +#include +#include +#include + +namespace openspace { + +class ImageData; + +class WwtCommunicator : public Browser { + +public: + + WwtCommunicator(const ghoul::Dictionary& dictionary); + WwtCommunicator(WwtCommunicator const&) = default; + virtual ~WwtCommunicator(); + + // Web page communication + + void setIdInBrowser(const std::string& id); + + // WorldWide Telescope communication + void displayImage(const std::string& url, const int i); + void removeSelectedImage(const int i); + void setImageLayerOrder(int i, int order); + + // Getters + const std::deque& getSelectedImages(); + glm::ivec3 borderColor() const; + float verticalFov() const; + glm::dvec2 fieldsOfView(); + bool hasLoadedImages() const; + + + // Setters + void setHasLoadedImages(bool isLoaded); + void setVerticalFov(float vfov); + void setWebpageBorderColor(glm::ivec3 color); + + // Display + void highlight(glm::ivec3 addition); + void removeHighlight(glm::ivec3 removal); + +protected: + void sendMessageToWwt(const ghoul::Dictionary& msg); + properties::FloatProperty _verticalFov; + properties::IVec3Property _borderColor; + + std::deque _selectedImages; + bool _hasLoadedImages{ false }; + +private: + void executeJavascript(const std::string& script) const; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SKYBROWSER___WWTCOMMUNICATOR___H__ diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp new file mode 100644 index 0000000000..7dc2347dbd --- /dev/null +++ b/modules/skybrowser/src/browser.cpp @@ -0,0 +1,174 @@ +/***************************************************************************************** + * * + * 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 +#include +#include +#include +#include + +namespace { + constexpr const char* _loggerCat = "Browser"; + + const openspace::properties::Property::PropertyInfo DimensionsInfo = { + "Dimensions", + "Browser Dimensions", + "Set the dimensions of the web browser window." + }; + const openspace::properties::Property::PropertyInfo UrlInfo = { + "Url", + "URL", + "The URL to load" + }; + + const openspace::properties::Property::PropertyInfo ReloadInfo = { + "Reload", + "Reload", + "Reload the web browser" + }; + +} // namespace + +namespace openspace { + + void Browser::RenderHandler::draw() {} + + void Browser::RenderHandler::render() {} + + void Browser::RenderHandler::setTexture(GLuint t) { + _texture = t; + } + + + Browser::Browser(const ghoul::Dictionary& dictionary) + : _url(UrlInfo) + , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) + , _reload(ReloadInfo) + { + if (dictionary.hasValue(UrlInfo.identifier)) { + _url = dictionary.value(UrlInfo.identifier); + } + + glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); + _dimensions = windowDimensions; + + _url.onChange([this]() { _isUrlDirty = true; }); + _dimensions.onChange([this]() { _isDimensionsDirty = true; }); + _reload.onChange([this]() { _browserInstance->reloadBrowser(); }); + + // Create browser and render handler + _renderHandler = new RenderHandler(); + _keyboardHandler = new WebKeyboardHandler(); + _browserInstance = std::make_unique( + _renderHandler, + _keyboardHandler + ); + + WebBrowserModule* webBrowser = global::moduleEngine->module(); + if (webBrowser) { + webBrowser->addBrowser(_browserInstance.get()); + } + } + + Browser::~Browser() { + // Delete + _browserInstance.reset(); + _texture.reset(); + } + + bool Browser::initializeGL() { + _texture = std::make_unique( + glm::uvec3(_dimensions.value(), 1.0f) + ); + + _renderHandler->setTexture(*_texture); + + _browserInstance->initialize(); + _browserInstance->loadUrl(_url); + return isReady(); + } + + + bool Browser::deinitializeGL() { + _renderHandler->setTexture(0); + _texture = nullptr; + + std::string urlString; + _url.getStringValue(urlString); + LDEBUG(fmt::format("Deinitializing ScreenSpaceBrowser: {}", urlString)); + + _browserInstance->close(true); + + WebBrowserModule* webBrowser = global::moduleEngine->module(); + if (webBrowser) { + webBrowser->removeBrowser(_browserInstance.get()); + _browserInstance.reset(); + } + else { + LWARNING("Could not find WebBrowserModule"); + } + + return true; + } + + void Browser::render() { + if (!_renderHandler->isTextureReady()) { + return; + } + _renderHandler->updateTexture(); + + } + + void Browser::update() { + if (_isUrlDirty) { + _browserInstance->loadUrl(_url); + _isUrlDirty = false; + } + + if (_isDimensionsDirty) { + _browserInstance->reshape(_dimensions.value()); + _isDimensionsDirty = false; + } + } + + bool Browser::isReady() const { + return _texture.get(); + } + + void Browser::bindTexture() { + _texture->bind(); + } + + glm::vec2 Browser::browserPixelDimensions() const { + return _dimensions.value(); + } + + +} // namespace openspace diff --git a/modules/skybrowser/src/screenspaceskybrowser2.cpp b/modules/skybrowser/src/screenspaceskybrowser2.cpp new file mode 100644 index 0000000000..748461d6a6 --- /dev/null +++ b/modules/skybrowser/src/screenspaceskybrowser2.cpp @@ -0,0 +1,335 @@ +#include + +#include +#include +#include +#include +#include +#include // formatJson +#include +#include + +namespace { + constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser2"; + + constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = + { + "BrowserDimensions", + "Browser Dimensions", + "The pixel dimensions of the sky browser." + }; + constexpr const openspace::properties::Property::PropertyInfo TargetIdInfo = + { + "TargetId", + "Target Id", + "The identifier of the target. It is used to synchronize the sky browser and the" + "sky target." + }; + constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = + { + "BorderColor", + "Border Color", + "The color of the border of the sky browser." + }; + constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = + { + "VerticalFieldOfView", + "Vertical Field Of View", + "The vertical field of view in degrees." + }; + + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser2)]] Parameters { + + // [[codegen::verbatim(BrowserDimensionInfo.description)]] + std::optional browserDimensions; + + // [[codegen::verbatim(VerticalFovInfo.description)]] + std::optional verticalFov; + + // [[codegen::verbatim(TargetIdInfo.description)]] + std::optional targetId; + + // [[codegen::verbatim(BorderColorInfo.description)]] + std::optional borderColor; + }; + +#include "ScreenSpaceSkyBrowser2_codegen.cpp" +} // namespace + +namespace openspace { + + ScreenSpaceSkyBrowser2::ScreenSpaceSkyBrowser2(const ghoul::Dictionary& dictionary) + : ScreenSpaceRenderable(dictionary), + WwtCommunicator(dictionary) + , _skyTargetId(TargetIdInfo) + { + // Make the color property display a color picker in the GUI + _borderColor.setViewOption("Color", true); + + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _verticalFov = p.verticalFov.value_or(_verticalFov); + _borderColor = p.borderColor.value_or(_borderColor); + _skyTargetId = p.targetId.value_or(_skyTargetId); + + addProperty(_dimensions); + addProperty(_verticalFov); + addProperty(_borderColor); + addProperty(_skyTargetId); + + _verticalFov.onChange([&]() { + if (_skyTarget) { + _skyTarget->setScale(_verticalFov); + } + }); + _borderColor.onChange([&]() { + setWebpageBorderColor(_borderColor.value()); + }); + _skyTargetId.onChange([&]() { + connectToSkyTarget(); + }); + + // Set a unique identifier + std::string identifier; + if (dictionary.hasValue(KeyIdentifier)) { + identifier = dictionary.value(KeyIdentifier); + } + else { + identifier = "ScreenSpaceSkyBrowser22"; + } + identifier = makeUniqueIdentifier(identifier); + setIdentifier(identifier); + + glm::vec2 screenPosition = _cartesianPosition.value(); + _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + + // Always make sure that the target and browser are visible together + _enabled.onChange([&]() { + if (_skyTarget) { + _skyTarget->property("Enabled")->set(_enabled.value()); + } + }); + + // Ensure the color of the border is bright enough. + // Make sure the RGB color at least is 50% brightness + // By making each channel 50% bright in general + // 222 = sqrt(3*(0.5*256)^2) + while (glm::length(glm::vec3(_borderColor.value())) < 222.f) { + _borderColor = glm::vec3(rand() % 256, rand() % 256, rand() % 256); + } + } + + ScreenSpaceSkyBrowser2::~ScreenSpaceSkyBrowser2() { + // Set flag to false so the thread can exit + _isSyncedWithWwt = false; + if (_wwtMessages.joinable()) { + _wwtMessages.join(); + LINFO("Joined thread"); + } + } + + bool ScreenSpaceSkyBrowser2::initializeGL() { + + return Browser::initializeGL() && ScreenSpaceRenderable::initializeGL(); + } + + + void ScreenSpaceSkyBrowser2::startSyncingWithWwt() { + // If the camera is already synced, the browser is already syncing + if (!_isSyncedWithWwt) { + _isSyncedWithWwt = true; + // Set border color + setWebpageBorderColor(_borderColor.value()); + // Track target + syncWwtView(); + } + } + + glm::dvec2 ScreenSpaceSkyBrowser2::fineTuneVector(glm::dvec2 drag) { + // Fine tuning of target + glm::dvec2 wwtFov = fieldsOfView(); + glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); + + glm::dvec2 browserDim = screenSpaceDimensions(); + glm::dvec2 angleResult = wwtFov * (drag / browserDim); + glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; + + // Convert to screen space coordinate system + glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; + glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; + return result; + } + /* + void ScreenSpaceBrowser::setXCallback(std::function callback) { + _originalDimensions.onChange(std::move(callback)); + } + */ + bool ScreenSpaceSkyBrowser2::deinitializeGL() { + // Set flag to false so the thread can exit + _isSyncedWithWwt = false; + if (_wwtMessages.joinable()) { + _wwtMessages.join(); + LINFO("Joined thread"); + } + return Browser::deinitializeGL() && ScreenSpaceRenderable::deinitializeGL(); + } + + bool ScreenSpaceSkyBrowser2::connectToSkyTarget() { + _skyTarget = dynamic_cast( + global::renderEngine->screenSpaceRenderable(_skyTargetId.value())); + return _skyTarget; + } + + bool ScreenSpaceSkyBrowser2::isAnimated() + { + return _isFovAnimated; + } + + void ScreenSpaceSkyBrowser2::startFovAnimation(float fov) + { + _isFovAnimated = true; + _endVfov = fov; + } + + void ScreenSpaceSkyBrowser2::incrementallyAnimateToFov(float deltaTime) + { + // If distance too large, keep animating. Else, stop animation + float diff = verticalFov() - _endVfov; + const bool shouldAnimate = abs(diff) > _fovDiff; + + if (shouldAnimate) { + setVerticalFovWithScroll(diff); + } + else { + _isFovAnimated = false; + } + } + + void ScreenSpaceSkyBrowser2::render() { + Browser::render(); + + draw( + globalRotationMatrix() * + translationMatrix() * + localRotationMatrix() * + scaleMatrix() + ); + } + + void ScreenSpaceSkyBrowser2::update() { + Browser::update(); + ScreenSpaceRenderable::update(); + } + + ScreenSpaceSkyTarget* ScreenSpaceSkyBrowser2::getSkyTarget() { + return _skyTarget; + } + + void ScreenSpaceSkyBrowser2::setVerticalFovWithScroll(float scroll) { + // Cap how often the zoom is allowed to update + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; + + if (timeSinceLastUpdate > _timeUpdateInterval) { + // Make scroll more sensitive the smaller the FOV + float x = _verticalFov; + float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; + float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; + _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); + _lastUpdateTime = std::chrono::system_clock::now(); + } + } + + void ScreenSpaceSkyBrowser2::syncWwtView() { + + // Start a thread to enable user interaction while sending the calls to WWT + _wwtMessages = std::thread([&] { + while (_isSyncedWithWwt) { + if (_skyTarget) { + // Message WorldWide Telescope current view + glm::dvec3 cartesian = _skyTarget->directionEquatorial(); + + ghoul::Dictionary message = wwtmessage::moveCamera( + skybrowser::cartesianToSpherical(cartesian), + _verticalFov, + skybrowser::cameraRoll() + ); + sendMessageToWwt(message); + } + + // Sleep so we don't bombard WWT with too many messages + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + }); + + } + + glm::ivec2 ScreenSpaceSkyBrowser2::isOnResizeArea(glm::vec2 coord) { + glm::ivec2 resizePosition = glm::ivec2{ 0 }; + // Make sure coordinate is on browser + if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; + + // TO DO: turn this into a vector and use prettier vector arithmetic + float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; + float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; + + const bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; + const bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; + const bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; + const bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; + + resizePosition.x = isOnRight ? 1 : isOnLeft ? -1 : 0; + resizePosition.y = isOnTop ? 1 : isOnBottom ? -1 : 0; + + return resizePosition; + } + // Scales the ScreenSpaceBrowser to a new ratio + void ScreenSpaceSkyBrowser2::setScale(glm::vec2 scalingFactor) { + + // Scale on the y axis, this is to ensure that _scale = 1 is + // equal to the height of the window + setScale(abs(scalingFactor.y)); + // Resize the dimensions of the texture on the x axis + glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; + _texture->setDimensions(glm::ivec3(newSize, 1)); + _objectSize = _texture->dimensions(); + } + + glm::mat4 ScreenSpaceSkyBrowser2::scaleMatrix() { + // To ensure the plane has the right ratio + // The _scale tells us how much of the windows height the + // browser covers: e.g. a browser that covers 0.25 of the + // height of the window will have scale = 0.25 + + float textureRatio = static_cast(_texture->dimensions().x) / + static_cast(_texture->dimensions().y); + + glm::mat4 scale = glm::scale( + glm::mat4(1.f), + glm::vec3(textureRatio * _scale, _scale, 1.f) + ); + return scale; + } + + void ScreenSpaceSkyBrowser2::saveResizeStartSize() { + _originalDimensions = _dimensions.value(); + _originalScale = _scale.value(); + } + + // Updates the browser size to match the size of the texture + void ScreenSpaceSkyBrowser2::updateBrowserSize() { + _dimensions = _texture->dimensions(); + } + + void ScreenSpaceSkyBrowser2::setScale(float scalingFactor) { + _scale = _originalScale * scalingFactor; + } + + properties::FloatProperty& ScreenSpaceSkyBrowser2::getOpacity() { + return _opacity; + } + + void ScreenSpaceSkyBrowser2::bindTexture() { + _texture->bind(); + } +} diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp new file mode 100644 index 0000000000..0018a5ce18 --- /dev/null +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -0,0 +1,183 @@ +/***************************************************************************************** + * * + * 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 // formatJson +#include + + +namespace { + constexpr const char* _loggerCat = "WwtCommunicator"; + + constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = + { + "BorderColor", + "Border Color", + "The color of the border of the sky browser." + }; + constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = + { + "VerticalFieldOfView", + "Vertical Field Of View", + "The vertical field of view in degrees." + }; + +} // namespace + +namespace openspace { + + WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary) + : Browser(dictionary), + _verticalFov(VerticalFovInfo, 10.f, 0.01f, 70.0f), + _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)) + { + + } + + WwtCommunicator::~WwtCommunicator() { + + } + + void WwtCommunicator::displayImage(const std::string& url, int i) + { + // Ensure there are no duplicates + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + if (it == std::end(_selectedImages)) { + // Push newly selected image to front + _selectedImages.push_front(i); + // Index of image is used as layer ID as it is unique in the image data set + sendMessageToWwt(wwtmessage::addImage(std::to_string(i), url)); + sendMessageToWwt(wwtmessage::setImageOpacity(std::to_string(i), 1.0)); + } + } + + void WwtCommunicator::removeSelectedImage(const int i) { + // Remove from selected list + auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); + + if (it != std::end(_selectedImages)) { + _selectedImages.erase(it); + sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); + } + } + + void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) { + std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; + executeJavascript(script); + } + + const std::deque& WwtCommunicator::getSelectedImages() { + return _selectedImages; + } + + void WwtCommunicator::setVerticalFov(float vfov) { + _verticalFov = vfov; + } + + void WwtCommunicator::setWebpageBorderColor(glm::ivec3 color) { + std::string stringColor = std::to_string(color.x) + "," + + std::to_string(color.y) + "," + std::to_string(color.z); + std::string script = "document.body.style.backgroundColor = 'rgb(" + + stringColor + ")';"; + executeJavascript(script); + } + + void WwtCommunicator::highlight(glm::ivec3 addition) + { + glm::ivec3 color = glm::ivec3(_borderColor.value()); + setWebpageBorderColor(color + addition); + } + + void WwtCommunicator::removeHighlight(glm::ivec3 removal) + { + glm::ivec3 color = glm::ivec3(_borderColor.value()); + setWebpageBorderColor(color - removal); + } + + glm::dvec2 WwtCommunicator::fieldsOfView() { + float browserRatio = _dimensions.value().x / _dimensions.value().y; + glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio, verticalFov()); + + return browserFov; + } + + bool WwtCommunicator::hasLoadedImages() const { + return _hasLoadedImages; + } + + void WwtCommunicator::setImageLayerOrder(int i, int order) { + // Find in selected images list + auto current = std::find( + std::begin(_selectedImages), + std::end(_selectedImages), + i + ); + auto target = std::begin(_selectedImages) + order; + + // Make sure the image was found in the list + if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { + // Swap the two images + std::iter_swap(current, target); + } + + int reverseOrder = _selectedImages.size() - order - 1; + ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), + reverseOrder); + sendMessageToWwt(message); + } + + void WwtCommunicator::setHasLoadedImages(bool isLoaded) { + _hasLoadedImages = isLoaded; + } + + void WwtCommunicator::setIdInBrowser(const std::string& id) { + // Send ID to it's browser + executeJavascript("setId('" + id + "')"); + } + + void WwtCommunicator::executeJavascript(const std::string& script) const { + // Make sure that the browser has a main frame + const bool browserExists = _browserInstance && _browserInstance->getBrowser(); + const bool frameIsLoaded = browserExists && + _browserInstance->getBrowser()->GetMainFrame(); + + if (frameIsLoaded) { + CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); + frame->ExecuteJavaScript(script, frame->GetURL(), 0); + } + } + + glm::ivec3 WwtCommunicator::borderColor() const { + return _borderColor.value(); + } + + float WwtCommunicator::verticalFov() const { + return _verticalFov.value(); + } + +} // namespace openspace From 80e4e26b43c7aba171d1afd32db9855843c5c531 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 17 Nov 2021 10:59:52 -0500 Subject: [PATCH 145/251] Remove old screen space sky browser --- data/assets/skyBrowserTargetPair.asset | 39 -- .../include/screenspaceskybrowser.h | 117 ----- .../skybrowser/src/screenspaceskybrowser.cpp | 437 ------------------ 3 files changed, 593 deletions(-) delete mode 100644 data/assets/skyBrowserTargetPair.asset delete mode 100644 modules/skybrowser/include/screenspaceskybrowser.h delete mode 100644 modules/skybrowser/src/screenspaceskybrowser.cpp diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset deleted file mode 100644 index 5e4857f3b1..0000000000 --- a/data/assets/skyBrowserTargetPair.asset +++ /dev/null @@ -1,39 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - -local targetId= "SkyTarget0" -local browserId = "SkyBrowser0" -local serverUrl = "https://data.openspaceproject.com/dist/skybrowser/page/" ---local localHostUrl = "http://localhost:8000" - -local browser = { - Type = "ScreenSpaceSkyBrowser", - Identifier = browserId, - Name = "Sky Browser", - Url = serverUrl, - FaceCamera = false, - TargetId = targetId, - CartesianPosition = {-1.0, -0.5, -2.1}, -}; - -local target = { - Type = "ScreenSpaceSkyTarget", - Identifier = targetId, - Name = "Sky Target", - FaceCamera = false, - BrowserId = browserId, -}; - -asset.onInitialize(function () - openspace.addScreenSpaceRenderable(browser) - openspace.addScreenSpaceRenderable(target) - openspace.skybrowser.addPairToSkyBrowserModule(targetId,browserId) - openspace.skybrowser.connectBrowserTarget(browserId) - openspace.skybrowser.setSelectedBrowser(browserId) -end) - -asset.onDeinitialize(function () - openspace.removeScreenSpaceRenderable(browserId) - openspace.removeScreenSpaceRenderable(targetId) -end) - -asset.export("browser", {browser, target}) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h deleted file mode 100644 index 5ec960475d..0000000000 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ -#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ - -#include -#include -#include -#include -#include -#include -#include - -namespace openspace { - //class ScreenSpaceSkyTarget; - - class ScreenSpaceSkyBrowser : public ScreenSpaceBrowser - { - public: - // Constructor and destructor - ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); - virtual ~ScreenSpaceSkyBrowser(); - - // Inherited functions - bool initializeGL() override; - bool deinitializeGL() override; - glm::mat4 scaleMatrix() override; - - // Target - browser connection - bool connectToSkyTarget(); - bool isAnimated(); - void startFovAnimation(float fov); - void incrementallyAnimateToFov(float deltaTime); - glm::vec2 browserPixelDimensions(); - - void startSyncingWithWwt(); - glm::dvec2 fineTuneVector(glm::dvec2 drag); - - // Getters returning values - bool hasLoadedImages() const; - glm::ivec3 borderColor() const; - float verticalFov() const; - glm::dvec2 fieldsOfView(); - - // Getters returning references - ScreenSpaceSkyTarget* getSkyTarget(); - const std::deque& getSelectedImages(); - properties::FloatProperty& getOpacity(); - - // Setters - void setHasLoadedImages(bool isLoaded); - void setVerticalFov(float vfov); - void setVerticalFovWithScroll(float scroll); - void setScale(glm::vec2 scalingFactor); - void setScale(float scalingFactor); - void setWebpageBorderColor(glm::ivec3 color); - - void sendIdToBrowser(); - - // Display - void highlight(glm::ivec3 addition); - void removeHighlight(glm::ivec3 removal); - - // Communication with WorldWide Telescope - void addSelectedImage(const std::string& url, int i); - void removeSelectedImage(int i); - void setImageOrder(int i, int order); - void sendMessageToWwt(const ghoul::Dictionary& msg); - void syncWwtView(); - - // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in - // image if the mouse is on a side of the browser - // __1__ - // y| -1 |_____|1 - // |__x -1 - glm::vec2 isOnResizeArea(glm::vec2 screenSpaceCoord); - - // Resize functions - void saveResizeStartSize(); - void updateBrowserSize(); - - // Translation - //void translate(glm::vec2 translation); - - private: - // Communication with the web page - void executeJavascript(std::string script); - - // Properties - properties::FloatProperty _verticalFov; - properties::StringProperty _skyTargetId; - properties::IVec3Property _borderColor; - - // Flags - bool _hasLoadedImages{ false }; - bool _isSyncedWithWwt{ false }; - bool _isFovAnimated{ false }; - float _endVfov{ 0.f }; - float _fovDiff{ 0.01f }; - - // Resizing of browser - glm::vec2 _originalDimensions; - float _originalScale; - float _resizeAreaPercentage{ 0.1f }; - - // Target & images - ScreenSpaceSkyTarget* _skyTarget{ nullptr }; - std::thread _wwtMessages; - std::deque _selectedImages; - - // Time variables - // For capping the calls to change the zoom from scrolling - constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; - std::chrono::system_clock::time_point _lastUpdateTime; - }; -} - -#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ - diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp deleted file mode 100644 index a9d736105e..0000000000 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ /dev/null @@ -1,437 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include // formatJson -#include -#include - -namespace { - constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; - - constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = - { - "VerticalFieldOfView", - "Vertical Field Of View", - "The vertical field of view in degrees." - }; - constexpr const openspace::properties::Property::PropertyInfo TargetIdInfo = - { - "TargetId", - "Target Id", - "The identifier of the target. It is used to synchronize the sky browser and the" - "sky target." - }; - constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = - { - "BorderColor", - "Border Color", - "The color of the border of the sky browser as well as the sky target." - }; - - - struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - - // [[codegen::verbatim(VerticalFovInfo.description)]] - std::optional verticalFov; - - // [[codegen::verbatim(TargetIdInfo.description)]] - std::optional targetId; - - // [[codegen::verbatim(BorderColorInfo.description)]] - std::optional borderColor; - }; - -#include "screenspaceskybrowser_codegen.cpp" -} // namespace - -namespace openspace { - - ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) - : ScreenSpaceBrowser(dictionary) - , _verticalFov(VerticalFovInfo, 10.f, 0.1f, 70.f) - , _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)) - , _skyTargetId(TargetIdInfo) - { - // Make the color property display a color picker in the GUI - _borderColor.setViewOption("Color", true); - - // Handle target dimension property - const Parameters p = codegen::bake(dictionary); - - _verticalFov = p.verticalFov.value_or(_verticalFov); - _borderColor = p.borderColor.value_or(_borderColor); - _skyTargetId = p.targetId.value_or(_skyTargetId); - - addProperty(_verticalFov); - addProperty(_borderColor); - addProperty(_skyTargetId); - - _verticalFov.onChange([&]() { - if (_skyTarget) { - _skyTarget->setScale(_verticalFov); - } - }); - _borderColor.onChange([&]() { - setWebpageBorderColor(_borderColor.value()); - }); - _skyTargetId.onChange([&]() { - connectToSkyTarget(); - }); - - // Set a unique identifier - std::string identifier; - if (dictionary.hasValue(KeyIdentifier)) { - identifier = dictionary.value(KeyIdentifier); - } - else { - identifier = "ScreenSpaceSkyBrowser"; - } - identifier = makeUniqueIdentifier(identifier); - setIdentifier(identifier); - - glm::vec2 screenPosition = _cartesianPosition.value(); - _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); - - // Always make sure that the target and browser are visible together - _enabled.onChange([&]() { - if (_skyTarget) { - _skyTarget->property("Enabled")->set(_enabled.value()); - } - }); - - // Ensure the color of the border is bright enough. - // Make sure the RGB color at least is 50% brightness - // By making each channel 50% bright in general - // 222 = sqrt(3*(0.5*256)^2) - while (glm::length(glm::vec3(_borderColor.value())) < 222.f) { - _borderColor = glm::vec3(rand() % 256, rand() % 256, rand() % 256); - } - } - - ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { - // Set flag to false so the thread can exit - _isSyncedWithWwt = false; - if (_wwtMessages.joinable()) { - _wwtMessages.join(); - LINFO("Joined thread"); - } - } - - bool ScreenSpaceSkyBrowser::initializeGL() { - return ScreenSpaceBrowser::initializeGL(); - } - - void ScreenSpaceSkyBrowser::sendIdToBrowser() { - // Send ID to it's browser - executeJavascript("setId('" + identifier() + "')"); - } - - void ScreenSpaceSkyBrowser::highlight(glm::ivec3 addition) - { - glm::ivec3 color = glm::ivec3(_borderColor.value()); - setWebpageBorderColor( color + addition ); - } - - void ScreenSpaceSkyBrowser::removeHighlight(glm::ivec3 removal) - { - glm::ivec3 color = glm::ivec3(_borderColor.value()); - setWebpageBorderColor( color - removal ); - } - - void ScreenSpaceSkyBrowser::startSyncingWithWwt() { - // If the camera is already synced, the browser is already syncing - if (!_isSyncedWithWwt) { - _isSyncedWithWwt = true; - // Set border color - setWebpageBorderColor(_borderColor.value()); - // Track target - syncWwtView(); - } - } - - glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) { - // Fine tuning of target - glm::dvec2 wwtFov = fieldsOfView(); - glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); - - glm::dvec2 browserDim = screenSpaceDimensions(); - glm::dvec2 angleResult = wwtFov * (drag / browserDim); - glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; - - // Convert to screen space coordinate system - glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; - glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; - return result; - } - /* - void ScreenSpaceBrowser::setXCallback(std::function callback) { - _originalDimensions.onChange(std::move(callback)); - } - */ - bool ScreenSpaceSkyBrowser::deinitializeGL() { - // Set flag to false so the thread can exit - _isSyncedWithWwt = false; - if (_wwtMessages.joinable()) { - _wwtMessages.join(); - LINFO("Joined thread"); - } - return ScreenSpaceBrowser::deinitializeGL(); - } - - bool ScreenSpaceSkyBrowser::connectToSkyTarget() { - _skyTarget = dynamic_cast( - global::renderEngine->screenSpaceRenderable(_skyTargetId.value())); - return _skyTarget; - } - - glm::vec2 ScreenSpaceSkyBrowser::browserPixelDimensions() { - return _dimensions.value(); - } - - bool ScreenSpaceSkyBrowser::isAnimated() - { - return _isFovAnimated; - } - - void ScreenSpaceSkyBrowser::startFovAnimation(float fov) - { - _isFovAnimated = true; - _endVfov = fov; - } - - void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) - { - // If distance too large, keep animating. Else, stop animation - float diff = verticalFov() - _endVfov; - const bool shouldAnimate = abs(diff) > _fovDiff; - - if (shouldAnimate) { - setVerticalFovWithScroll(diff); - } - else { - _isFovAnimated = false; - } - } - - ScreenSpaceSkyTarget* ScreenSpaceSkyBrowser::getSkyTarget() { - return _skyTarget; - } - - bool ScreenSpaceSkyBrowser::hasLoadedImages() const { - return _hasLoadedImages; - } - - void ScreenSpaceSkyBrowser::setHasLoadedImages(bool isLoaded) { - _hasLoadedImages = isLoaded; - } - - void ScreenSpaceSkyBrowser::setVerticalFov(float vfov) { - _verticalFov = vfov; - } - - void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { - // Cap how often the zoom is allowed to update - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; - - if (timeSinceLastUpdate > _timeUpdateInterval) { - // Make scroll more sensitive the smaller the FOV - float x = _verticalFov; - float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; - float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); - _lastUpdateTime = std::chrono::system_clock::now(); - } - } - - void ScreenSpaceSkyBrowser::executeJavascript(std::string script) { - // Make sure that the browser has a main frame - const bool browserExists = _browserInstance && _browserInstance->getBrowser(); - const bool frameIsLoaded = browserExists && - _browserInstance->getBrowser()->GetMainFrame(); - - if (frameIsLoaded) { - CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - frame->ExecuteJavaScript(script, frame->GetURL(), 0); - } - } - - glm::ivec3 ScreenSpaceSkyBrowser::borderColor() const { - return _borderColor.value(); - } - - float ScreenSpaceSkyBrowser::verticalFov() const { - return _verticalFov.value(); - } - - glm::dvec2 ScreenSpaceSkyBrowser::fieldsOfView() { - glm::dvec2 browserDim = screenSpaceDimensions(); - double browserRatio = browserDim.x / browserDim.y; - glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio, verticalFov()); - - return browserFov; - } - - void ScreenSpaceSkyBrowser::setWebpageBorderColor(glm::ivec3 color) { - std::string stringColor = std::to_string(color.x) + "," - + std::to_string(color.y) + "," + std::to_string(color.z); - std::string script = "document.body.style.backgroundColor = 'rgb(" - + stringColor + ")';"; - executeJavascript(script); - } - - void ScreenSpaceSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) { - std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; - executeJavascript(script); - } - - void ScreenSpaceSkyBrowser::syncWwtView() { - - // Start a thread to enable user interaction while sending the calls to WWT - _wwtMessages = std::thread([&] { - while (_isSyncedWithWwt) { - if (_skyTarget) { - // Message WorldWide Telescope current view - glm::dvec3 cartesian = _skyTarget->directionEquatorial(); - - ghoul::Dictionary message = wwtmessage::moveCamera( - skybrowser::cartesianToSpherical(cartesian), - _verticalFov, - skybrowser::cameraRoll() - ); - sendMessageToWwt(message); - } - - // Sleep so we don't bombard WWT with too many messages - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } - }); - - } - - glm::vec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { - glm::vec2 resizePosition = glm::vec2{ 0 }; - // Make sure coordinate is on browser - if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; - - // TO DO: turn this into a vector and use prettier vector arithmetic - float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; - float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; - - const bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; - const bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; - const bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; - const bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; - - resizePosition.x = isOnRight ? 1.f : isOnLeft ? -1.f : 0.f; - resizePosition.y = isOnTop ? 1.f : isOnBottom ? -1.f : 0.f; - - return resizePosition; - } - // Scales the ScreenSpaceBrowser to a new ratio - void ScreenSpaceSkyBrowser::setScale(glm::vec2 scalingFactor) { - - // Scale on the y axis, this is to ensure that _scale = 1 is - // equal to the height of the window - setScale(abs(scalingFactor.y)); - // Resize the dimensions of the texture on the x axis - glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; - _texture->setDimensions(glm::ivec3(newSize, 1)); - _objectSize = _texture->dimensions(); - } - - glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { - // To ensure the plane has the right ratio - // The _scale tells us how much of the windows height the - // browser covers: e.g. a browser that covers 0.25 of the - // height of the window will have scale = 0.25 - - float textureRatio = static_cast(_texture->dimensions().x) / - static_cast(_texture->dimensions().y); - - glm::mat4 scale = glm::scale( - glm::mat4(1.f), - glm::vec3(textureRatio * _scale, _scale, 1.f) - ); - return scale; - } - - void ScreenSpaceSkyBrowser::saveResizeStartSize() { - _originalDimensions = _dimensions.value(); - _originalScale = _scale.value(); - } - - // Updates the browser size to match the size of the texture - void ScreenSpaceSkyBrowser::updateBrowserSize() { - _dimensions = _texture->dimensions(); - } - void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { - _scale = _originalScale * scalingFactor; - } - - properties::FloatProperty& ScreenSpaceSkyBrowser::getOpacity() { - return _opacity; - } - - const std::deque& ScreenSpaceSkyBrowser::getSelectedImages() { - return _selectedImages; - } - - void ScreenSpaceSkyBrowser::addSelectedImage(const std::string& url, int i) { - // Ensure there are no duplicates - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it == std::end(_selectedImages)) { - // Push newly selected image to front - _selectedImages.push_front(i); - // Index of image is used as layer ID as it is unique in the image data set - sendMessageToWwt(wwtmessage::addImage(std::to_string(i), url)); - sendMessageToWwt(wwtmessage::setImageOpacity(std::to_string(i), 1.0)); - } - } - - void ScreenSpaceSkyBrowser::removeSelectedImage(int i) { - // Remove from selected list - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - - if (it != std::end(_selectedImages)) { - _selectedImages.erase(it); - sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); - } - } - - void ScreenSpaceSkyBrowser::setImageOrder(int i, int order) { - - // Find the selected image - auto selected = std::find( - std::begin(_selectedImages), - std::end(_selectedImages), - i - ); - - // Find the target for the swap - auto target = std::begin(_selectedImages) + order; - - // Make sure the selected and the target placement was found in the list - const bool foundSelected = selected != std::end(_selectedImages); - const bool foundTarget = target != std::end(_selectedImages); - - if (foundSelected && foundTarget) { - // Swap the two images - std::iter_swap(selected, target); - } - - // The images in the selected list are displayed in the reverse order from how the - // WorldWide Telescope application sees them - int reverseOrder = _selectedImages.size() - order - 1; - ghoul::Dictionary message = wwtmessage::setLayerOrder( - std::to_string(i), - reverseOrder - ); - sendMessageToWwt(message); - } -} From d5cdf4b3f82c0de47c987d0eedadfc083df0d3d7 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 17 Nov 2021 11:15:21 -0500 Subject: [PATCH 146/251] Finish change of structure of screenspaceskybrowser --- modules/skybrowser/CMakeLists.txt | 16 +- modules/skybrowser/include/pair.h | 1 + .../include/screenspaceskybrowser2.h | 89 ----- modules/skybrowser/include/wwtcommunicator.h | 12 +- modules/skybrowser/skybrowsermodule.cpp | 18 +- modules/skybrowser/skybrowsermodule.h | 5 +- modules/skybrowser/src/browser.cpp | 1 + modules/skybrowser/src/pair.cpp | 16 +- .../skybrowser/src/screenspaceskybrowser2.cpp | 335 ------------------ modules/skybrowser/src/wwtcommunicator.cpp | 12 +- 10 files changed, 46 insertions(+), 459 deletions(-) delete mode 100644 modules/skybrowser/include/screenspaceskybrowser2.h delete mode 100644 modules/skybrowser/src/screenspaceskybrowser2.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 7c45c9431d..3c76020dc4 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -27,13 +27,15 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES skybrowsermodule.h - include/screenspaceskybrowser.h include/screenspaceskytarget.h include/wwtdatahandler.h include/utility.h include/renderableskybrowser.h - include/pair.h - tinyxml2/tinyxml2.h + include/pair.h + include/wwtcommunicator.h + include/browser.h + include/screenspaceskybrowser.h + ext/tinyxml2/tinyxml2.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -42,13 +44,15 @@ set(SOURCE_FILES skybrowsermodule.cpp skybrowsermodule_lua.inl - src/screenspaceskybrowser.cpp src/screenspaceskytarget.cpp src/wwtdatahandler.cpp src/utility.cpp src/renderableskybrowser.cpp - src/pair.cpp - tinyxml2/tinyxml2.cpp + src/pair.cpp + src/wwtcommunicator.cpp + src/browser.cpp + src/screenspaceskybrowser.cpp + ext/tinyxml2/tinyxml2.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 983dacf312..beab32bf30 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -74,6 +74,7 @@ public: void loadImages(std::string collection); void setImageOpacity(const int i, float opacity); void sendIdToBrowser(); + void updateBrowserSize(); ScreenSpaceSkyTarget* getTarget(); ScreenSpaceSkyBrowser* getBrowser(); diff --git a/modules/skybrowser/include/screenspaceskybrowser2.h b/modules/skybrowser/include/screenspaceskybrowser2.h deleted file mode 100644 index 4d88b2ba2c..0000000000 --- a/modules/skybrowser/include/screenspaceskybrowser2.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ -#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ - -#include -#include -#include -#include -#include -#include -#include - -namespace openspace { - class ScreenSpaceSkyTarget; - - class ScreenSpaceSkyBrowser2 : public ScreenSpaceRenderable, public WwtCommunicator - { - public: - // Constructor and destructor - ScreenSpaceSkyBrowser2(const ghoul::Dictionary& dictionary); - virtual ~ScreenSpaceSkyBrowser2(); - - // Inherited functions - bool initializeGL() override; - bool deinitializeGL() override; - glm::mat4 scaleMatrix() override; - void render() override; - void update() override; - - // Target - browser connection - bool connectToSkyTarget(); - bool isAnimated(); - void startFovAnimation(float fov); - void incrementallyAnimateToFov(float deltaTime); - glm::dvec2 fineTuneVector(glm::dvec2 drag); - - // Getters returning references - ScreenSpaceSkyTarget* getSkyTarget(); - properties::FloatProperty& getOpacity(); - - // Setters - void setVerticalFovWithScroll(float scroll); - void setScale(glm::vec2 scalingFactor); - void setScale(float scalingFactor); - - // Communication with WorldWide Telescope - void startSyncingWithWwt(); - - - // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in - // image if the mouse is on a side of the browser - // __1__ - // y| -1 |_____|1 - // |__x -1 - glm::ivec2 isOnResizeArea(glm::vec2 screenSpaceCoord); - - private: - void syncWwtView(); - void bindTexture() override; - - // Resize functions - void saveResizeStartSize(); - void updateBrowserSize(); - - // Properties - properties::StringProperty _skyTargetId; - - // Flags - bool _isSyncedWithWwt{ false }; - bool _isFovAnimated{ false }; - float _endVfov{ 0.f }; - float _fovDiff{ 0.01f }; - - // Resizing of browser - glm::vec2 _originalDimensions; - float _originalScale; - float _resizeAreaPercentage{ 0.1f }; - - // Target & images - ScreenSpaceSkyTarget* _skyTarget{ nullptr }; - std::thread _wwtMessages; - - // Time variables - // For capping the calls to change the zoom from scrolling - constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; - std::chrono::system_clock::time_point _lastUpdateTime; - }; -} - -#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index cc6672f64d..b95edc6046 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -44,14 +44,12 @@ public: WwtCommunicator(WwtCommunicator const&) = default; virtual ~WwtCommunicator(); - // Web page communication - - void setIdInBrowser(const std::string& id); - // WorldWide Telescope communication void displayImage(const std::string& url, const int i); void removeSelectedImage(const int i); - void setImageLayerOrder(int i, int order); + void setImageOrder(int i, int order); + void loadImageCollection(const std::string& collection); + void setImageOpacity(const int i, float opacity); // Getters const std::deque& getSelectedImages(); @@ -59,7 +57,6 @@ public: float verticalFov() const; glm::dvec2 fieldsOfView(); bool hasLoadedImages() const; - // Setters void setHasLoadedImages(bool isLoaded); @@ -72,6 +69,9 @@ public: protected: void sendMessageToWwt(const ghoul::Dictionary& msg); + // Web page communication + void setIdInBrowser(const std::string& id); + properties::FloatProperty _verticalFov; properties::IVec3Property _borderColor; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 510d768281..6bb043aff6 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -255,7 +255,7 @@ SkyBrowserModule::SkyBrowserModule() if (_mouseOnPair && action == MouseAction::Press) { // Get the currently selected browser - setSelectedBrowser(_mouseOnPair->getBrowser()); + setSelectedBrowser(_mouseOnPair->getBrowser()->identifier()); if (button == MouseButton::Left) { _isCameraRotating = false; @@ -315,7 +315,7 @@ SkyBrowserModule::SkyBrowserModule() } if (_isResizing) { _isResizing = false; - _mouseOnPair->getBrowser()->updateBrowserSize(); + _mouseOnPair->updateBrowserSize(); return true; } } @@ -447,11 +447,13 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { // register ScreenSpaceBrowser auto fScreenSpaceRenderable = FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); - fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); // register ScreenSpaceTarget fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); + // register ScreenSpaceTarget + fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); + // Register Renderable Skybrowser auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "Renderable factory was not created"); @@ -716,7 +718,7 @@ std::vector& SkyBrowserModule::getPairs() return _targetsBrowsers; } -Pair* SkyBrowserModule::getPair(std::string id) +Pair* SkyBrowserModule::getPair(const std::string& id) { auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&](Pair& pair) { @@ -855,14 +857,8 @@ void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) } } -void SkyBrowserModule::setSelectedBrowser(ScreenSpaceSkyBrowser* browser) { - if (browser) { - _selectedBrowser = browser->identifier(); - } -} - void SkyBrowserModule::setSelectedBrowser(const std::string& id) { - if (getPair(id) || _browser3dNode->identifier() == id) { + if (getPair(id) || (_browser3dNode && _browser3dNode->identifier() == id)) { _selectedBrowser = id; } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 21f1733a73..991bd036b3 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -29,7 +29,6 @@ #include #include #include - //#include #include #include #include @@ -39,7 +38,6 @@ namespace openspace { -class ScreenSpaceSkyBrowser; class RenderableSkyBrowser; enum class Transparency { @@ -59,7 +57,7 @@ public: // Getters std::vector& getPairs(); - Pair* getPair(std::string id); + Pair* getPair(const std::string& id); SceneGraphNode* get3dBrowserNode(); RenderableSkyBrowser* get3dBrowser(); RenderableSkyBrowser* get3dBrowser(const std::string& id); @@ -68,7 +66,6 @@ public: // Setters void set3dBrowser(const std::string& id); - void setSelectedBrowser(ScreenSpaceSkyBrowser* ptr); void setSelectedBrowser(const std::string& id); void selectImage2dBrowser(int i); void selectImage3dBrowser(int i); diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index 7dc2347dbd..df9af7a94b 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -147,6 +147,7 @@ namespace openspace { } void Browser::update() { + if (_isUrlDirty) { _browserInstance->loadUrl(_url); _isUrlDirty = false; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 409ec3a978..4dfd73c33d 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -167,7 +167,7 @@ namespace openspace { void Pair::selectImage(const ImageData& image, int i) { // Load image into browser - _browser->addSelectedImage(image.imageUrl, i); + _browser->displayImage(image.imageUrl, i); // If the image has coordinates, move the target if (image.hasCelestialCoords) { @@ -185,21 +185,23 @@ namespace openspace { void Pair::loadImages(std::string collection) { - _browser->sendMessageToWwt(wwtmessage::loadCollection(collection)); - _browser->setHasLoadedImages(true); + _browser->loadImageCollection(collection); } void Pair::setImageOpacity(const int i, float opacity) { - ghoul::Dictionary msg = wwtmessage::setImageOpacity(std::to_string(i), opacity); - _browser->sendMessageToWwt(msg); + _browser->setImageOpacity(i, opacity); } void Pair::sendIdToBrowser() { - _browser->sendIdToBrowser(); + _browser->setIdInBrowser(); } -#pragma optimize("", off) + + void Pair::updateBrowserSize() { + _browser->updateBrowserSize(); + } + void Pair::incrementallyAnimateToCoordinate(double deltaTime) { // Animate the target before the field of view starts to animate diff --git a/modules/skybrowser/src/screenspaceskybrowser2.cpp b/modules/skybrowser/src/screenspaceskybrowser2.cpp deleted file mode 100644 index 748461d6a6..0000000000 --- a/modules/skybrowser/src/screenspaceskybrowser2.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include // formatJson -#include -#include - -namespace { - constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser2"; - - constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo = - { - "BrowserDimensions", - "Browser Dimensions", - "The pixel dimensions of the sky browser." - }; - constexpr const openspace::properties::Property::PropertyInfo TargetIdInfo = - { - "TargetId", - "Target Id", - "The identifier of the target. It is used to synchronize the sky browser and the" - "sky target." - }; - constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = - { - "BorderColor", - "Border Color", - "The color of the border of the sky browser." - }; - constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = - { - "VerticalFieldOfView", - "Vertical Field Of View", - "The vertical field of view in degrees." - }; - - struct [[codegen::Dictionary(ScreenSpaceSkyBrowser2)]] Parameters { - - // [[codegen::verbatim(BrowserDimensionInfo.description)]] - std::optional browserDimensions; - - // [[codegen::verbatim(VerticalFovInfo.description)]] - std::optional verticalFov; - - // [[codegen::verbatim(TargetIdInfo.description)]] - std::optional targetId; - - // [[codegen::verbatim(BorderColorInfo.description)]] - std::optional borderColor; - }; - -#include "ScreenSpaceSkyBrowser2_codegen.cpp" -} // namespace - -namespace openspace { - - ScreenSpaceSkyBrowser2::ScreenSpaceSkyBrowser2(const ghoul::Dictionary& dictionary) - : ScreenSpaceRenderable(dictionary), - WwtCommunicator(dictionary) - , _skyTargetId(TargetIdInfo) - { - // Make the color property display a color picker in the GUI - _borderColor.setViewOption("Color", true); - - // Handle target dimension property - const Parameters p = codegen::bake(dictionary); - _verticalFov = p.verticalFov.value_or(_verticalFov); - _borderColor = p.borderColor.value_or(_borderColor); - _skyTargetId = p.targetId.value_or(_skyTargetId); - - addProperty(_dimensions); - addProperty(_verticalFov); - addProperty(_borderColor); - addProperty(_skyTargetId); - - _verticalFov.onChange([&]() { - if (_skyTarget) { - _skyTarget->setScale(_verticalFov); - } - }); - _borderColor.onChange([&]() { - setWebpageBorderColor(_borderColor.value()); - }); - _skyTargetId.onChange([&]() { - connectToSkyTarget(); - }); - - // Set a unique identifier - std::string identifier; - if (dictionary.hasValue(KeyIdentifier)) { - identifier = dictionary.value(KeyIdentifier); - } - else { - identifier = "ScreenSpaceSkyBrowser22"; - } - identifier = makeUniqueIdentifier(identifier); - setIdentifier(identifier); - - glm::vec2 screenPosition = _cartesianPosition.value(); - _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); - - // Always make sure that the target and browser are visible together - _enabled.onChange([&]() { - if (_skyTarget) { - _skyTarget->property("Enabled")->set(_enabled.value()); - } - }); - - // Ensure the color of the border is bright enough. - // Make sure the RGB color at least is 50% brightness - // By making each channel 50% bright in general - // 222 = sqrt(3*(0.5*256)^2) - while (glm::length(glm::vec3(_borderColor.value())) < 222.f) { - _borderColor = glm::vec3(rand() % 256, rand() % 256, rand() % 256); - } - } - - ScreenSpaceSkyBrowser2::~ScreenSpaceSkyBrowser2() { - // Set flag to false so the thread can exit - _isSyncedWithWwt = false; - if (_wwtMessages.joinable()) { - _wwtMessages.join(); - LINFO("Joined thread"); - } - } - - bool ScreenSpaceSkyBrowser2::initializeGL() { - - return Browser::initializeGL() && ScreenSpaceRenderable::initializeGL(); - } - - - void ScreenSpaceSkyBrowser2::startSyncingWithWwt() { - // If the camera is already synced, the browser is already syncing - if (!_isSyncedWithWwt) { - _isSyncedWithWwt = true; - // Set border color - setWebpageBorderColor(_borderColor.value()); - // Track target - syncWwtView(); - } - } - - glm::dvec2 ScreenSpaceSkyBrowser2::fineTuneVector(glm::dvec2 drag) { - // Fine tuning of target - glm::dvec2 wwtFov = fieldsOfView(); - glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); - - glm::dvec2 browserDim = screenSpaceDimensions(); - glm::dvec2 angleResult = wwtFov * (drag / browserDim); - glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; - - // Convert to screen space coordinate system - glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; - glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; - return result; - } - /* - void ScreenSpaceBrowser::setXCallback(std::function callback) { - _originalDimensions.onChange(std::move(callback)); - } - */ - bool ScreenSpaceSkyBrowser2::deinitializeGL() { - // Set flag to false so the thread can exit - _isSyncedWithWwt = false; - if (_wwtMessages.joinable()) { - _wwtMessages.join(); - LINFO("Joined thread"); - } - return Browser::deinitializeGL() && ScreenSpaceRenderable::deinitializeGL(); - } - - bool ScreenSpaceSkyBrowser2::connectToSkyTarget() { - _skyTarget = dynamic_cast( - global::renderEngine->screenSpaceRenderable(_skyTargetId.value())); - return _skyTarget; - } - - bool ScreenSpaceSkyBrowser2::isAnimated() - { - return _isFovAnimated; - } - - void ScreenSpaceSkyBrowser2::startFovAnimation(float fov) - { - _isFovAnimated = true; - _endVfov = fov; - } - - void ScreenSpaceSkyBrowser2::incrementallyAnimateToFov(float deltaTime) - { - // If distance too large, keep animating. Else, stop animation - float diff = verticalFov() - _endVfov; - const bool shouldAnimate = abs(diff) > _fovDiff; - - if (shouldAnimate) { - setVerticalFovWithScroll(diff); - } - else { - _isFovAnimated = false; - } - } - - void ScreenSpaceSkyBrowser2::render() { - Browser::render(); - - draw( - globalRotationMatrix() * - translationMatrix() * - localRotationMatrix() * - scaleMatrix() - ); - } - - void ScreenSpaceSkyBrowser2::update() { - Browser::update(); - ScreenSpaceRenderable::update(); - } - - ScreenSpaceSkyTarget* ScreenSpaceSkyBrowser2::getSkyTarget() { - return _skyTarget; - } - - void ScreenSpaceSkyBrowser2::setVerticalFovWithScroll(float scroll) { - // Cap how often the zoom is allowed to update - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; - - if (timeSinceLastUpdate > _timeUpdateInterval) { - // Make scroll more sensitive the smaller the FOV - float x = _verticalFov; - float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; - float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); - _lastUpdateTime = std::chrono::system_clock::now(); - } - } - - void ScreenSpaceSkyBrowser2::syncWwtView() { - - // Start a thread to enable user interaction while sending the calls to WWT - _wwtMessages = std::thread([&] { - while (_isSyncedWithWwt) { - if (_skyTarget) { - // Message WorldWide Telescope current view - glm::dvec3 cartesian = _skyTarget->directionEquatorial(); - - ghoul::Dictionary message = wwtmessage::moveCamera( - skybrowser::cartesianToSpherical(cartesian), - _verticalFov, - skybrowser::cameraRoll() - ); - sendMessageToWwt(message); - } - - // Sleep so we don't bombard WWT with too many messages - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } - }); - - } - - glm::ivec2 ScreenSpaceSkyBrowser2::isOnResizeArea(glm::vec2 coord) { - glm::ivec2 resizePosition = glm::ivec2{ 0 }; - // Make sure coordinate is on browser - if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; - - // TO DO: turn this into a vector and use prettier vector arithmetic - float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; - float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; - - const bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; - const bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; - const bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; - const bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; - - resizePosition.x = isOnRight ? 1 : isOnLeft ? -1 : 0; - resizePosition.y = isOnTop ? 1 : isOnBottom ? -1 : 0; - - return resizePosition; - } - // Scales the ScreenSpaceBrowser to a new ratio - void ScreenSpaceSkyBrowser2::setScale(glm::vec2 scalingFactor) { - - // Scale on the y axis, this is to ensure that _scale = 1 is - // equal to the height of the window - setScale(abs(scalingFactor.y)); - // Resize the dimensions of the texture on the x axis - glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; - _texture->setDimensions(glm::ivec3(newSize, 1)); - _objectSize = _texture->dimensions(); - } - - glm::mat4 ScreenSpaceSkyBrowser2::scaleMatrix() { - // To ensure the plane has the right ratio - // The _scale tells us how much of the windows height the - // browser covers: e.g. a browser that covers 0.25 of the - // height of the window will have scale = 0.25 - - float textureRatio = static_cast(_texture->dimensions().x) / - static_cast(_texture->dimensions().y); - - glm::mat4 scale = glm::scale( - glm::mat4(1.f), - glm::vec3(textureRatio * _scale, _scale, 1.f) - ); - return scale; - } - - void ScreenSpaceSkyBrowser2::saveResizeStartSize() { - _originalDimensions = _dimensions.value(); - _originalScale = _scale.value(); - } - - // Updates the browser size to match the size of the texture - void ScreenSpaceSkyBrowser2::updateBrowserSize() { - _dimensions = _texture->dimensions(); - } - - void ScreenSpaceSkyBrowser2::setScale(float scalingFactor) { - _scale = _originalScale * scalingFactor; - } - - properties::FloatProperty& ScreenSpaceSkyBrowser2::getOpacity() { - return _opacity; - } - - void ScreenSpaceSkyBrowser2::bindTexture() { - _texture->bind(); - } -} diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 0018a5ce18..602056f854 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -130,7 +130,7 @@ namespace openspace { return _hasLoadedImages; } - void WwtCommunicator::setImageLayerOrder(int i, int order) { + void WwtCommunicator::setImageOrder(int i, int order) { // Find in selected images list auto current = std::find( std::begin(_selectedImages), @@ -151,6 +151,16 @@ namespace openspace { sendMessageToWwt(message); } + void WwtCommunicator::loadImageCollection(const std::string& collection) { + sendMessageToWwt(wwtmessage::loadCollection(collection)); + _hasLoadedImages = true; + } + + void WwtCommunicator::setImageOpacity(const int i, float opacity) { + ghoul::Dictionary msg = wwtmessage::setImageOpacity(std::to_string(i), opacity); + sendMessageToWwt(msg); + } + void WwtCommunicator::setHasLoadedImages(bool isLoaded) { _hasLoadedImages = isLoaded; } From 27d68556ec3dd5408379f36743ee3faa2e3fb7ab Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 09:48:07 -0500 Subject: [PATCH 147/251] Update the structure of the renderable sky browser to inherit fronm renderable plane and wwtcommuicator --- data/assets/renderableBrowser.asset | 5 +- modules/skybrowser/CMakeLists.txt | 2 +- .../skybrowser/include/renderableskybrowser.h | 56 +---- modules/skybrowser/skybrowsermodule.cpp | 60 ++--- modules/skybrowser/skybrowsermodule.h | 4 +- .../skybrowser/src/renderableskybrowser.cpp | 216 ++---------------- 6 files changed, 65 insertions(+), 278 deletions(-) diff --git a/data/assets/renderableBrowser.asset b/data/assets/renderableBrowser.asset index 57ae2c63ad..c81c82af08 100644 --- a/data/assets/renderableBrowser.asset +++ b/data/assets/renderableBrowser.asset @@ -39,12 +39,11 @@ local browser = { asset.onInitialize(function () openspace.addSceneGraphNode(browser) - openspace.skybrowser.addToSkyBrowserModule(browserId) + openspace.skybrowser.add3dBrowserToSkyBrowserModule(browserId) end) asset.onDeinitialize(function () - openspace.removeScreenSpaceRenderable(browserId) - openspace.removeScreenSpaceRenderable(targetId) + openspace.removeSceneGraphNode(browserId) end) asset.export("browser", {browser}) diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 3c76020dc4..10d8708415 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -30,11 +30,11 @@ set(HEADER_FILES include/screenspaceskytarget.h include/wwtdatahandler.h include/utility.h - include/renderableskybrowser.h include/pair.h include/wwtcommunicator.h include/browser.h include/screenspaceskybrowser.h + include/renderableskybrowser.h ext/tinyxml2/tinyxml2.h ) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 942c130fb3..448326d61b 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -2,9 +2,7 @@ #define __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ #include -#include -#include -#include +#include #include #include #include @@ -35,72 +33,32 @@ namespace ghoul::opengl { class Texture; } namespace openspace::documentation { struct Documentation; } +#pragma optimize("", off) + namespace openspace { - class RenderableSkyBrowser : public RenderablePlane + class RenderableSkyBrowser : public RenderablePlane, public WwtCommunicator { public: static constexpr const char* KeyIdentifier = "Identifier"; RenderableSkyBrowser(const ghoul::Dictionary& dictionary); - virtual ~RenderableSkyBrowser() = default; + ~RenderableSkyBrowser(); // Inherited from RenderablePlane void initializeGL() override; void deinitializeGL() override; void update(const UpdateData& data) override; - // Web page communication - void executeJavascript(std::string script) const; - void setIdInBrowser(std::string id); - - // WorldWide Telescope communication - void displayImage(const ImageData& image, const int i); - void removeSelectedImage(const ImageData& image, const int i); - void sendMessageToWwt(const ghoul::Dictionary& msg); - void syncWwtView(); + // Set up initialization with wwt void stopSyncingWwtView(); + void setIdInBrowser(); // Place void placeAt3dPosition(const ImageData& image); - // Getters - float verticalFov() const; - std::deque& getSelectedImages(); - - // Setters - void setImageLayerOrder(int i, int order); - private: - // Properties - properties::Vec2Property _dimensions; - properties::StringProperty _url; - properties::TriggerProperty _reload; - class ScreenSpaceRenderHandler : public WebRenderHandler { - public: - void draw() override; - void render() override; - - void setTexture(GLuint t); - }; - - void bindTexture() override; - - // Browser variables - std::unique_ptr _browserInstance; - std::unique_ptr _texture; - CefRefPtr _renderHandler; - CefRefPtr _keyboardHandler; - - // Flags - bool _isUrlDirty = false; - bool _isDimensionsDirty = false; - bool _isSyncedWithWwt; - - float _verticalFov; - std::thread _threadWwtMessages; - std::deque _selectedImages; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 6bb043aff6..e3734c7f7a 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -470,15 +470,15 @@ void SkyBrowserModule::setSelectedObject() // Find and save what mouse is currently hovering on auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - [&] (Pair &pair) { - bool onBrowser = pair.getBrowser()->coordIsInsideCornersScreenSpace( + [&] (const std::unique_ptr &pair) { + bool onBrowser = pair->getBrowser()->coordIsInsideCornersScreenSpace( _mousePosition ); - bool onTarget = pair.getTarget()->coordIsInsideCornersScreenSpace( + bool onTarget = pair->getTarget()->coordIsInsideCornersScreenSpace( _mousePosition ); if (onBrowser) { - _selectedBrowser = pair.getBrowser()->identifier(); + _selectedBrowser = pair->getBrowser()->identifier(); } _isBrowser = onBrowser; @@ -489,7 +489,7 @@ void SkyBrowserModule::setSelectedObject() _mouseOnPair = nullptr; } else { - _mouseOnPair = &(*it); + _mouseOnPair = it->get(); } // Selection has changed @@ -518,8 +518,7 @@ void SkyBrowserModule::addTargetBrowserPair(std::string targetId, std::string br // Assert pair to have both target and browser if (browser && target) { - Pair newPair(browser, target); - _targetsBrowsers.push_back(newPair); + _targetsBrowsers.push_back(std::make_unique(browser, target)); } } @@ -584,9 +583,11 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { if (!found) { return; } - auto it = std::remove(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - *found); - + auto it = std::remove_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + [&](const std::unique_ptr& pair) { + return *found == *(pair.get()); + }); + std::string targetId = found->getTarget()->identifier(); // Remove from engine openspace::global::scriptEngine->queueScript( @@ -644,7 +645,7 @@ void SkyBrowserModule::selectImage3dBrowser(int i) _browser3dNode->renderable()); if (renderable) { const ImageData& image = _dataHandler->getImage(i); - renderable->displayImage(image, i); + renderable->displayImage(image.imageUrl, i); } } @@ -698,13 +699,11 @@ void SkyBrowserModule::add2dSelectedImagesTo3d(const std::string& pairId) if (pair && get3dBrowser()) { - // Empty 3D browser selection - get3dBrowser()->getSelectedImages().clear(); // Copy 2D selection of images to 3D browser const std::deque images = pair->getSelectedImages(); std::for_each(std::begin(images), std::end(images), [&](const int i) { const ImageData& image = _dataHandler->getImage(i); - get3dBrowser()->displayImage(image, i); + get3dBrowser()->displayImage(image.imageUrl, i); }); } } @@ -713,7 +712,7 @@ const std::unique_ptr& SkyBrowserModule::getWWTDataHandler() { return _dataHandler; } -std::vector& SkyBrowserModule::getPairs() +std::vector>& SkyBrowserModule::getPairs() { return _targetsBrowsers; } @@ -721,12 +720,17 @@ std::vector& SkyBrowserModule::getPairs() Pair* SkyBrowserModule::getPair(const std::string& id) { auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - [&](Pair& pair) { - bool foundBrowser = pair.browserId() == id; - bool foundTarget = pair.targetId() == id; + [&](const std::unique_ptr& pair) { + bool foundBrowser = pair->browserId() == id; + bool foundTarget = pair->targetId() == id; return foundBrowser || foundTarget; }); - return &(*it); + if (it == std::end(_targetsBrowsers)) { + return nullptr; + } + else { + return it->get(); + } } SceneGraphNode* SkyBrowserModule::get3dBrowserNode() { @@ -776,7 +780,7 @@ void SkyBrowserModule::place3dBrowser(const ImageData& image, const int i) { // If the image has a 3D position, add it to the scene graph if (image.has3dCoords && get3dBrowser()) { - get3dBrowser()->displayImage(image, i); + get3dBrowser()->displayImage(image.imageUrl, i); get3dBrowser()->placeAt3dPosition(image); } else { @@ -829,14 +833,14 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float }(goal); bool isAllFinished{ false }; - for (Pair& pair : _targetsBrowsers) { - if (pair.isEnabled()) { - bool isPairFinished = pair.hasFinishedFading(transparency); + for (std::unique_ptr& pair : _targetsBrowsers) { + if (pair->isEnabled()) { + bool isPairFinished = pair->hasFinishedFading(transparency); if (!isPairFinished) { - pair.incrementallyFade(transparency, _fadingTime, deltaTime); + pair->incrementallyFade(transparency, _fadingTime, deltaTime); } else if (isPairFinished && goal == Transparency::Transparent) { - pair.disable(); + pair->disable(); } isAllFinished &= isPairFinished; } @@ -850,9 +854,9 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) { - for (Pair& pair : _targetsBrowsers) { - if (pair.isEnabled()) { - pair.incrementallyAnimateToCoordinate(deltaTime); + for (std::unique_ptr& pair : _targetsBrowsers) { + if (pair->isEnabled()) { + pair->incrementallyAnimateToCoordinate(deltaTime); } } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 991bd036b3..500ee1efb5 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -56,7 +56,7 @@ public: virtual ~SkyBrowserModule(); // Getters - std::vector& getPairs(); + std::vector>& getPairs(); Pair* getPair(const std::string& id); SceneGraphNode* get3dBrowserNode(); RenderableSkyBrowser* get3dBrowser(); @@ -108,7 +108,7 @@ private: void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate // The browsers and targets - std::vector _targetsBrowsers; + std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; Pair* _selectedPair{ nullptr }; bool _isBrowser{ false }; diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 19f036a59a..71e6fc21aa 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include #include #include #include @@ -49,27 +47,11 @@ namespace { namespace openspace { - void RenderableSkyBrowser::ScreenSpaceRenderHandler::draw() {} - - void RenderableSkyBrowser::ScreenSpaceRenderHandler::render() {} - - void RenderableSkyBrowser::ScreenSpaceRenderHandler::setTexture(GLuint t) { - _texture = t; - } - RenderableSkyBrowser::RenderableSkyBrowser(const ghoul::Dictionary& dictionary) - : RenderablePlane(dictionary) - , _url(UrlInfo) - , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) - , _reload(ReloadInfo) - , _verticalFov(70.f) - , _isSyncedWithWwt(false) + : RenderablePlane(dictionary), + WwtCommunicator(dictionary) { - // Handle target dimension property - const Parameters p = codegen::bake(dictionary); - _url = p.url.value_or(_url); - std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -79,179 +61,51 @@ namespace openspace { } setIdentifier(identifier); + const Parameters p = codegen::bake(dictionary); + _url = p.url.value_or(_url); + // Ensure the texture is a square for now // Maybe change later glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); float maxDimension = std::max(windowDimensions.x, windowDimensions.y); _dimensions = { maxDimension, maxDimension }; - // Create browser and render handler - _renderHandler = new ScreenSpaceRenderHandler(); - _keyboardHandler = new WebKeyboardHandler(); - _browserInstance = std::make_unique( - _renderHandler, - _keyboardHandler - ); - - _url.onChange([this]() { _isUrlDirty = true; }); - _dimensions.onChange([this]() { _isDimensionsDirty = true; }); - _reload.onChange([this]() { _browserInstance->reloadBrowser(); }); - addProperty(_url); addProperty(_dimensions); addProperty(_reload); + addProperty(_verticalFov); + addProperty(_borderColor); + addProperty(_equatorialAim); + } + + RenderableSkyBrowser::~RenderableSkyBrowser() { - WebBrowserModule* webBrowser = global::moduleEngine->module(); - if (webBrowser) { - webBrowser->addBrowser(_browserInstance.get()); - } } void RenderableSkyBrowser::initializeGL() { + Browser::initializeGL(); RenderablePlane::initializeGL(); - _texture = std::make_unique( - glm::uvec3(_dimensions.value(), 1.0f) - ); - _texture->setDimensions(glm::ivec3(_dimensions.value(), 1)); - - _renderHandler->setTexture(*_texture); - // The browser gets by default the size of the OpenSpace window, so it needs to - // be resized - _browserInstance->initialize(); - _browserInstance->loadUrl(_url); - _browserInstance->reshape(_dimensions.value()); } void RenderableSkyBrowser::deinitializeGL() { + RenderablePlane::deinitializeGL(); - _renderHandler->setTexture(0); - _texture = nullptr; - - std::string urlString; - _url.getStringValue(urlString); - LDEBUG(fmt::format("Deinitializing RenderableSkyBrowser: {}", urlString)); - - _browserInstance->close(true); - - WebBrowserModule* webBrowser = global::moduleEngine->module(); - if (webBrowser) { - webBrowser->removeBrowser(_browserInstance.get()); - _browserInstance.reset(); - } - else { - LWARNING("Could not find WebBrowserModule"); - } - - RenderablePlane::deinitializeGL(); + Browser::deinitializeGL(); } void RenderableSkyBrowser::update(const UpdateData& data) { + Browser::update(); RenderablePlane::update(data); - _renderHandler->updateTexture(); - - if (_isUrlDirty) { - _browserInstance->loadUrl(_url); - _isUrlDirty = false; - } - - if (_isDimensionsDirty) { - _browserInstance->reshape(_dimensions.value()); - _isDimensionsDirty = false; - } } - void RenderableSkyBrowser::bindTexture() { - if (_texture) { - _texture->bind(); - } - else { - glBindTexture(GL_TEXTURE_2D, 0); - } + void RenderableSkyBrowser::stopSyncingWwtView() + { + } - void RenderableSkyBrowser::executeJavascript(std::string script) const { - //LINFOC(_loggerCat, "Executing javascript " + script); - const bool isBrowserReady = _browserInstance && _browserInstance->getBrowser(); - const bool isMainFrameReady = _browserInstance->getBrowser()->GetMainFrame(); - if (isBrowserReady && isMainFrameReady) { - CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - frame->ExecuteJavaScript(script, frame->GetURL(), 0); - } - } - - void RenderableSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) { - std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; - executeJavascript(script); - } - - void RenderableSkyBrowser::displayImage(const ImageData& image, const int i) { - ghoul::Dictionary msg = wwtmessage::moveCamera( - image.equatorialSpherical, - image.fov, - 0.0 - ); - sendMessageToWwt(msg); - _verticalFov = image.fov; - // Add to selected images if there are no duplicates - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it == std::end(_selectedImages)) { - // Push newly selected image to front - _selectedImages.push_front(i); - // Create image layer and center WWT app on the image - sendMessageToWwt(wwtmessage::addImage(std::to_string(i), image.imageUrl)); - LINFO("Image has been loaded to " + identifier()); - } - } - - void RenderableSkyBrowser::removeSelectedImage(const ImageData& image, const int i) { - // Remove from selected list - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it != std::end(_selectedImages)) { - _selectedImages.erase(it); - sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); - } - } - - void RenderableSkyBrowser::setIdInBrowser(std::string id) { - // Send ID to it's browser - executeJavascript("setId('" + id + "')"); - } - - float RenderableSkyBrowser::verticalFov() const { - return _verticalFov; - } - - void RenderableSkyBrowser::syncWwtView() { - // If the camera is already synced, the browser is already initialized - if (!_isSyncedWithWwt) { - _isSyncedWithWwt = true; - // Start a thread to enable user interaction while sending the calls to WWT - _threadWwtMessages = std::thread([&] { - while (_isSyncedWithWwt) { - - glm::dvec2 aim{ 0.0 }; - // Send a message just to establish contact - ghoul::Dictionary msg = wwtmessage::moveCamera( - aim, - _verticalFov, - 0.0 - ); - sendMessageToWwt(msg); - - // Sleep so we don't bombard WWT with too many messages - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } - }); - } - - } - - void RenderableSkyBrowser::stopSyncingWwtView() { - _isSyncedWithWwt = false; - - if (_threadWwtMessages.joinable()) { - _threadWwtMessages.join(); - } + void RenderableSkyBrowser::setIdInBrowser() + { + WwtCommunicator::setIdInBrowser(identifier()); } void RenderableSkyBrowser::placeAt3dPosition(const ImageData& image) @@ -301,32 +155,4 @@ namespace openspace { scripting::ScriptEngine::RemoteScripting::Yes ); } - - std::deque& RenderableSkyBrowser::getSelectedImages() { - return _selectedImages; - } - - void RenderableSkyBrowser::setImageLayerOrder(int i, int order) { - // Remove from selected list - auto current = std::find( - std::begin(_selectedImages), - std::end(_selectedImages), - i - ); - auto target = std::begin(_selectedImages) + order; - - // Make sure the image was found in the list - if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { - // Swap the two images - std::iter_swap(current, target); - } - - int reverseOrder = _selectedImages.size() - order - 1; - ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), - reverseOrder); - sendMessageToWwt(message); - } - - - } // namespace From 1705fe41fe36ba2b31a771a69d5a9794982c6724 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 09:48:33 -0500 Subject: [PATCH 148/251] Change engine to also call deinitializeGL for all screenspacerenderables --- src/rendering/renderengine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index ff37ec8c07..02c3344953 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -1210,6 +1210,7 @@ void RenderEngine::removeScreenSpaceRenderable(ScreenSpaceRenderable* s) { ); if (it != global::screenSpaceRenderables->end()) { + s->deinitializeGL(); s->deinitialize(); global::screenSpaceRootPropertyOwner->removePropertySubOwner(s); From 1542209c42b1d17f2339b199411856f06a20d7ff Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 15:48:16 -0500 Subject: [PATCH 149/251] Add setter for enabled property for screenspacerenderable --- include/openspace/rendering/screenspacerenderable.h | 1 + src/rendering/screenspacerenderable.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index a27de28b34..ed6fb3c220 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -69,6 +69,7 @@ public: virtual void update(); virtual bool isReady() const; bool isEnabled() const; + void setEnabled(bool isEnabled); float depth(); // Added by skybrowser team diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index a91dff3d6c..d0502fc4ea 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -447,7 +447,10 @@ void ScreenSpaceRenderable::update() {} bool ScreenSpaceRenderable::isEnabled() const { return _enabled; } - +void ScreenSpaceRenderable::setEnabled(bool isEnabled) +{ + _enabled = isEnabled; +} float ScreenSpaceRenderable::depth() { return _useRadiusAzimuthElevation ? _raePosition.value().x : From 54ed28ce66873758f3b1e647c0b580300d8f4c15 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 15:49:02 -0500 Subject: [PATCH 150/251] Update assethelper to new version --- data/assets/util/asset_helper.asset | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/assets/util/asset_helper.asset b/data/assets/util/asset_helper.asset index 840f845b13..7da0050068 100644 --- a/data/assets/util/asset_helper.asset +++ b/data/assets/util/asset_helper.asset @@ -14,7 +14,7 @@ local registerSpiceKernels = function (spiceAsset, kernels) spiceAsset.onDeinitialize(function () for i = #kernels, 1, -1 do local kernel = kernels[i] - openspace.spice.unloadKernel(kernel) + openspace.spice.unloadKernel(kernel) end end) end @@ -59,7 +59,7 @@ local registerScreenSpaceRenderables = function (sceneAsset, renderables, overri end) sceneAsset.onDeinitialize(function () for i = #renderables, 1, -1 do - renderable = renderables[i] + local renderable = renderables[i] openspace.removeScreenSpaceRenderable(renderable.Identifier) end end) @@ -168,7 +168,7 @@ local createModelPart = function (parent, sunLightSourceNode, models, geometry, GeometryFile = models .. "/" .. geometry .. ".obj", LightSources = lightSources, PerformShading = performShading, - DisableFaceCulling = true + DisableFaceCulling = true }, GUI = { Hidden = true From 68c0635a9ae3ac99846b3fa144d680bdd3949054 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 15:49:20 -0500 Subject: [PATCH 151/251] Restructure browser and target to not have pointers to each other --- modules/skybrowser/include/browser.h | 24 +- modules/skybrowser/include/pair.h | 29 +- .../skybrowser/include/screenspaceskytarget.h | 31 +- modules/skybrowser/include/utility.h | 39 +- modules/skybrowser/include/wwtcommunicator.h | 35 +- modules/skybrowser/skybrowsermodule.cpp | 19 +- modules/skybrowser/skybrowsermodule_lua.inl | 816 +++++++++--------- modules/skybrowser/src/browser.cpp | 51 +- modules/skybrowser/src/pair.cpp | 107 ++- .../skybrowser/src/screenspaceskytarget.cpp | 127 +-- modules/skybrowser/src/utility.cpp | 123 +-- modules/skybrowser/src/wwtcommunicator.cpp | 202 ++++- 12 files changed, 844 insertions(+), 759 deletions(-) diff --git a/modules/skybrowser/include/browser.h b/modules/skybrowser/include/browser.h index a50fda6f2f..6a5f4639d7 100644 --- a/modules/skybrowser/include/browser.h +++ b/modules/skybrowser/include/browser.h @@ -55,13 +55,12 @@ namespace ghoul::opengl { class Texture; } namespace openspace { - class BrowserInstance; - class RenderHandler; - class WebKeyboardHandler; +class BrowserInstance; +class RenderHandler; +class WebKeyboardHandler; class Browser { public: - Browser(const ghoul::Dictionary& dictionary); Browser(Browser const&) = default; ~Browser(); @@ -73,17 +72,23 @@ public: void update(); bool isReady() const; - glm::vec2 browserPixelDimensions() const; + void updateBrowserSize(); + // Getters + glm::vec2 browserPixelDimensions() const; + float browserRatio() const; + void setCallbackDimensions(const std::function& function); protected: properties::Vec2Property _dimensions; properties::StringProperty _url; properties::TriggerProperty _reload; - std::unique_ptr _browserInstance; + std::unique_ptr _texture; + + void executeJavascript(const std::string& script) const; - +private: class RenderHandler : public WebRenderHandler { public: void draw() override; @@ -92,14 +97,13 @@ protected: void setTexture(GLuint t); }; -private: - void bindTexture(); - + std::unique_ptr _browserInstance; CefRefPtr _renderHandler; CefRefPtr _keyboardHandler; bool _isUrlDirty = false; bool _isDimensionsDirty = false; + bool _shouldReload = false; }; } // namespace openspace diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index beab32bf30..1fa8777769 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -25,28 +25,30 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ #define __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ -#include -//#include -#include #include #include namespace openspace { class ScreenSpaceSkyBrowser; +class ScreenSpaceSkyTarget; +class ImageData; class Pair { public: constexpr static const float AcceptableDiff = 0.01f; + constexpr static const double epsilon = std::numeric_limits::epsilon(); Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); + Pair(Pair const&) = default; + // user-defined copy assignment (copy-and-swap idiom) + Pair& operator=(Pair other); + void lock(); void unlock(); void setImageOrder(int i, int order); - void connectPair(); - void synchronizeWithWwt(); void removeHighlight(glm::ivec3 color); void highlight(glm::ivec3 color); void enable(); @@ -61,26 +63,31 @@ public: bool isEnabled(); bool isLocked(); + void initialize(); glm::ivec3 borderColor(); glm::dvec3 targetDirectionEquatorial(); glm::dvec3 targetDirectionGalactic(); std::string browserGuiName(); - std::string browserId(); - std::string targetId(); + const std::string& browserId() const; + const std::string& targetId() const; float verticalFov(); const std::deque& getSelectedImages(); void selectImage(const ImageData& image, const int i); void removeSelectedImage(const int i); - void loadImages(std::string collection); + void loadImageCollection(std::string collection); void setImageOpacity(const int i, float opacity); void sendIdToBrowser(); void updateBrowserSize(); + void setIsSyncedWithWwt(bool isSynced); + ScreenSpaceSkyTarget* getTarget(); ScreenSpaceSkyBrowser* getBrowser(); - - friend bool operator==(const Pair& lhs, const Pair& rhs); - friend bool operator!=(const Pair& lhs, const Pair& rhs); + + friend bool operator==(const Pair& lhs, + const Pair& rhs); + friend bool operator!=(const Pair& lhs, + const Pair& rhs); private: diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index ee4d9df3c5..4fded24047 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -25,37 +25,35 @@ namespace openspace { bool deinitializeGL() override; bool isReady() const override; void render() override; + void update() override; glm::mat4 scaleMatrix() override; void bindTexture() override; // Empty function but has to be defined void createShaders(); - // Sky browser functionality - bool connectoToSkyBrowser(); - void matchAppearanceToSkyBrowser(); - - // Getters - ScreenSpaceSkyBrowser* getSkyBrowser(); glm::ivec3 borderColor() const; float opacity() const; // Setters - void setScale(float verticalFov); + void setScaleFromVfov(float verticalFov); void setDimensions(glm::vec2 dimensions); void setColor(glm::ivec3 color); void setOpacity(float opacity); + void setLock(bool isLocked); + + // Set callbacks + void setCallbackEnabled(std::function function); + void setCallbackPosition(std::function function); // Target directions glm::dvec3 directionGalactic() const; glm::dvec3 directionEquatorial() const; // Locking functionality - void lock(); - void unlock(); - bool isLocked(); + bool isLocked() const; // Animation bool isAnimated(); - void startAnimation(glm::dvec3 end, bool shouldLockAfter); + void startAnimation(glm::dvec3 end, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(float deltaTime); // Display void highlight(glm::ivec3 addition); @@ -63,7 +61,6 @@ namespace openspace { private: // Properties - properties::StringProperty _skyBrowserId; properties::FloatProperty _showCrosshairThreshold; properties::FloatProperty _showRectangleThreshold; properties::DoubleProperty _stopAnimationThreshold; @@ -87,15 +84,15 @@ namespace openspace { GLuint _vertexBuffer = 0; // Sky browser - ScreenSpaceSkyBrowser* _skyBrowser; glm::ivec3 _color; + float _verticalFov{ 0.f }; // Lock target to a coordinate on the sky - glm::dvec3 _lockedCoordinates; // Spherical celestial coordinates - std::thread _lockTarget; + glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates - glm::dvec3 _animationEnd; // Cartesian celestial coordinates - glm::dvec3 _animationStart; // Cartesian celestial coordinates + // Animation + glm::dvec3 _animationEnd; // Cartesian equatorial coordinates + glm::dvec3 _animationStart; // Cartesian equatorial coordinates }; } diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index ba6061c5a2..a6086ce13e 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -21,22 +21,22 @@ namespace openspace { // Galactic coordinates are projected onto the celestial sphere // Equatorial coordinates are unit length // Conversion spherical <-> Cartesian - glm::dvec2 cartesianToSpherical(glm::dvec3 coords); - glm::dvec3 sphericalToCartesian(glm::dvec2 coords); + glm::dvec2 cartesianToSpherical(const glm::dvec3& coords); + glm::dvec3 sphericalToCartesian(const glm::dvec2& coords); // Conversion J2000 equatorial <-> galactic - glm::dvec3 galacticToEquatorial(glm::dvec3 coords); - glm::dvec3 equatorialToGalactic(glm::dvec3 coords); + glm::dvec3 galacticToEquatorial(const glm::dvec3& coords); + glm::dvec3 equatorialToGalactic(const glm::dvec3& coords); // Conversion to screen space from J2000 equatorial / galactic / pixels - glm::dvec3 equatorialToScreenSpace3d(glm::dvec3 coords); - glm::dvec3 galacticToScreenSpace3d(glm::dvec3 coords); - glm::vec2 pixelToScreenSpace2d(glm::vec2& mouseCoordinate); + glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords); + glm::dvec3 galacticToScreenSpace3d(const glm::dvec3& coords); + glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate); // Conversion local camera space <-> galactic / equatorial - glm::dvec3 galacticToLocalCamera(glm::dvec3 coords); - glm::dvec3 localCameraToGalactic(glm::dvec3 coords); - glm::dvec3 localCameraToEquatorial(glm::dvec3 coords); + glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords); + glm::dvec3 localCameraToGalactic(const glm::dvec3& coords); + glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); // Camera roll and direction double cameraRoll(); // Camera roll is with respect to the equatorial North Pole @@ -46,26 +46,13 @@ namespace openspace { // Window and field of view float windowRatio(); glm::dvec2 fovWindow(); - bool isCoordinateInView(glm::dvec3 equatorial); + bool isCoordinateInView(const glm::dvec3& equatorial); // Animation for target and camera - double angleBetweenVectors(glm::dvec3 start, glm::dvec3 end); - glm::dmat4 incrementalAnimationMatrix(glm::dvec3 start, glm::dvec3 end, + double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); + glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, double deltaTime, double speedFactor = 1.0); } - // WorldWide Telescope messages - namespace wwtmessage { - inline int messageCounter{ 0 }; - ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, - const double roll, const bool shouldMoveInstantly = true); - ghoul::Dictionary loadCollection(const std::string& url); - ghoul::Dictionary setForeground(const std::string& name); - ghoul::Dictionary addImage(const std::string& id, const std::string& url); - ghoul::Dictionary removeImage(const std::string& id); - ghoul::Dictionary setImageOpacity(const std::string& id, double opacity); - ghoul::Dictionary setForegroundOpacity(double val); - ghoul::Dictionary setLayerOrder(const std::string& id, int version); - } } #endif // __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index b95edc6046..f0318e94e0 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -45,11 +46,12 @@ public: virtual ~WwtCommunicator(); // WorldWide Telescope communication - void displayImage(const std::string& url, const int i); + void displayImage(const std::string& url, int i); void removeSelectedImage(const int i); void setImageOrder(int i, int order); void loadImageCollection(const std::string& collection); - void setImageOpacity(const int i, float opacity); + void setImageOpacity(int i, float opacity); + void update(); // Getters const std::deque& getSelectedImages(); @@ -57,29 +59,52 @@ public: float verticalFov() const; glm::dvec2 fieldsOfView(); bool hasLoadedImages() const; + glm::dvec3 equatorialAimCartesian() const; // Setters void setHasLoadedImages(bool isLoaded); void setVerticalFov(float vfov); - void setWebpageBorderColor(glm::ivec3 color); + void setIsSyncedWithWwt(bool isSynced); + void setEquatorialAim(glm::dvec3 cartesian); // Display void highlight(glm::ivec3 addition); void removeHighlight(glm::ivec3 removal); + void updateBorderColor(); + protected: - void sendMessageToWwt(const ghoul::Dictionary& msg); // Web page communication void setIdInBrowser(const std::string& id); + properties::DVec2Property _equatorialAim; properties::FloatProperty _verticalFov; properties::IVec3Property _borderColor; + std::deque _selectedImages; bool _hasLoadedImages{ false }; private: - void executeJavascript(const std::string& script) const; + bool _isSyncedWithWwt{ false }; + const std::chrono::microseconds interval = std::chrono::microseconds(10000); + std::chrono::time_point latestCall; + + void setWebpageBorderColor(glm::ivec3 color); + void sendMessageToWwt(const ghoul::Dictionary& msg); + + int messageCounter{ 0 }; + + ghoul::Dictionary moveCamera(const glm::dvec2& celestCoords, const double fov, + const double roll, const bool shouldMoveInstantly = true); + ghoul::Dictionary loadCollection(const std::string& url); + ghoul::Dictionary setForeground(const std::string& name); + ghoul::Dictionary addImage(const std::string& id, const std::string& url); + ghoul::Dictionary removeImage(const std::string& id); + ghoul::Dictionary setImageOpacity(const std::string& id, double opacity); + ghoul::Dictionary setForegroundOpacity(double val); + ghoul::Dictionary setLayerOrder(const std::string& id, int version); + }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index e3734c7f7a..433b245b54 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -186,14 +186,6 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, - { - "connectBrowserTarget", - &skybrowser::luascriptfunctions::connectBrowserTarget, - {}, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, { "add3dBrowserToSkyBrowserModule", &skybrowser::luascriptfunctions::add3dBrowserToSkyBrowserModule, @@ -429,9 +421,7 @@ SkyBrowserModule::SkyBrowserModule() if (_isCameraRotating) { incrementallyRotateCamera(deltaTime); } - }); - - + }); } SkyBrowserModule::~SkyBrowserModule() { @@ -539,7 +529,6 @@ void SkyBrowserModule::createTargetBrowserPair() { "Name = '" + nameBrowser + "'," "Url = '"+ url +"'," "FaceCamera = false," - "TargetId = '" + idTarget + "'," "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," "}"; const std::string target = "{" @@ -547,7 +536,6 @@ void SkyBrowserModule::createTargetBrowserPair() { "Type = 'ScreenSpaceSkyTarget'," "Name = '" + nameTarget + "'," "FaceCamera = false," - "BrowserId = '" + idBrowser + "'," "}"; openspace::global::scriptEngine->queueScript( @@ -566,11 +554,6 @@ void SkyBrowserModule::createTargetBrowserPair() { scripting::ScriptEngine::RemoteScripting::Yes ); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.connectBrowserTarget('" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::Yes diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 8b2861b16c..b627267489 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -16,378 +16,320 @@ namespace { namespace openspace::skybrowser::luascriptfunctions { - int selectImage(lua_State* L) { - // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); - const int i = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); +int selectImage(lua_State* L) { + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); - if (module->isCameraInSolarSystem()) { - module->selectImage2dBrowser(i); - } - else { - module->selectImage3dBrowser(i); - } + if (module->isCameraInSolarSystem()) { + module->selectImage2dBrowser(i); + } + else { + module->selectImage3dBrowser(i); + } - return 0; - } + return 0; +} - int moveCircleToHoverImage(lua_State* L) { - // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); - const int i = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - module->moveHoverCircle(i); +int moveCircleToHoverImage(lua_State* L) { + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + module->moveHoverCircle(i); - return 0; - } + return 0; +} - int disableHoverCircle(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); - SkyBrowserModule* module = global::moduleEngine->module(); - module->disableHoverCircle(); +int disableHoverCircle(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); + SkyBrowserModule* module = global::moduleEngine->module(); + module->disableHoverCircle(); - return 0; + return 0; +} + +int lockTarget(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(id)) { + module->getPair(id)->lock(); + } + return 0; +} + +int unlockTarget(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(id)) { + module->getPair(id)->unlock(); + } + return 0; +} + + +int setImageLayerOrder(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); + const std::string id = ghoul::lua::value(L, 1); + const int i = ghoul::lua::value(L, 2); + int order = ghoul::lua::value(L, 3); + SkyBrowserModule* module = global::moduleEngine->module(); + + if (module->getPair(id)) { + module->getPair(id)->setImageOrder(i, order); + } + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->setImageOrder(i, order); } - int lockTarget(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->lock(); - } - return 0; - } - - int unlockTarget(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->unlock(); - } - return 0; - } - - - int setImageLayerOrder(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); - const std::string id = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 2); - int order = ghoul::lua::value(L, 3); - SkyBrowserModule* module = global::moduleEngine->module(); - - if (module->getPair(id)) { - module->getPair(id)->setImageOrder(i, order); - } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->setImageLayerOrder(i, order); - } - - return 0; - } + return 0; +} - int loadImagesToWWT(lua_State* L) { - // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT"); - const std::string id = ghoul::lua::value(L, 1); - LINFO("Connection established to WorldWide Telescope application in " + id); - LINFO("Loading image collections to " + id); +int loadImagesToWWT(lua_State* L) { + // Load images from url + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT"); + const std::string id = ghoul::lua::value(L, 1); + LINFO("Connection established to WorldWide Telescope application in " + id); + LINFO("Loading image collections to " + id); - // Load the collections here because here we know that the browser can execute - // javascript - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" - "wwt-web-client/master/assets/webclient-explore-root.wtml"; + // Load the collections here because here we know that the browser can execute + // javascript + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" + "wwt-web-client/master/assets/webclient-explore-root.wtml"; - SkyBrowserModule* module = global::moduleEngine->module(); + SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->loadImages(root); - } - else if (module->get3dBrowser(id)) { + if (module->getPair(id)) { + module->getPair(id)->loadImageCollection(root); + } + else if (module->get3dBrowser(id)) { - // Load Image collections - module->get3dBrowser(id)->stopSyncingWwtView(); - LINFO("Load images to " + module->get3dBrowser(id)->identifier()); - module->get3dBrowser(id)->sendMessageToWwt(wwtmessage::loadCollection(root)); - LINFO("Image collection loaded in " + module->get3dBrowser(id)->identifier()); + // Load Image collections + module->get3dBrowser(id)->stopSyncingWwtView(); + LINFO("Load images to " + module->get3dBrowser(id)->identifier()); + module->get3dBrowser(id)->loadImageCollection(root); + LINFO("Image collection loaded in " + module->get3dBrowser(id)->identifier()); - } - - return 0; - } - - int sendOutIdsToBrowsers(lua_State* L) { - // This is called when the sky_browser website is connected to OpenSpace - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers"); - - // Send out ID's to the browsers - SkyBrowserModule* module = global::moduleEngine->module(); - std::vector pairs = module->getPairs(); - for (Pair pair : pairs) { - pair.sendIdToBrowser(); - } - if(module->get3dBrowser()) { - std::string id = module->get3dBrowserNode()->identifier(); - module->get3dBrowser()->setIdInBrowser(id); - } - return 0; } - int connectBrowserTarget(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::connectBrowserTarget"); - const std::string id = ghoul::lua::value(L, 1); + return 0; +} - // Connect the target and browser to each other - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->connectPair(); - } +int sendOutIdsToBrowsers(lua_State* L) { + // This is called when the sky_browser website is connected to OpenSpace + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers"); - return 0; + // Send out ID's to the browsers + SkyBrowserModule* module = global::moduleEngine->module(); + std::vector>& pairs = module->getPairs(); + for (std::unique_ptr& pair : pairs) { + pair->sendIdToBrowser(); } - - int initializeBrowser(lua_State* L) { - // Initialize browser with ID and its corresponding target - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowser"); - const std::string id = ghoul::lua::value(L, 1); - - LINFO("Initializing sky browser " + id); - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->synchronizeWithWwt(); - } - else if(module->get3dBrowser(id)) { - // Initialize - LINFO("Initializing 3D sky browsers"); - module->get3dBrowser()->syncWwtView(); - } - - return 0; - } - - int add3dBrowserToSkyBrowserModule(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::add3dBrowserToSkyBrowserModule"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - - LINFO("Add to sky browser module id " + id); - module->set3dBrowser(id); - - return 0; - } - - int addPairToSkyBrowserModule(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); - const std::string targetId = ghoul::lua::value(L, 1); - const std::string browserId = ghoul::lua::value(L, 2); - SkyBrowserModule* module = global::moduleEngine->module(); - - LINFO("Add browser " + browserId + " to sky browser module."); - LINFO("Add target " + targetId + " to sky browser module."); - - module->addTargetBrowserPair(targetId, browserId); - - return 0; - } - - int getListOfImages(lua_State* L) { - // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); - SkyBrowserModule* module = global::moduleEngine->module(); - - // If no data has been loaded yet, download the data from the web! - - if (module->nLoadedImages() == 0) { - std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" - "wwt-web-client/master/assets/webclient-explore-root.wtml"; - //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/" - //"catalog.aspx?W=hubble"; - std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); - - // 3D images - std::string http = "${BASE}/sync/http/"; - std::string globular = "digitaluniverse_globularclusters_speck/2/gc.speck"; - std::string open = "digitaluniverse_openclusters_speck/2/oc.speck"; - // Load speck files for 3D positions - std::filesystem::path globularClusters = absPath(http + globular); - std::filesystem::path openClusters = absPath(http + open); - std::vector specks = { - openClusters, - globularClusters - }; - - module->loadImages(root, directory, specks); - } - - // Create Lua table to send to the GUI - lua_newtable(L); - - for (int i = 0; i < module->nLoadedImages(); i++) { - const ImageData& img = module->getWWTDataHandler()->getImage(i); - glm::dvec3 coords = img.equatorialCartesian; - glm::dvec3 position = img.position3d; - - // Conversions for ghoul - std::vector cartCoordsVec = { coords.x, coords.y, coords.z }; - std::vector position3d = { position.x, position.y, position.z }; + if(module->get3dBrowser()) { - // Index for current ImageData - ghoul::lua::push(L, i + 1); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "name", img.name); - lua_settable(L, -3); - ghoul::lua::push(L, "thumbnail", img.thumbnailUrl); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", img.equatorialSpherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", img.equatorialSpherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); - lua_settable(L, -3); - ghoul::lua::push(L, "hasCelestialCoords", img.hasCelestialCoords); - lua_settable(L, -3); - ghoul::lua::push(L, "credits", img.credits); - lua_settable(L, -3); - ghoul::lua::push(L, "creditsUrl", img.creditsUrl); - lua_settable(L, -3); - ghoul::lua::push(L, "identifier", std::to_string(i)); - lua_settable(L, -3); - ghoul::lua::push(L, "has3dCoords", img.has3dCoords); - lua_settable(L, -3); - ghoul::lua::push(L, "position3d", position3d); - lua_settable(L, -3); - // Set table for the current ImageData - lua_settable(L, -3); - } + module->get3dBrowser()->setIdInBrowser(); + } + return 0; +} - return 1; - } +int initializeBrowser(lua_State* L) { + // Initialize browser with ID and its corresponding target + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowser"); + const std::string id = ghoul::lua::value(L, 1); - int getTargetData(lua_State* L) { - // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getTargetData"); + LINFO("Initializing sky browser " + id); + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(id)) { + module->getPair(id)->setIsSyncedWithWwt(true); + module->getPair(id)->initialize(); + } + else if(module->get3dBrowser(id)) { + // Initialize + LINFO("Initializing 3D sky browsers"); + module->get3dBrowser()->setIsSyncedWithWwt(true); + } - SkyBrowserModule* module = global::moduleEngine->module(); + return 0; +} + +int add3dBrowserToSkyBrowserModule(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::add3dBrowserToSkyBrowserModule"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); - lua_newtable(L); + LINFO("Add to sky browser module id " + id); + module->set3dBrowser(id); + + return 0; +} + +int addPairToSkyBrowserModule(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); + const std::string targetId = ghoul::lua::value(L, 1); + const std::string browserId = ghoul::lua::value(L, 2); + SkyBrowserModule* module = global::moduleEngine->module(); + + LINFO("Add browser " + browserId + " to sky browser module."); + LINFO("Add target " + targetId + " to sky browser module."); - // Add the window data for OpenSpace - ghoul::lua::push(L, "OpenSpace"); - lua_newtable(L); - glm::dvec3 cartesianCam = skybrowser::cameraDirectionEquatorial(); - glm::dvec2 sphericalCam = skybrowser::cartesianToSpherical(cartesianCam); - // Convert to vector so ghoul can read it - std::vector viewDirCelestVec = { - cartesianCam.x, - cartesianCam.y, - cartesianCam.z + module->addTargetBrowserPair(targetId, browserId); + + return 0; +} + +int getListOfImages(lua_State* L) { + // Send image list to GUI + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); + SkyBrowserModule* module = global::moduleEngine->module(); + + // If no data has been loaded yet, download the data from the web! + + if (module->nLoadedImages() == 0) { + std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" + "wwt-web-client/master/assets/webclient-explore-root.wtml"; + //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/" + //"catalog.aspx?W=hubble"; + std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); + + // 3D images + std::string http = "${BASE}/sync/http/"; + std::string globular = "digitaluniverse_globularclusters_speck/2/gc.speck"; + std::string open = "digitaluniverse_openclusters_speck/2/oc.speck"; + // Load speck files for 3D positions + std::filesystem::path globularClusters = absPath(http + globular); + std::filesystem::path openClusters = absPath(http + open); + std::vector specks = { + openClusters, + globularClusters }; - - // Calculate the smallest FOV of vertical and horizontal - glm::dvec2 fovs = skybrowser::fovWindow(); - double FOV = std::min(fovs.x, fovs.y); - // Push window data - ghoul::lua::push(L, "windowHFOV", FOV); + + module->loadImages(root, directory, specks); + } + + // Create Lua table to send to the GUI + lua_newtable(L); + + for (int i = 0; i < module->nLoadedImages(); i++) { + const ImageData& img = module->getWWTDataHandler()->getImage(i); + glm::dvec3 coords = img.equatorialCartesian; + glm::dvec3 position = img.position3d; + + // Conversions for ghoul + std::vector cartCoordsVec = { coords.x, coords.y, coords.z }; + std::vector position3d = { position.x, position.y, position.z }; + + // Index for current ImageData + ghoul::lua::push(L, i + 1); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "name", img.name); lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); + ghoul::lua::push(L, "thumbnail", img.thumbnailUrl); lua_settable(L, -3); - ghoul::lua::push(L, "ra", sphericalCam.x); + ghoul::lua::push(L, "ra", img.equatorialSpherical.x); lua_settable(L, -3); - ghoul::lua::push(L, "dec", sphericalCam.y); + ghoul::lua::push(L, "dec", img.equatorialSpherical.y); lua_settable(L, -3); - ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); + ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); lua_settable(L, -3); - ghoul::lua::push(L, "cameraInSolarSystem", module->isCameraInSolarSystem()); + ghoul::lua::push(L, "hasCelestialCoords", img.hasCelestialCoords); + lua_settable(L, -3); + ghoul::lua::push(L, "credits", img.credits); + lua_settable(L, -3); + ghoul::lua::push(L, "creditsUrl", img.creditsUrl); + lua_settable(L, -3); + ghoul::lua::push(L, "identifier", std::to_string(i)); + lua_settable(L, -3); + ghoul::lua::push(L, "has3dCoords", img.has3dCoords); + lua_settable(L, -3); + ghoul::lua::push(L, "position3d", position3d); lua_settable(L, -3); // Set table for the current ImageData - lua_settable(L, -3); + lua_settable(L, -3); + } - // Pass data for all the browsers and the corresponding targets - if (module->isCameraInSolarSystem()) { - std::vector pairs = module->getPairs(); + return 1; +} - for (Pair pair : pairs) { - std::string id = pair.browserId(); - // Convert deque to vector so ghoul can read it - std::vector selectedImagesVector; - const std::deque selectedImages = pair.getSelectedImages(); - std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) { - selectedImagesVector.push_back(i); - }); - - glm::dvec3 cartesian = pair.targetDirectionEquatorial(); - glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); - - std::vector cartesianVec = { - cartesian.x, - cartesian.y, - cartesian.z - }; - // Convert color to vector so ghoul can read it - glm::ivec3 color = pair.borderColor(); - std::vector colorVec = { color.r, color.g, color.b }; +int getTargetData(lua_State* L) { + // Send image list to GUI + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getTargetData"); - ghoul::lua::push(L, id); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "id", id); - lua_settable(L, -3); - ghoul::lua::push(L, "name", pair.browserGuiName()); - lua_settable(L, -3); - ghoul::lua::push(L, "FOV", pair.verticalFov()); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedImages", selectedImagesVector); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", cartesianVec); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", spherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", spherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "color", colorVec); - lua_settable(L, -3); - ghoul::lua::push(L, "isLocked", pair.isLocked()); - lua_settable(L, -3); - - // Set table for the current target - lua_settable(L, -3); - - } - } - else if(module->get3dBrowser()){ + SkyBrowserModule* module = global::moduleEngine->module(); + + lua_newtable(L); + + // Add the window data for OpenSpace + ghoul::lua::push(L, "OpenSpace"); + lua_newtable(L); + glm::dvec3 cartesianCam = skybrowser::cameraDirectionEquatorial(); + glm::dvec2 sphericalCam = skybrowser::cartesianToSpherical(cartesianCam); + // Convert to vector so ghoul can read it + std::vector viewDirCelestVec = { + cartesianCam.x, + cartesianCam.y, + cartesianCam.z + }; + + // Calculate the smallest FOV of vertical and horizontal + glm::dvec2 fovs = skybrowser::fovWindow(); + double FOV = std::min(fovs.x, fovs.y); + // Push window data + ghoul::lua::push(L, "windowHFOV", FOV); + lua_settable(L, -3); + ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); + lua_settable(L, -3); + ghoul::lua::push(L, "ra", sphericalCam.x); + lua_settable(L, -3); + ghoul::lua::push(L, "dec", sphericalCam.y); + lua_settable(L, -3); + ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); + lua_settable(L, -3); + ghoul::lua::push(L, "cameraInSolarSystem", module->isCameraInSolarSystem()); + lua_settable(L, -3); + // Set table for the current ImageData + lua_settable(L, -3); + + // Pass data for all the browsers and the corresponding targets + if (module->isCameraInSolarSystem()) { + std::vector>& pairs = module->getPairs(); + + for (std::unique_ptr& pair : pairs) { + std::string id = pair->browserId(); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - std::deque selectedImages = module->get3dBrowser()->getSelectedImages(); - std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { - selectedImagesVector.push_back(index); + const std::deque selectedImages = pair->getSelectedImages(); + std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) { + selectedImagesVector.push_back(i); }); - glm::dvec3 position3dBrowser = module->get3dBrowserNode()->position(); - glm::dvec3 cartesian = skybrowser::galacticToEquatorial(position3dBrowser); + + glm::dvec3 cartesian = pair->targetDirectionEquatorial(); glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); - std::vector celestialCartVec = { + + std::vector cartesianVec = { cartesian.x, cartesian.y, cartesian.z }; // Convert color to vector so ghoul can read it - //glm::ivec3 color = browser->_borderColor.value(); - std::vector colorVec = { 200, 200, 200 }; + glm::ivec3 color = pair->borderColor(); + std::vector colorVec = { color.r, color.g, color.b }; - ghoul::lua::push(L, module->get3dBrowser()->identifier()); + ghoul::lua::push(L, id); lua_newtable(L); // Push ("Key", value) - ghoul::lua::push(L, "id", module->get3dBrowser()->identifier()); + ghoul::lua::push(L, "id", id); lua_settable(L, -3); - ghoul::lua::push(L, "name", module->get3dBrowserNode()->guiName()); + ghoul::lua::push(L, "name", pair->browserGuiName()); lua_settable(L, -3); - ghoul::lua::push(L, "FOV", module->get3dBrowser()->verticalFov()); + ghoul::lua::push(L, "FOV", pair->verticalFov()); lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", celestialCartVec); + ghoul::lua::push(L, "cartesianDirection", cartesianVec); lua_settable(L, -3); ghoul::lua::push(L, "ra", spherical.x); lua_settable(L, -3); @@ -395,129 +337,171 @@ namespace openspace::skybrowser::luascriptfunctions { lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); - + ghoul::lua::push(L, "isLocked", pair->isLocked()); + lua_settable(L, -3); + // Set table for the current target lua_settable(L, -3); + } + } + else if(module->get3dBrowser()){ + // Convert deque to vector so ghoul can read it + std::vector selectedImagesVector; + std::deque selectedImages = module->get3dBrowser()->getSelectedImages(); + std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { + selectedImagesVector.push_back(index); + }); + glm::dvec3 position3dBrowser = module->get3dBrowserNode()->position(); + glm::dvec3 cartesian = skybrowser::galacticToEquatorial(position3dBrowser); + glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); + std::vector celestialCartVec = { + cartesian.x, + cartesian.y, + cartesian.z + }; + // Convert color to vector so ghoul can read it + //glm::ivec3 color = browser->_borderColor.value(); + std::vector colorVec = { 200, 200, 200 }; + + ghoul::lua::push(L, module->get3dBrowser()->identifier()); + lua_newtable(L); + // Push ("Key", value) + ghoul::lua::push(L, "id", module->get3dBrowser()->identifier()); + lua_settable(L, -3); + ghoul::lua::push(L, "name", module->get3dBrowserNode()->guiName()); + lua_settable(L, -3); + ghoul::lua::push(L, "FOV", module->get3dBrowser()->verticalFov()); + lua_settable(L, -3); + ghoul::lua::push(L, "selectedImages", selectedImagesVector); + lua_settable(L, -3); + ghoul::lua::push(L, "cartesianDirection", celestialCartVec); + lua_settable(L, -3); + ghoul::lua::push(L, "ra", spherical.x); + lua_settable(L, -3); + ghoul::lua::push(L, "dec", spherical.y); + lua_settable(L, -3); + ghoul::lua::push(L, "color", colorVec); + lua_settable(L, -3); + + // Set table for the current target + lua_settable(L, -3); + } - return 1; + return 1; +} +int adjustCamera(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + + if(module->isCameraInSolarSystem()) { + module->lookAtTarget(id); } - int adjustCamera(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - - if(module->isCameraInSolarSystem()) { - module->lookAtTarget(id); - } - else { - module->lookAt3dBrowser(); - } - - return 0; - } - - int set3dSelectedImagesAs2dSelection(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); - const std::string pairId = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - module->add2dSelectedImagesTo3d(pairId); - - return 0; + else { + module->lookAt3dBrowser(); } - int setOpacityOfImageLayer(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); - const std::string id = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 2); - double opacity = ghoul::lua::value(L, 3); - SkyBrowserModule* module = global::moduleEngine->module(); - ghoul::Dictionary message = wwtmessage::setImageOpacity( - std::to_string(i), - opacity - ); + return 0; +} - if (module->getPair(id)) { - module->getPair(id)->setImageOpacity(i, opacity); +int set3dSelectedImagesAs2dSelection(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); + const std::string pairId = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + module->add2dSelectedImagesTo3d(pairId); + + return 0; +} + +int setOpacityOfImageLayer(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); + const std::string id = ghoul::lua::value(L, 1); + const int i = ghoul::lua::value(L, 2); + double opacity = ghoul::lua::value(L, 3); + SkyBrowserModule* module = global::moduleEngine->module(); + + if (module->getPair(id)) { + module->getPair(id)->setImageOpacity(i, opacity); - } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->sendMessageToWwt(message); - } - - return 0; + } + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->setImageOpacity(i, opacity); } - int centerTargetOnScreen(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); - if (pair) { - pair->centerTargetOnScreen(); - } + return 0; +} + +int centerTargetOnScreen(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + Pair* pair = module->getPair(id); + if (pair) { + pair->centerTargetOnScreen(); + } - return 0; - } + return 0; +} - int setSelectedBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); +int setSelectedBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); + const std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); - module->setSelectedBrowser(id); + module->setSelectedBrowser(id); - return 0; - } + return 0; +} - int createTargetBrowserPair(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createTargetBrowserPair"); - SkyBrowserModule* module = global::moduleEngine->module(); - module->createTargetBrowserPair(); +int createTargetBrowserPair(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createTargetBrowserPair"); + SkyBrowserModule* module = global::moduleEngine->module(); + module->createTargetBrowserPair(); - return 0; - } + return 0; +} - int removeTargetBrowserPair(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeTargetBrowserPair"); - std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - module->removeTargetBrowserPair(id); +int removeTargetBrowserPair(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeTargetBrowserPair"); + std::string id = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + module->removeTargetBrowserPair(id); - return 0; - } + return 0; +} - int place3dSkyBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::place3dSkyBrowser"); - // Image index to place in 3D - const int i = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData image = module->getWWTDataHandler()->getImage(i); +int place3dSkyBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::place3dSkyBrowser"); + // Image index to place in 3D + const int i = ghoul::lua::value(L, 1); + SkyBrowserModule* module = global::moduleEngine->module(); + const ImageData image = module->getWWTDataHandler()->getImage(i); - module->place3dBrowser(image, i); + module->place3dBrowser(image, i); - return 0; - } + return 0; +} - int removeSelectedImageInBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); - // Image index - const int i = ghoul::lua::value(L, 1); - const std::string id = ghoul::lua::value(L, 2); - // Get browser - SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData& image = module->getWWTDataHandler()->getImage(i); +int removeSelectedImageInBrowser(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); + // Image index + const int i = ghoul::lua::value(L, 1); + const std::string id = ghoul::lua::value(L, 2); + // Get browser + SkyBrowserModule* module = global::moduleEngine->module(); + const ImageData& image = module->getWWTDataHandler()->getImage(i); - Pair* pair = module->getPair(id); - if (pair) { - pair->removeSelectedImage(i); - } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->removeSelectedImage(image, i); - } - return 0; + Pair* pair = module->getPair(id); + if (pair) { + pair->removeSelectedImage(i); } + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->removeSelectedImage(i); + } + return 0; +} } diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index df9af7a94b..9d9ff9c733 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -81,7 +81,7 @@ namespace openspace { _url.onChange([this]() { _isUrlDirty = true; }); _dimensions.onChange([this]() { _isDimensionsDirty = true; }); - _reload.onChange([this]() { _browserInstance->reloadBrowser(); }); + _reload.onChange([this]() { _shouldReload = true; }); // Create browser and render handler _renderHandler = new RenderHandler(); @@ -98,9 +98,7 @@ namespace openspace { } Browser::~Browser() { - // Delete - _browserInstance.reset(); - _texture.reset(); + } bool Browser::initializeGL() { @@ -118,11 +116,12 @@ namespace openspace { bool Browser::deinitializeGL() { _renderHandler->setTexture(0); + _texture = nullptr; std::string urlString; _url.getStringValue(urlString); - LDEBUG(fmt::format("Deinitializing ScreenSpaceBrowser: {}", urlString)); + LDEBUG(fmt::format("Deinitializing browser: {}", urlString)); _browserInstance->close(true); @@ -157,19 +156,53 @@ namespace openspace { _browserInstance->reshape(_dimensions.value()); _isDimensionsDirty = false; } + + if (_shouldReload) { + _browserInstance->reloadBrowser(); + _shouldReload = false; + } } bool Browser::isReady() const { return _texture.get(); } - void Browser::bindTexture() { - _texture->bind(); - } - glm::vec2 Browser::browserPixelDimensions() const { return _dimensions.value(); } + // Updates the browser size to match the size of the texture + void Browser::updateBrowserSize() { + _dimensions = _texture->dimensions(); + } + float Browser::browserRatio() const + { + return static_cast(_texture->dimensions().x) / + static_cast(_texture->dimensions().y); + } + + void Browser::setCallbackDimensions( + const std::function& function) + { + _dimensions.onChange([&]() { + function(_dimensions.value()); + }); + } + + void Browser::executeJavascript(const std::string& script) const { + + // Make sure that the browser has a main frame + const bool browserExists = _browserInstance && _browserInstance->getBrowser(); + const bool frameIsLoaded = browserExists && + _browserInstance->getBrowser()->GetMainFrame(); + + if (frameIsLoaded) { + _browserInstance->getBrowser()->GetMainFrame()->ExecuteJavaScript( + script, + _browserInstance->getBrowser()->GetMainFrame()->GetURL(), + 0 + ); + } + } } // namespace openspace diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 4dfd73c33d..be536f5481 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -25,8 +25,14 @@ #include #include +#include +#include #include #include +#include +#include + +#pragma optimize("", off) namespace openspace { @@ -37,31 +43,76 @@ namespace openspace { { ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); ghoul_assert(target != nullptr, "Sky target is null pointer!"); + + // Set callback functions so that the target and the browser update each other + _browser->setCallbackEquatorialAim( + [&](const glm::dvec3& equatorialAim, bool) { + double diff = glm::length(equatorialAim - _target->directionEquatorial()); + if ( diff > epsilon) { + _target->startAnimation(equatorialAim, false); + } + } + ); + _browser->setCallbackBorderColor( + [&](const glm::ivec3& color) { + _target->setColor(color); + } + ); + _browser->setCallbackVerticalFov( + [&](float vfov) { + _target->setScaleFromVfov(vfov); + } + ); + _browser->setCallbackDimensions( + [&](const glm::vec2& dimensions) { + _target->setDimensions(dimensions); + } + ); + // Always make sure that the target and browser are visible together + _browser->setCallbackEnabled( + [&](bool enabled) { + _target->setEnabled(enabled); + } + ); + _target->setCallbackEnabled( + [&](bool enabled) { + _browser->setEnabled(enabled); + } + ); + _target->setCallbackPosition( + [&](glm::vec3 localCameraPosition) { + double diff = glm::length( + _browser->equatorialAimCartesian() - _target->directionEquatorial() + ); + if (diff > epsilon) { + _browser->setEquatorialAim( + skybrowser::localCameraToEquatorial(localCameraPosition) + ); + } + } + ); + } + + Pair& Pair::operator=(Pair other) + { + std::swap(_target, other._target); + std::swap(_browser, other._browser); + return *this; + } void Pair::lock() { - _target->lock(); + _target->setLock(true); } void Pair::unlock() { - _target->unlock(); + _target->setLock(false); } void Pair::setImageOrder(int i, int order) { _browser->setImageOrder(i, order); } - void Pair::connectPair() - { - _browser->connectToSkyTarget(); - _target->connectoToSkyBrowser(); - } - - void Pair::synchronizeWithWwt() - { - _browser->startSyncingWithWwt(); - } - void Pair::removeHighlight(glm::ivec3 color) { _target->removeHighlight(color); @@ -84,7 +135,7 @@ namespace openspace { bool Pair::isBrowserFadeFinished(float goalState) { - float browserDiff = abs(_browser->getOpacity().value() - goalState); + float browserDiff = abs(_browser->opacity() - goalState); return browserDiff < AcceptableDiff; } @@ -124,6 +175,14 @@ namespace openspace { return _target->isLocked(); } + void Pair::initialize() + { + _target->setColor(_browser->borderColor()); + _target->setDimensions(_browser->browserPixelDimensions()); + _target->setScaleFromVfov(_browser->verticalFov()); + _browser->updateBorderColor(); + } + glm::ivec3 Pair::borderColor() { return _browser->borderColor(); @@ -144,12 +203,12 @@ namespace openspace { return _browser->guiName(); } - std::string Pair::browserId() + const std::string& Pair::browserId() const { return _browser->identifier(); } - std::string Pair::targetId() + const std::string& Pair::targetId() const { return _target->identifier(); } @@ -183,7 +242,7 @@ namespace openspace { _browser->removeSelectedImage(i); } - void Pair::loadImages(std::string collection) + void Pair::loadImageCollection(std::string collection) { _browser->loadImageCollection(collection); } @@ -202,6 +261,11 @@ namespace openspace { _browser->updateBrowserSize(); } + void Pair::setIsSyncedWithWwt(bool isSynced) + { + _browser->setIsSyncedWithWwt(isSynced); + } + void Pair::incrementallyAnimateToCoordinate(double deltaTime) { // Animate the target before the field of view starts to animate @@ -258,18 +322,19 @@ namespace openspace { } if (!isBrowserFadeFinished(goalState)) { - _browser->getOpacity() = _browser->getOpacity().value() + opacityDelta; + _browser->setOpacity(_browser->opacity() + opacityDelta); } else { - _browser->getOpacity() = goalState; + _browser->setOpacity(goalState); } } - + bool operator==(const Pair& lhs, const Pair& rhs) { return lhs._target == rhs._target && lhs._browser == rhs._browser; } - bool operator!=(const Pair & lhs, const Pair & rhs) { + bool operator!=(const Pair& lhs, const Pair& rhs) { return !(lhs == rhs); } + } // namespace openspace diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index c248b73e17..1e664c2ff8 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,6 +1,5 @@ #include -#include #include #include #include @@ -19,13 +18,6 @@ namespace { "dimensions", "lineColor" }; - constexpr const openspace::properties::Property::PropertyInfo BrowserIDInfo = - { - "BrowserId", - "Browser Identifier", - "The identifier of the corresponding sky browser." - }; - constexpr const openspace::properties::Property::PropertyInfo CrosshairThresholdInfo = { "CrosshairThreshold", @@ -60,9 +52,6 @@ namespace { struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { - // [[codegen::verbatim(BrowserIDInfo.description)]] - std::optional browserId; - // [[codegen::verbatim(CrosshairThresholdInfo.description)]] std::optional crosshairThreshold; @@ -84,8 +73,6 @@ namespace { namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _skyBrowserId(BrowserIDInfo) - , _skyBrowser(nullptr) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 1.0) @@ -94,30 +81,16 @@ namespace openspace { { // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _skyBrowserId = p.browserId.value_or(_skyBrowserId); _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); _stopAnimationThreshold = p.crosshairThreshold.value_or(_stopAnimationThreshold); _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - addProperty(_skyBrowserId); addProperty(_showCrosshairThreshold); addProperty(_showRectangleThreshold); addProperty(_stopAnimationThreshold); addProperty(_animationSpeed); - // If the ID changes for the corresponding browser, update - _skyBrowserId.onChange([&]() { - connectoToSkyBrowser(); - }); - - // Always make sure that the target and browser are visible together - _enabled.onChange([&]() { - if (_skyBrowser) { - _skyBrowser->property("Enabled")->set(_enabled.value()); - } - }); - // Set a unique identifier std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { @@ -137,9 +110,7 @@ namespace openspace { } ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { - if (_lockTarget.joinable()) { - _lockTarget.join(); - } + } // Pure virtual in the screen space renderable class and hence must be defined @@ -147,21 +118,6 @@ namespace openspace { } - bool ScreenSpaceSkyTarget::connectoToSkyBrowser() { - _skyBrowser = dynamic_cast( - global::renderEngine->screenSpaceRenderable(_skyBrowserId.value())); - matchAppearanceToSkyBrowser(); - return _skyBrowser; - } - - void ScreenSpaceSkyTarget::matchAppearanceToSkyBrowser() { - if (_skyBrowser) { - _color = _skyBrowser->borderColor(); - _objectSize = _skyBrowser->browserPixelDimensions(); - setScale(_skyBrowser->verticalFov()); - } - } - bool ScreenSpaceSkyTarget::isReady() const { return _shader != nullptr; } @@ -177,9 +133,6 @@ namespace openspace { bool ScreenSpaceSkyTarget::deinitializeGL() { - if (isLocked()) { - unlock(); - } return ScreenSpaceRenderable::deinitializeGL(); } @@ -219,18 +172,10 @@ namespace openspace { return _color; } - ScreenSpaceSkyBrowser* ScreenSpaceSkyTarget::getSkyBrowser() { - return _skyBrowser; - } - void ScreenSpaceSkyTarget::render() { - bool showCrosshair = false; - bool showRectangle = true; - if (_skyBrowser) { - showCrosshair = _skyBrowser->verticalFov() < _showCrosshairThreshold; - showRectangle = _skyBrowser->verticalFov() > _showRectangleThreshold; - } + bool showCrosshair = _verticalFov < _showCrosshairThreshold; + bool showRectangle = _verticalFov > _showRectangleThreshold; glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() }; glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * @@ -259,6 +204,15 @@ namespace openspace { _shader->deactivate(); } + void ScreenSpaceSkyTarget::update() + { + if (_isLocked) { + _cartesianPosition = skybrowser::equatorialToScreenSpace3d( + _lockedCoordinates + ); + } + } + void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { _objectSize = dimensions; } @@ -275,8 +229,9 @@ namespace openspace { // Update the scale of the target (the height of the target in relation to the // OpenSpace window) - void ScreenSpaceSkyTarget::setScale(float verticalFov) { + void ScreenSpaceSkyTarget::setScaleFromVfov(float verticalFov) { + _verticalFov = verticalFov; glm::dvec2 fovs = skybrowser::fovWindow(); // Cap the scale at small scales so it is still visible @@ -286,31 +241,7 @@ namespace openspace { _scale = std::max(heightRatio, smallestHeightRatio); } - void ScreenSpaceSkyTarget::unlock() { - _isLocked = false; - if (_lockTarget.joinable()) { - _lockTarget.join(); - } - } - - void ScreenSpaceSkyTarget::lock() { - if (_isLocked) { - unlock(); - } - _isLocked = true; - _lockedCoordinates = directionEquatorial(); - - // Start a thread to enable user interactions while locking target - _lockTarget = std::thread([&] { - while (_isLocked) { - _cartesianPosition = skybrowser::equatorialToScreenSpace3d( - _lockedCoordinates - ); - } - }); - } - - bool ScreenSpaceSkyTarget::isLocked() { + bool ScreenSpaceSkyTarget::isLocked() const { return _isLocked; } @@ -325,12 +256,14 @@ namespace openspace { _animationEnd = glm::normalize(end); _shouldLockAfterAnimation = shouldLockAfter; _isAnimated = true; + _isLocked = false; } void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, _animationEnd); + double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, + _animationEnd); const bool shouldAnimate = smallestAngle > _stopAnimationThreshold; // Only keep animating when target is not at goal position @@ -357,8 +290,8 @@ namespace openspace { _isAnimated = false; // Lock target when it first arrives to the position - if (!isLocked() && _shouldLockAfterAnimation) { - lock(); + if (!_isLocked && _shouldLockAfterAnimation) { + _isLocked = true; } } } @@ -387,4 +320,24 @@ namespace openspace { void ScreenSpaceSkyTarget::setOpacity(float opacity) { _opacity = opacity; } + void ScreenSpaceSkyTarget::setLock(bool isLocked) + { + _isLocked = isLocked; + if (_isLocked) { + _lockedCoordinates = directionEquatorial(); + } + } + void ScreenSpaceSkyTarget::setCallbackEnabled(std::function function) + { + _enabled.onChange([this, f = std::move(function)]() { + f(_enabled); + }); + } + void ScreenSpaceSkyTarget::setCallbackPosition( + std::function function) + { + _cartesianPosition.onChange([this, f = std::move(function)]() { + f(_cartesianPosition); + }); + } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 6d1510407f..652ceb99ad 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -11,7 +11,7 @@ namespace openspace::skybrowser { - glm::dvec3 sphericalToCartesian(glm::dvec2 coords) { + glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) { glm::dvec2 coordsRadians = glm::radians(coords); @@ -24,7 +24,7 @@ namespace openspace::skybrowser { return cartesian; } - glm::dvec2 cartesianToSpherical(glm::dvec3 coord) { + glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) { // Equatorial coordinates RA = right ascension, Dec = declination double ra = atan2(coord.y, coord.x); double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y))); @@ -36,17 +36,17 @@ namespace openspace::skybrowser { return glm::degrees(celestialCoords); } - glm::dvec3 galacticToEquatorial(glm::dvec3 coords) { + glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) { return glm::transpose(conversionMatrix) * glm::normalize(coords); } - glm::dvec3 equatorialToGalactic(glm::dvec3 coords) { + glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) { // On the unit sphere glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); return rGalactic * CelestialSphereRadius; } - glm::dvec3 galacticToScreenSpace3d(glm::dvec3 coords) { + glm::dvec3 galacticToScreenSpace3d(const glm::dvec3& coords) { glm::dvec3 localCameraSpace = galacticToLocalCamera(coords); // Ensure that if the coord is behind the camera, @@ -62,7 +62,7 @@ namespace openspace::skybrowser { return screenSpace; } - glm::dvec3 localCameraToGalactic(glm::dvec3 coords) { + glm::dvec3 localCameraToGalactic(const glm::dvec3& coords) { glm::dmat4 rotation = glm::inverse( global::navigationHandler->camera()->viewRotationMatrix()); glm::dvec4 position = glm::dvec4(coords, 1.0); @@ -70,7 +70,7 @@ namespace openspace::skybrowser { return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius; } - glm::dvec3 localCameraToEquatorial(glm::dvec3 coords) { + glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) { // Calculate the galactic coordinate of the target direction // projected onto the celestial sphere glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); @@ -79,7 +79,7 @@ namespace openspace::skybrowser { return skybrowser::galacticToEquatorial(galactic); } - glm::dvec3 galacticToLocalCamera(glm::dvec3 coords) { + glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) { // Transform vector to camera's local coordinate system glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); @@ -89,7 +89,7 @@ namespace openspace::skybrowser { return glm::normalize(viewDirectionLocal); } - glm::dvec3 equatorialToScreenSpace3d(glm::dvec3 coords) { + glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords) { // Transform equatorial J2000 to galactic coord with infinite radius glm::dvec3 galactic = equatorialToGalactic(coords); // Transform galactic coord to screen space @@ -130,7 +130,7 @@ namespace openspace::skybrowser { return windowRatio.x / windowRatio.y; } - bool isCoordinateInView(glm::dvec3 equatorial) { + bool isCoordinateInView(const glm::dvec3& equatorial) { // Check if image coordinate is within current FOV glm::dvec3 coordsScreen = equatorialToScreenSpace3d(equatorial); double r = static_cast(windowRatio()); @@ -143,7 +143,7 @@ namespace openspace::skybrowser { } // Transforms a pixel coordinate to a screen space coordinate - glm::vec2 pixelToScreenSpace2d(glm::vec2& mouseCoordinate) { + glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) { glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); // Change origin to middle of the window glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f); @@ -164,15 +164,15 @@ namespace openspace::skybrowser { return OpenSpaceFOV; } - double angleBetweenVectors(glm::dvec3 start, glm::dvec3 end) { + double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { // Find smallest angle between the two vectors double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); return std::acos(cos); } - glm::dmat4 incrementalAnimationMatrix(glm::dvec3 start, - glm::dvec3 end, double deltaTime, + glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, + const glm::dvec3& end, double deltaTime, double speedFactor) { double smallestAngle = angleBetweenVectors(start, end); @@ -186,101 +186,6 @@ namespace openspace::skybrowser { } -// WWT messages -namespace openspace::wwtmessage { - // WWT messages - ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, - const double roll, const bool shouldMoveInstantly) { - using namespace std::string_literals; - ghoul::Dictionary msg; - - // Create message - msg.setValue("event", "center_on_coordinates"s); - msg.setValue("ra", celestCoords.x); - msg.setValue("dec", celestCoords.y); - msg.setValue("fov", fov); - msg.setValue("roll", roll); - msg.setValue("instant", shouldMoveInstantly); - - return msg; - } - - ghoul::Dictionary loadCollection(const std::string& url) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "load_image_collection"s); - msg.setValue("url", url); - msg.setValue("loadChildFolders", true); - - return msg; - } - - ghoul::Dictionary setForeground(const std::string& name) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_by_name"s); - msg.setValue("name", name); - - return msg; - } - - ghoul::Dictionary addImage(const std::string& id, const std::string& url) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_create"s); - msg.setValue("id", id); - msg.setValue("url", url); - msg.setValue("mode", "preloaded"s); - msg.setValue("goto", false); - - return msg; - } - - ghoul::Dictionary removeImage(const std::string& imageId) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_remove"s); - msg.setValue("id", imageId); - - return msg; - } - - ghoul::Dictionary setImageOpacity(const std::string& imageId, double opacity) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_set"s); - msg.setValue("id", imageId); - msg.setValue("setting", "opacity"s); - msg.setValue("value", opacity); - - return msg; - } - - ghoul::Dictionary setForegroundOpacity(double val) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_opacity"s); - msg.setValue("value", val); - - return msg; - } - - ghoul::Dictionary setLayerOrder(const std::string& id, int order) { - // The lower the layer order, the more towards the back the image is placed - // 0 is the background - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_order"s); - msg.setValue("id", id); - msg.setValue("order", order); - msg.setValue("version", messageCounter); - - messageCounter++; - - return msg; - } -} - diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 602056f854..94a026ad73 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -29,7 +29,10 @@ #include #include // formatJson #include - +#include +#include // For atan2 +#define _USE_MATH_DEFINES +#include // For M_PI namespace { constexpr const char* _loggerCat = "WwtCommunicator"; @@ -46,6 +49,13 @@ namespace { "Vertical Field Of View", "The vertical field of view in degrees." }; + constexpr const openspace::properties::Property::PropertyInfo EquatorialAimInfo = + { + "EquatorialAim", + "Equatorial aim of the sky browser", + "The aim of the sky browser given in spherical equatorial coordinates right " + "ascension (RA) and declination (Dec) in epoch J2000. The unit is degrees." + }; } // namespace @@ -54,9 +64,13 @@ namespace openspace { WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary) : Browser(dictionary), _verticalFov(VerticalFovInfo, 10.f, 0.01f, 70.0f), - _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)) + _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)), + _equatorialAim(EquatorialAimInfo, glm::dvec2(0.0), glm::dvec2(0.0, -90.0), + glm::dvec2(360.0, 90.0)) { - + _borderColor.onChange([this]() { + updateBorderColor(); + }); } WwtCommunicator::~WwtCommunicator() { @@ -71,18 +85,18 @@ namespace openspace { // Push newly selected image to front _selectedImages.push_front(i); // Index of image is used as layer ID as it is unique in the image data set - sendMessageToWwt(wwtmessage::addImage(std::to_string(i), url)); - sendMessageToWwt(wwtmessage::setImageOpacity(std::to_string(i), 1.0)); + sendMessageToWwt(addImage(std::to_string(i), url)); + sendMessageToWwt(setImageOpacity(std::to_string(i), 1.0)); } } - void WwtCommunicator::removeSelectedImage(const int i) { + void WwtCommunicator::removeSelectedImage(int i) { // Remove from selected list auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); if (it != std::end(_selectedImages)) { _selectedImages.erase(it); - sendMessageToWwt(wwtmessage::removeImage(std::to_string(i))); + sendMessageToWwt(removeImage(std::to_string(i))); } } @@ -107,21 +121,33 @@ namespace openspace { executeJavascript(script); } + void WwtCommunicator::setIsSyncedWithWwt(bool isSynced) + { + _isSyncedWithWwt = isSynced; + } + + void WwtCommunicator::setEquatorialAim(glm::dvec3 cartesian) + { + _equatorialAim = skybrowser::cartesianToSpherical(cartesian); + } + void WwtCommunicator::highlight(glm::ivec3 addition) { - glm::ivec3 color = glm::ivec3(_borderColor.value()); - setWebpageBorderColor(color + addition); + setWebpageBorderColor(_borderColor.value() + addition); } void WwtCommunicator::removeHighlight(glm::ivec3 removal) { - glm::ivec3 color = glm::ivec3(_borderColor.value()); - setWebpageBorderColor(color - removal); + setWebpageBorderColor(_borderColor.value() - removal); + } + + void WwtCommunicator::updateBorderColor() + { + setWebpageBorderColor(_borderColor); } glm::dvec2 WwtCommunicator::fieldsOfView() { - float browserRatio = _dimensions.value().x / _dimensions.value().y; - glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio, verticalFov()); + glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio(), verticalFov()); return browserFov; } @@ -130,6 +156,11 @@ namespace openspace { return _hasLoadedImages; } + glm::dvec3 WwtCommunicator::equatorialAimCartesian() const + { + return skybrowser::sphericalToCartesian(_equatorialAim); + } + void WwtCommunicator::setImageOrder(int i, int order) { // Find in selected images list auto current = std::find( @@ -146,21 +177,48 @@ namespace openspace { } int reverseOrder = _selectedImages.size() - order - 1; - ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i), + ghoul::Dictionary message = setLayerOrder(std::to_string(i), reverseOrder); sendMessageToWwt(message); } void WwtCommunicator::loadImageCollection(const std::string& collection) { - sendMessageToWwt(wwtmessage::loadCollection(collection)); + sendMessageToWwt(loadCollection(collection)); _hasLoadedImages = true; } - void WwtCommunicator::setImageOpacity(const int i, float opacity) { - ghoul::Dictionary msg = wwtmessage::setImageOpacity(std::to_string(i), opacity); + void WwtCommunicator::setImageOpacity(int i, float opacity) { + ghoul::Dictionary msg = setImageOpacity(std::to_string(i), opacity); sendMessageToWwt(msg); } + void WwtCommunicator::update() + { + if (_isSyncedWithWwt) { + const std::chrono::time_point + timeBefore = std::chrono::high_resolution_clock::now(); + + std::chrono::microseconds duration = + std::chrono::duration_cast( + timeBefore - latestCall + ); + + if (duration > interval) { + // Message WorldWide Telescope current view + ghoul::Dictionary message = moveCamera( + _equatorialAim, + _verticalFov, + skybrowser::cameraRoll() + ); + sendMessageToWwt(message); + + latestCall = std::chrono::high_resolution_clock::now(); + } + } + + Browser::update(); + } + void WwtCommunicator::setHasLoadedImages(bool isLoaded) { _hasLoadedImages = isLoaded; } @@ -170,24 +228,108 @@ namespace openspace { executeJavascript("setId('" + id + "')"); } - void WwtCommunicator::executeJavascript(const std::string& script) const { - // Make sure that the browser has a main frame - const bool browserExists = _browserInstance && _browserInstance->getBrowser(); - const bool frameIsLoaded = browserExists && - _browserInstance->getBrowser()->GetMainFrame(); - - if (frameIsLoaded) { - CefRefPtr frame = _browserInstance->getBrowser()->GetMainFrame(); - frame->ExecuteJavaScript(script, frame->GetURL(), 0); - } - } glm::ivec3 WwtCommunicator::borderColor() const { - return _borderColor.value(); + return _borderColor; } float WwtCommunicator::verticalFov() const { - return _verticalFov.value(); + return _verticalFov; + } + + // WWT messages + ghoul::Dictionary WwtCommunicator::moveCamera(const glm::dvec2& celestCoords, + double fov, double roll, + bool shouldMoveInstantly) { + using namespace std::string_literals; + ghoul::Dictionary msg; + + // Create message + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("ra", celestCoords.x); + msg.setValue("dec", celestCoords.y); + msg.setValue("fov", fov); + msg.setValue("roll", roll); + msg.setValue("instant", shouldMoveInstantly); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::loadCollection(const std::string& url) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "load_image_collection"s); + msg.setValue("url", url); + msg.setValue("loadChildFolders", true); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::setForeground(const std::string& name) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_by_name"s); + msg.setValue("name", name); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::addImage(const std::string& id, + const std::string& url) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_create"s); + msg.setValue("id", id); + msg.setValue("url", url); + msg.setValue("mode", "preloaded"s); + msg.setValue("goto", false); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::removeImage(const std::string& imageId) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_remove"s); + msg.setValue("id", imageId); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::setImageOpacity(const std::string& imageId, + double opacity) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_set"s); + msg.setValue("id", imageId); + msg.setValue("setting", "opacity"s); + msg.setValue("value", opacity); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::setForegroundOpacity(double val) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_opacity"s); + msg.setValue("value", val); + + return msg; + } + + ghoul::Dictionary WwtCommunicator::setLayerOrder(const std::string& id, int order) { + // The lower the layer order, the more towards the back the image is placed + // 0 is the background + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_order"s); + msg.setValue("id", id); + msg.setValue("order", order); + msg.setValue("version", messageCounter); + + messageCounter++; + + return msg; } } // namespace openspace From 979ba8544f374d127e4f116946ecbe956baf7c2b Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 15:51:29 -0500 Subject: [PATCH 152/251] Update asset file to new structure --- data/assets/skyBrowserTargetPair.asset | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 data/assets/skyBrowserTargetPair.asset diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset new file mode 100644 index 0000000000..4facf93371 --- /dev/null +++ b/data/assets/skyBrowserTargetPair.asset @@ -0,0 +1,37 @@ +local assetHelper = asset.require('util/asset_helper') + +local targetId= "SkyTarget0" +local browserId = "SkyBrowser0" +local serverUrl = "https://data.openspaceproject.com/dist/skybrowser/page/" +--local localHostUrl = "http://localhost:8000" + +local browser = { + Type = "ScreenSpaceSkyBrowser", + Identifier = browserId, + Name = "Sky Browser", + Url = serverUrl, + FaceCamera = false, + CartesianPosition = {-1.0, -0.5, -2.1}, + Dimensions = { 1000, 1000 }, +}; + +local target = { + Type = "ScreenSpaceSkyTarget", + Identifier = targetId, + Name = "Sky Target", + FaceCamera = false, +}; + +asset.onInitialize(function () + openspace.addScreenSpaceRenderable(browser) + openspace.addScreenSpaceRenderable(target) + openspace.skybrowser.addPairToSkyBrowserModule(targetId,browserId) + openspace.skybrowser.setSelectedBrowser(browserId) +end) + +asset.onDeinitialize(function () + openspace.removeScreenSpaceRenderable(browserId) + openspace.removeScreenSpaceRenderable(targetId) +end) + +asset.export("browser", {browser, target}) From 30ea90ce646d3735cbf69ade57b8a8491c2fd425 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 23 Nov 2021 15:52:38 -0500 Subject: [PATCH 153/251] Update screenspaceskybrowser to new changes --- .../include/screenspaceskybrowser.h | 85 ++++++ .../skybrowser/src/screenspaceskybrowser.cpp | 287 ++++++++++++++++++ 2 files changed, 372 insertions(+) create mode 100644 modules/skybrowser/include/screenspaceskybrowser.h create mode 100644 modules/skybrowser/src/screenspaceskybrowser.cpp diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h new file mode 100644 index 0000000000..7de42f72a5 --- /dev/null +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -0,0 +1,85 @@ +#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace openspace { + //class ScreenSpaceSkyTarget; + class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator + { + public: + // Constructor and destructor + ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); + ~ScreenSpaceSkyBrowser(); + + // Inherited functions + bool initializeGL() override; + bool deinitializeGL() override; + glm::mat4 scaleMatrix() override; + void render() override; + void update() override; + + // Animation + bool isAnimated(); + void startFovAnimation(float fov); + void incrementallyAnimateToFov(float deltaTime); + + // Getters + float opacity() const; + + // Setters + void setVerticalFovWithScroll(float scroll); + void setScale(glm::vec2 scalingFactor); + void setScale(float scalingFactor); + void setOpacity(float opacity); + // Set callback functions + void setCallbackEquatorialAim(std::function function); + void setCallbackVerticalFov(std::function function); + void setCallbackDimensions(std::function function); + void setCallbackBorderColor(std::function function); + void setCallbackEnabled(std::function function); + + // Interaction. Resize + void saveResizeStartSize(); + // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in + // image if the mouse is on a side of the browser + // __1__ + // y| -1 |_____|1 + // |__x -1 + glm::ivec2 isOnResizeArea(glm::vec2 screenSpaceCoord); + + glm::dvec2 fineTuneVector(glm::dvec2 drag); + void setIdInBrowser(); + + private: + void bindTexture() override; + + // Flags + bool _isSyncedWithWwt{ false }; + bool _isFovAnimated{ false }; + + // Animation of browser + float _endVfov{ 0.f }; + float _fovDiff{ 0.01f }; + + // Resizing of browser + glm::vec2 _originalDimensions; + float _originalScale; + float _resizeAreaPercentage{ 0.1f }; + + // Time variables + // For capping the calls onchange properties from scrolling + constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; + std::chrono::system_clock::time_point _lastUpdateTime; + }; +} + +#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp new file mode 100644 index 0000000000..c83cf1c4eb --- /dev/null +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -0,0 +1,287 @@ +#include + +#include +#include +#include +#include +#include +#include // formatJson +#include +#include +#include +#include + +namespace { + constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; + + constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = + { + "BorderColor", + "Border Color", + "The color of the border of the sky browser." + }; + constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = + { + "VerticalFieldOfView", + "Vertical Field Of View", + "The vertical field of view in degrees." + }; + + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { + + // [[codegen::verbatim(VerticalFovInfo.description)]] + std::optional verticalFov; + + // [[codegen::verbatim(BorderColorInfo.description)]] + std::optional borderColor; + }; + +#include "ScreenSpaceSkyBrowser_codegen.cpp" +} // namespace + +namespace openspace { + + ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) + : ScreenSpaceRenderable(dictionary), + WwtCommunicator(dictionary) + { + // Set a unique identifier + std::string identifier; + if (dictionary.hasValue(KeyIdentifier)) { + identifier = dictionary.value(KeyIdentifier); + } + else { + identifier = "ScreenSpaceSkyBrowser22"; + } + identifier = makeUniqueIdentifier(identifier); + setIdentifier(identifier); + + // Make the color property display a color picker in the GUI + _borderColor.setViewOption(properties::Property::ViewOptions::Color, true); + + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _verticalFov = p.verticalFov.value_or(_verticalFov); + _borderColor = p.borderColor.value_or(_borderColor); + + addProperty(_url); + addProperty(_dimensions); + addProperty(_reload); + addProperty(_verticalFov); + addProperty(_borderColor); + addProperty(_equatorialAim); + + glm::vec2 screenPosition = _cartesianPosition.value(); + _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + + // Generate a random border color + std::random_device rd; + std::uniform_int_distribution hue(0, 255); + int value = 220; + int saturation = 128; + glm::ivec3 hsvColor = glm::ivec3(hue(rd), saturation , value); + _borderColor = glm::rgbColor(hsvColor); + } + + ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { + + } + + bool ScreenSpaceSkyBrowser::initializeGL() { + + Browser::initializeGL(); + ScreenSpaceRenderable::initializeGL(); + return true; + } + + glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) { + // Fine tuning of target + glm::dvec2 wwtFov = fieldsOfView(); + glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); + + glm::dvec2 browserDim = screenSpaceDimensions(); + glm::dvec2 angleResult = wwtFov * (drag / browserDim); + glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; + + // Convert to screen space coordinate system + glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; + glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; + return result; + } + + void ScreenSpaceSkyBrowser::setIdInBrowser() { + WwtCommunicator::setIdInBrowser(identifier()); + } + + bool ScreenSpaceSkyBrowser::deinitializeGL() { + ScreenSpaceRenderable::deinitializeGL(); + Browser::deinitializeGL(); + return true; + } + + bool ScreenSpaceSkyBrowser::isAnimated() + { + return _isFovAnimated; + } + + void ScreenSpaceSkyBrowser::startFovAnimation(float fov) + { + _isFovAnimated = true; + _endVfov = fov; + } + + void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) + { + // If distance too large, keep animating. Else, stop animation + float diff = verticalFov() - _endVfov; + const bool shouldAnimate = abs(diff) > _fovDiff; + + if (shouldAnimate) { + setVerticalFovWithScroll(diff); + } + else { + _isFovAnimated = false; + } + } + + void ScreenSpaceSkyBrowser::render() { + Browser::render(); + + draw( + globalRotationMatrix() * + translationMatrix() * + localRotationMatrix() * + scaleMatrix() + ); + } + + void ScreenSpaceSkyBrowser::update() { + + _objectSize = _texture->dimensions(); + + if (global::windowDelegate->windowHasResized()) { + // change the resolution of the texture + } + + WwtCommunicator::update(); + ScreenSpaceRenderable::update(); + } + + void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { + // Cap how often the zoom is allowed to update + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; + + if (timeSinceLastUpdate > _timeUpdateInterval) { + // Make scroll more sensitive the smaller the FOV + float x = _verticalFov; + float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; + float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; + _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); + _lastUpdateTime = std::chrono::system_clock::now(); + } + } + + void ScreenSpaceSkyBrowser::bindTexture() + { + _texture->bind(); + } + + glm::ivec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { + glm::ivec2 resizePosition = glm::ivec2{ 0 }; + // Make sure coordinate is on browser + if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; + + // TO DO: turn this into a vector and use prettier vector arithmetic + float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; + float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; + + const bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; + const bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; + const bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; + const bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; + + resizePosition.x = isOnRight ? 1 : isOnLeft ? -1 : 0; + resizePosition.y = isOnTop ? 1 : isOnBottom ? -1 : 0; + + return resizePosition; + } + // Scales the ScreenSpaceBrowser to a new ratio + void ScreenSpaceSkyBrowser::setScale(glm::vec2 scalingFactor) { + + // Scale on the y axis, this is to ensure that _scale = 1 is + // equal to the height of the window + setScale(abs(scalingFactor.y)); + // Resize the dimensions of the texture on the x axis + glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; + _texture->setDimensions(glm::ivec3(newSize, 1)); + _objectSize = _texture->dimensions(); + } + + glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { + // To ensure the plane has the right ratio + // The _scale tells us how much of the windows height the + // browser covers: e.g. a browser that covers 0.25 of the + // height of the window will have scale = 0.25 + + glm::mat4 scale = glm::scale( + glm::mat4(1.f), + glm::vec3(browserRatio() * _scale, _scale, 1.f) + ); + return scale; + } + + void ScreenSpaceSkyBrowser::saveResizeStartSize() { + _originalDimensions = _dimensions.value(); + _originalScale = _scale.value(); + } + + void ScreenSpaceSkyBrowser::setCallbackEquatorialAim( + std::function function) + { + _equatorialAim.onChange([this, f = std::move(function)]() { + f(skybrowser::sphericalToCartesian(_equatorialAim), false); + }); + + } + void ScreenSpaceSkyBrowser::setCallbackVerticalFov( + std::function function) + { + _verticalFov.onChange([this, f = std::move(function)]() { + f(_verticalFov.value()); + }); + + } + void ScreenSpaceSkyBrowser::setCallbackDimensions( + std::function function) + { + _dimensions.onChange([this, f = std::move(function)]() { + f(_dimensions); + }); + + } + void ScreenSpaceSkyBrowser::setCallbackBorderColor( + std::function function) { + _borderColor.onChange([this, f = std::move(function)]() { + f(_borderColor.value()); + }); + } + void ScreenSpaceSkyBrowser::setCallbackEnabled(std::function function) + { + _enabled.onChange([this, f = std::move(function)]() { + f(_enabled); + }); + } + void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { + _scale = _originalScale * scalingFactor; + } + + void ScreenSpaceSkyBrowser::setOpacity(float opacity) + { + _opacity = opacity; + } + + float ScreenSpaceSkyBrowser::opacity() const { + return _opacity; + } +} From 0fb5bd937ecd425a26995a16f3a7693e75873b3d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 31 May 2021 15:46:05 +0200 Subject: [PATCH 154/251] Fix issue with not being able to include sgct anymore with Visual Studio 16.10 (cherry picked from commit 404fc3f9bf37ab9e5ea0f831de7692e1b69c7320) --- apps/OpenSpace/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/OpenSpace/CMakeLists.txt b/apps/OpenSpace/CMakeLists.txt index 7622653bf6..c43e141b3f 100644 --- a/apps/OpenSpace/CMakeLists.txt +++ b/apps/OpenSpace/CMakeLists.txt @@ -116,13 +116,13 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct) target_link_libraries(OpenSpace PRIVATE sgct) set_folder_location(sgct "External") -set_folder_location(glfw "External/SGCT") -set_folder_location(miniziplibstatic "External/SGCT") -set_folder_location(png16_static "External/SGCT") -set_folder_location(quat "External/SGCT") -set_folder_location(tinyxml2static "External/SGCT") -set_folder_location(vrpn "External/SGCT") -set_folder_location(zlibstatic "External/SGCT") +set_folder_location(glfw "External") +set_folder_location(miniziplibstatic "External") +set_folder_location(png16_static "External") +set_folder_location(quat "External") +set_folder_location(tinyxml2static "External") +set_folder_location(vrpn "External") +set_folder_location(zlibstatic "External") if (UNIX AND (NOT APPLE)) target_link_libraries(OpenSpace PRIVATE Xcursor Xinerama X11) From 921f4ff31d4a730a203de48bf8c54d041a0d8230 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 30 Nov 2021 12:34:33 -0500 Subject: [PATCH 155/251] Bugfix after merge with master --- modules/skybrowser/include/wwtdatahandler.h | 38 +-- modules/skybrowser/skybrowsermodule.cpp | 26 +- modules/skybrowser/skybrowsermodule_lua.inl | 26 +- .../skybrowser/src/screenspaceskytarget.cpp | 4 +- modules/skybrowser/src/utility.cpp | 4 +- modules/skybrowser/src/wwtdatahandler.cpp | 224 +----------------- modules/space/speckloader.cpp | 4 +- 7 files changed, 25 insertions(+), 301 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 2178e65b70..71ea59e3d7 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -2,6 +2,7 @@ #define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ #include +#include #include #include @@ -13,43 +14,6 @@ namespace openspace::documentation { struct Documentation; } -// Copied from the branch feature/speck-loader -// Should be changed to a more general way of loading -// Speck files one that has been created -namespace openspace::speck { - - BooleanType(SkipAllZeroLines); - - struct Dataset { - struct Variable { - int index; - std::string name; - }; - std::vector variables; - - struct Texture { - int index; - std::string file; - }; - std::vector textures; - - int textureDataIndex = -1; - int orientationDataIndex = -1; - - struct Entry { - glm::dvec3 position; - std::vector data; - std::optional comment; - }; - std::vector entries; - }; - - // In-out methods - Dataset loadSpeckFile(std::filesystem::path path, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); - -} // namespace openspace::speck\ - namespace openspace::wwt { const std::string Thumbnail = "Thumbnail"; const std::string Name = "Name"; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 433b245b54..1d8247aaae 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -30,9 +30,9 @@ #include "skybrowsermodule_lua.inl" #include #include -#include +#include #include -#include +#include #include namespace { @@ -53,7 +53,6 @@ namespace openspace { { "getListOfImages", &skybrowser::luascriptfunctions::getListOfImages, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -61,7 +60,6 @@ namespace openspace { { "moveCircleToHoverImage", &skybrowser::luascriptfunctions::moveCircleToHoverImage, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -69,7 +67,6 @@ namespace openspace { { "disableHoverCircle", &skybrowser::luascriptfunctions::disableHoverCircle, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -77,7 +74,6 @@ namespace openspace { { "loadImagesToWWT", &skybrowser::luascriptfunctions::loadImagesToWWT, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -85,7 +81,6 @@ namespace openspace { { "selectImage", &skybrowser::luascriptfunctions::selectImage, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -93,7 +88,6 @@ namespace openspace { { "removeSelectedImageInBrowser", &skybrowser::luascriptfunctions::removeSelectedImageInBrowser, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -101,7 +95,6 @@ namespace openspace { { "adjustCamera", & skybrowser::luascriptfunctions::adjustCamera, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -109,7 +102,6 @@ namespace openspace { { "setSelectedBrowser", & skybrowser::luascriptfunctions::setSelectedBrowser, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -117,7 +109,6 @@ namespace openspace { { "getTargetData", &skybrowser::luascriptfunctions::getTargetData, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -125,7 +116,6 @@ namespace openspace { { "lockTarget", &skybrowser::luascriptfunctions::lockTarget, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -133,7 +123,6 @@ namespace openspace { { "unlockTarget", &skybrowser::luascriptfunctions::unlockTarget, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -141,7 +130,6 @@ namespace openspace { { "createTargetBrowserPair", &skybrowser::luascriptfunctions::createTargetBrowserPair, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -149,7 +137,6 @@ namespace openspace { { "removeTargetBrowserPair", &skybrowser::luascriptfunctions::removeTargetBrowserPair, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -157,7 +144,6 @@ namespace openspace { { "place3dSkyBrowser", &skybrowser::luascriptfunctions::place3dSkyBrowser, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -165,7 +151,6 @@ namespace openspace { { "setOpacityOfImageLayer", &skybrowser::luascriptfunctions::setOpacityOfImageLayer, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -173,7 +158,6 @@ namespace openspace { { "sendOutIdsToBrowsers", &skybrowser::luascriptfunctions::sendOutIdsToBrowsers, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -181,7 +165,6 @@ namespace openspace { { "initializeBrowser", &skybrowser::luascriptfunctions::initializeBrowser, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -189,7 +172,6 @@ namespace openspace { { "add3dBrowserToSkyBrowserModule", &skybrowser::luascriptfunctions::add3dBrowserToSkyBrowserModule, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -197,7 +179,6 @@ namespace openspace { { "set3dSelectedImagesAs2dSelection", &skybrowser::luascriptfunctions::set3dSelectedImagesAs2dSelection, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -205,7 +186,6 @@ namespace openspace { { "centerTargetOnScreen", &skybrowser::luascriptfunctions::centerTargetOnScreen, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -213,7 +193,6 @@ namespace openspace { { "setImageLayerOrder", &skybrowser::luascriptfunctions::setImageLayerOrder, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" @@ -221,7 +200,6 @@ namespace openspace { { "addPairToSkyBrowserModule", &skybrowser::luascriptfunctions::addPairToSkyBrowserModule, - {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b627267489..2226ef4720 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -74,8 +74,8 @@ int unlockTarget(lua_State* L) { int setImageLayerOrder(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); const std::string id = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 2); - int order = ghoul::lua::value(L, 3); + const int i = ghoul::lua::value(L, 1); + int order = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { @@ -169,7 +169,7 @@ int add3dBrowserToSkyBrowserModule(lua_State* L) { int addPairToSkyBrowserModule(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); const std::string targetId = ghoul::lua::value(L, 1); - const std::string browserId = ghoul::lua::value(L, 2); + const std::string browserId = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); LINFO("Add browser " + browserId + " to sky browser module."); @@ -192,7 +192,7 @@ int getListOfImages(lua_State* L) { "wwt-web-client/master/assets/webclient-explore-root.wtml"; //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/" //"catalog.aspx?W=hubble"; - std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); + std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/").string(); // 3D images std::string http = "${BASE}/sync/http/"; @@ -201,10 +201,10 @@ int getListOfImages(lua_State* L) { // Load speck files for 3D positions std::filesystem::path globularClusters = absPath(http + globular); std::filesystem::path openClusters = absPath(http + open); - std::vector specks = { - openClusters, - globularClusters - }; + std::vector specks; // = { + //openClusters, + //globularClusters + //}; module->loadImages(root, directory, specks); } @@ -361,8 +361,8 @@ int getTargetData(lua_State* L) { cartesian.z }; // Convert color to vector so ghoul can read it - //glm::ivec3 color = browser->_borderColor.value(); - std::vector colorVec = { 200, 200, 200 }; + glm::ivec3 color = module->get3dBrowser()->borderColor(); + std::vector colorVec = { color.x, color.y, color.z }; ghoul::lua::push(L, module->get3dBrowser()->identifier()); lua_newtable(L); @@ -418,8 +418,8 @@ int set3dSelectedImagesAs2dSelection(lua_State* L) { int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); const std::string id = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 2); - double opacity = ghoul::lua::value(L, 3); + const int i = ghoul::lua::value(L, 1); + double opacity = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { @@ -488,7 +488,7 @@ int removeSelectedImageInBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); // Image index const int i = ghoul::lua::value(L, 1); - const std::string id = ghoul::lua::value(L, 2); + const std::string id = ghoul::lua::value(L, 1); // Get browser SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& image = module->getWWTDataHandler()->getImage(i); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 1e664c2ff8..416e20436b 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -2,11 +2,11 @@ #include #include -#include +#include #include #include #include -#include +#include #include #include diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 652ceb99ad..4836649779 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include // For atan2 #define _USE_MATH_DEFINES diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 4042297490..24a67d1beb 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -1,6 +1,7 @@ #include #include + #include // For downloading files from url #include #include @@ -9,13 +10,6 @@ #include #include -// For loading the speck files -#include -#include -#include -#include -#include - namespace { constexpr const char* _loggerCat = "WWTDataHandler"; } //namespace @@ -239,7 +233,7 @@ namespace openspace { // Load 3D data from speck files for (std::filesystem::path& path : speckFiles) { - speck::Dataset speck = speck::loadSpeckFile(path); + speck::Dataset speck = speck::data::loadFileWithCache(path); _3dPositions = loadSpeckData(speck); LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + " entries!"); @@ -446,217 +440,3 @@ namespace { } } // namespace -namespace openspace::speck { - - Dataset loadSpeckFile(std::filesystem::path path, - SkipAllZeroLines skipAllZeroLines) - { - ghoul_assert(std::filesystem::exists(path), "File must exist"); - - std::ifstream file(path); - if (!file.good()) { - throw ghoul::RuntimeError(fmt::format("Failed to open speck file '{}'", path)); - } - - Dataset res; - - int nDataValues = 0; - - std::string line; - // First phase: Loading the header information - while (std::getline(file, line)) { - // Ignore empty line or commented-out lines - if (line.empty() || line[0] == '#') { - continue; - } - - // Guard against wrong line endings (copying files from Windows to Mac) causes - // lines to have a final \r - if (line.back() == '\r') { - line = line.substr(0, line.length() - 1); - } - - strip(line); - - // If the first character is a digit, we have left the preamble and are in the - // data section of the file - if (std::isdigit(line[0]) || line[0] == '-') { - break; - } - - - if (startsWith(line, "datavar")) { - // each datavar line is following the form: - // datavar - // with being the index of the data variable - - std::stringstream str(line); - std::string dummy; - Dataset::Variable v; - str >> dummy >> v.index >> v.name; - - //if (v.name == "orientation" || v.name == "ori" || v.name == "texture") { - // // The values for orientation and the texture indices are handled by - // // their own keywords - //} - //else { - nDataValues += 1; - res.variables.push_back(v); - //} - - continue; - } - - if (startsWith(line, "texturevar")) { - // each texturevar line is following the form: - // texturevar - // where is the data value index where the texture index is stored - if (res.textureDataIndex != -1) { - throw ghoul::RuntimeError(fmt::format( - "Error loading speck file '{}': Texturevar defined twice", - path - )); - } - - std::stringstream str(line); - std::string dummy; - str >> dummy >> res.textureDataIndex; - - //nDataValues += 1; - continue; - } - - if (startsWith(line, "polyorivar")) { - // each texturevar line is following the form: - // texturevar - // where is the data value index where the orientation index storage - // starts. There are 6 values stored in total, xyz + uvw - - if (res.orientationDataIndex != -1) { - throw ghoul::RuntimeError(fmt::format( - "Error loading speck file '{}': Orientation index defined twice", - path - )); - } - - std::stringstream str(line); - std::string dummy; - str >> dummy >> res.orientationDataIndex; - - //nDataValues += 6; - continue; - } - - if (startsWith(line, "texture")) { - // each texture line is following one of two forms: - // 1: texture -M 1 halo.sgi - // 2: texture 1 M1.sgi - // The parameter in #1 is currently being ignored - - std::stringstream str(line); - - std::string dummy; - str >> dummy; - - if (line.find('-') != std::string::npos) { - str >> dummy; - } - - Dataset::Texture texture; - str >> texture.index >> texture.file; - res.textures.push_back(texture); - continue; - } - } - - std::sort( - res.variables.begin(), res.variables.end(), - [](const Dataset::Variable& lhs, const Dataset::Variable& rhs) { - return lhs.index < rhs.index; - } - ); - - std::sort( - res.textures.begin(), res.textures.end(), - [](const Dataset::Texture& lhs, const Dataset::Texture& rhs) { - return lhs.index < rhs.index; - } - ); - - // For the first line, we already loaded it and rejected it above, so if we do another - // std::getline, we'd miss the first data value line - bool isFirst = true; - while (isFirst || std::getline(file, line)) { - isFirst = false; - - // Ignore empty line or commented-out lines - if (line.empty() || line[0] == '#') { - continue; - } - - // Guard against wrong line endings (copying files from Windows to Mac) causes - // lines to have a final \r - if (line.back() == '\r') { - line = line.substr(0, line.length() - 1); - } - - strip(line); - - if (line.empty()) { - continue; - } - - // If the first character is a digit, we have left the preamble and are in the - // data section of the file - if (!std::isdigit(line[0]) && line[0] != '-') { - throw ghoul::RuntimeError(fmt::format( - "Error loading speck file '{}': Header information and datasegment " - "intermixed", path - )); - } - - bool allZero = true; - - std::stringstream str(line); - Dataset::Entry entry; - str >> entry.position.x >> entry.position.y >> entry.position.z; - allZero &= (entry.position == glm::dvec3(0.0)); - - entry.data.resize(nDataValues); - for (int i = 0; i < nDataValues; i += 1) { - str >> entry.data[i]; - allZero &= (entry.data[i] == 0.0); - } - - if (skipAllZeroLines && allZero) { - continue; - } - - std::string rest; - std::getline(str, rest); - if (!rest.empty()) { - - strip(rest); - entry.comment = rest; - } - - res.entries.push_back(std::move(entry)); - - } - -#ifdef _DEBUG - if (!res.entries.empty()) { - size_t nDataValues = res.entries[0].data.size(); - for (const Dataset::Entry& e : res.entries) { - ghoul_assert( - e.data.size() == nDataValues, - "Row had different number of data values" - ); - } - } -#endif - - return res; - } - -} // namespace openspace::speck diff --git a/modules/space/speckloader.cpp b/modules/space/speckloader.cpp index d4165fa3b6..ecda919a40 100644 --- a/modules/space/speckloader.cpp +++ b/modules/space/speckloader.cpp @@ -130,6 +130,7 @@ namespace { } } // namespace +#pragma optimize("", off) namespace openspace::speck { namespace data { @@ -332,7 +333,8 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) strip(rest); entry.comment = rest; } - + int i = 0; + i += 1; res.entries.push_back(std::move(entry)); } From ef1af3b6be810cde36d5fd01e946c6282928fb22 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 11:10:48 -0500 Subject: [PATCH 156/251] Add set cartesian position to screenspace renderable --- include/openspace/rendering/screenspacerenderable.h | 1 + src/rendering/screenspacerenderable.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 18544ec240..bfa41ee975 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -81,6 +81,7 @@ public: bool coordIsInsideCornersScreenSpace(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); friend bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs); + void setCartesianPosition(const glm::vec3& position); // End of addition by skybrowser team diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 3c113429f0..a4f7686855 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -540,6 +540,11 @@ void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); } +void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) +{ + _cartesianPosition = position; +} + bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs) { // Sort on depth coordinate, larger values are closer to camera return lhs._cartesianPosition.value().z > rhs._cartesianPosition.value().z; From 16f608fd5c02d3332bbbbcba6cb2425c7ca81e5a Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 11:12:32 -0500 Subject: [PATCH 157/251] Cleanup --- modules/skybrowser/include/pair.h | 6 +-- .../skybrowser/include/screenspaceskytarget.h | 2 +- modules/skybrowser/include/wwtcommunicator.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 10 ++--- modules/skybrowser/src/pair.cpp | 41 +++++++++---------- .../skybrowser/src/screenspaceskytarget.cpp | 21 ++++------ modules/skybrowser/src/wwtcommunicator.cpp | 2 +- modules/skybrowser/src/wwtdatahandler.cpp | 2 +- 9 files changed, 42 insertions(+), 46 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 1fa8777769..450a97d214 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -37,8 +37,8 @@ class ImageData; class Pair { public: - constexpr static const float AcceptableDiff = 0.01f; - constexpr static const double epsilon = std::numeric_limits::epsilon(); + constexpr static const float FadeThreshold = 0.01f; + constexpr static const double AnimationThreshold = 0.0001f;; Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); Pair(Pair const&) = default; @@ -51,7 +51,7 @@ public: void setImageOrder(int i, int order); void removeHighlight(glm::ivec3 color); void highlight(glm::ivec3 color); - void enable(); + void setEnabled(bool enable); void disable(); void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 4fded24047..b4fec5e27c 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -46,7 +46,7 @@ namespace openspace { // Target directions glm::dvec3 directionGalactic() const; - glm::dvec3 directionEquatorial() const; + glm::dvec3 equatorialAim() const; // Locking functionality bool isLocked() const; diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index f0318e94e0..d47d7372c6 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -59,7 +59,7 @@ public: float verticalFov() const; glm::dvec2 fieldsOfView(); bool hasLoadedImages() const; - glm::dvec3 equatorialAimCartesian() const; + glm::dvec3 equatorialAim() const; // Setters void setHasLoadedImages(bool isLoaded); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1d8247aaae..2a2f9affda 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -801,7 +801,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float pair->incrementallyFade(transparency, _fadingTime, deltaTime); } else if (isPairFinished && goal == Transparency::Transparent) { - pair->disable(); + pair->setEnabled(false); } isAllFinished &= isPairFinished; } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 2226ef4720..7a6a2f38d0 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -195,16 +195,16 @@ int getListOfImages(lua_State* L) { std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/").string(); // 3D images - std::string http = "${BASE}/sync/http/"; + std::string http = "${SYNC}/http/"; std::string globular = "digitaluniverse_globularclusters_speck/2/gc.speck"; std::string open = "digitaluniverse_openclusters_speck/2/oc.speck"; // Load speck files for 3D positions std::filesystem::path globularClusters = absPath(http + globular); std::filesystem::path openClusters = absPath(http + open); - std::vector specks; // = { - //openClusters, - //globularClusters - //}; + std::vector specks = { + openClusters, + globularClusters + }; module->loadImages(root, directory, specks); } diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index be536f5481..b3ab88a070 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -43,13 +43,16 @@ namespace openspace { { ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); ghoul_assert(target != nullptr, "Sky target is null pointer!"); - + + // Set browser callback functions // Set callback functions so that the target and the browser update each other _browser->setCallbackEquatorialAim( [&](const glm::dvec3& equatorialAim, bool) { - double diff = glm::length(equatorialAim - _target->directionEquatorial()); - if ( diff > epsilon) { - _target->startAnimation(equatorialAim, false); + double diff = glm::length(equatorialAim - _target->equatorialAim()); + if ( diff > AnimationThreshold) { + _target->setCartesianPosition( + skybrowser::equatorialToScreenSpace3d(equatorialAim) + ); } } ); @@ -74,6 +77,8 @@ namespace openspace { _target->setEnabled(enabled); } ); + + // Set target callback functions _target->setCallbackEnabled( [&](bool enabled) { _browser->setEnabled(enabled); @@ -82,9 +87,9 @@ namespace openspace { _target->setCallbackPosition( [&](glm::vec3 localCameraPosition) { double diff = glm::length( - _browser->equatorialAimCartesian() - _target->directionEquatorial() + _browser->equatorialAim() - _target->equatorialAim() ); - if (diff > epsilon) { + if (diff > AnimationThreshold) { _browser->setEquatorialAim( skybrowser::localCameraToEquatorial(localCameraPosition) ); @@ -130,13 +135,13 @@ namespace openspace { // Is fading finished? float targetDiff = abs(_target->opacity() - goalState); - return targetDiff < AcceptableDiff; + return targetDiff < FadeThreshold; } bool Pair::isBrowserFadeFinished(float goalState) { float browserDiff = abs(_browser->opacity() - goalState); - return browserDiff < AcceptableDiff; + return browserDiff < FadeThreshold; } bool Pair::isCoordOnPair(glm::vec2 mousePosition) @@ -153,16 +158,10 @@ namespace openspace { return onBrowser || onTarget; } - void Pair::enable() + void Pair::setEnabled(bool enable) { - _browser->property("Enabled")->set(true); - _target->property("Enabled")->set(true); - } - - void Pair::disable() - { - _browser->property("Enabled")->set(false); - _target->property("Enabled")->set(false); + _browser->setEnabled(enable); + _target->setEnabled(enable); } bool Pair::isEnabled() @@ -190,7 +189,7 @@ namespace openspace { glm::dvec3 Pair::targetDirectionEquatorial() { - return _target->directionEquatorial(); + return _target->equatorialAim(); } glm::dvec3 Pair::targetDirectionGalactic() @@ -233,7 +232,7 @@ namespace openspace { // Animate the target to the image coordinate position unlock(); - startAnimation(image.equatorialCartesian, image.fov); + startAnimation(image.equatorialCartesian, image.fov, true); } } @@ -277,9 +276,9 @@ namespace openspace { } } - void Pair::startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter) + void Pair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, bool shouldLockAfter) { - _target->startAnimation(coordsEnd, shouldLockAfter); + _target->startAnimation(equatorialCoords, shouldLockAfter); _browser->startFovAnimation(fovEnd); } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 416e20436b..10283b0665 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -75,7 +75,7 @@ namespace openspace { : ScreenSpaceRenderable(dictionary) , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) - , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 1.0) + , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _color(220, 220, 220) { @@ -250,10 +250,10 @@ namespace openspace { return _isAnimated; } - void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 end, bool shouldLockAfter) + void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, bool shouldLockAfter) { - _animationStart = glm::normalize(directionEquatorial()); - _animationEnd = glm::normalize(end); + _animationStart = glm::normalize(equatorialAim()); + _animationEnd = glm::normalize(equatorialCoordsEnd); _shouldLockAfterAnimation = shouldLockAfter; _isAnimated = true; _isLocked = false; @@ -282,21 +282,18 @@ namespace openspace { _cartesianPosition = skybrowser::equatorialToScreenSpace3d(newDir); // Update position - _animationStart = glm::normalize(newDir); + _animationStart = glm::normalize(equatorialAim()); } else { // Set the exact target position - _cartesianPosition = skybrowser::equatorialToScreenSpace3d(_animationEnd); + _cartesianPosition = glm::vec3(skybrowser::equatorialToScreenSpace3d(_animationEnd)); _isAnimated = false; - // Lock target when it first arrives to the position - if (!_isLocked && _shouldLockAfterAnimation) { - _isLocked = true; - } + setLock(_shouldLockAfterAnimation); } } - glm::dvec3 ScreenSpaceSkyTarget::directionEquatorial() const { + glm::dvec3 ScreenSpaceSkyTarget::equatorialAim() const { // Calculate the galactic coordinate of the target direction // projected onto the celestial sphere return skybrowser::localCameraToEquatorial(_cartesianPosition.value()); @@ -324,7 +321,7 @@ namespace openspace { { _isLocked = isLocked; if (_isLocked) { - _lockedCoordinates = directionEquatorial(); + _lockedCoordinates = equatorialAim(); } } void ScreenSpaceSkyTarget::setCallbackEnabled(std::function function) diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 94a026ad73..72a4e8fce4 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -156,7 +156,7 @@ namespace openspace { return _hasLoadedImages; } - glm::dvec3 WwtCommunicator::equatorialAimCartesian() const + glm::dvec3 WwtCommunicator::equatorialAim() const { return skybrowser::sphericalToCartesian(_equatorialAim); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 24a67d1beb..b8bf7e5516 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -11,7 +11,7 @@ #include namespace { - constexpr const char* _loggerCat = "WWTDataHandler"; + constexpr const char* _loggerCat = "WwtDataHandler"; } //namespace namespace openspace { From 8703ad84b4ce371e3ec8a0fc5c1b8becf4bb7274 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 11:51:57 -0500 Subject: [PATCH 158/251] Fix random border color of browser to have constant saturation and brightness --- .../skybrowser/src/screenspaceskybrowser.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index c83cf1c4eb..669fa7c653 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -11,6 +11,8 @@ #include #include + +#pragma optimize("", off) namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -74,13 +76,16 @@ namespace openspace { glm::vec2 screenPosition = _cartesianPosition.value(); _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); - // Generate a random border color + // Generate a random border color with sufficient lightness and a n std::random_device rd; - std::uniform_int_distribution hue(0, 255); - int value = 220; - int saturation = 128; - glm::ivec3 hsvColor = glm::ivec3(hue(rd), saturation , value); - _borderColor = glm::rgbColor(hsvColor); + // Hue is in the unit degrees [0, 360] + std::uniform_real_distribution hue(0.f, 360.f); + // Value in saturation are in the unit percent [0,1] + float value = 0.95f; // Brightness + float saturation = 0.5f; + glm::vec3 hsvColor = glm::vec3(hue(rd), saturation , value); + glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor)*255.f); + _borderColor = rgbColor; } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { From 69eb10cdda231d56126fb484254db83def71ff1e Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 13:46:50 -0500 Subject: [PATCH 159/251] Cleanup of pair --- modules/skybrowser/include/pair.h | 69 ++++++++++++++++++------------- modules/skybrowser/src/pair.cpp | 34 +++++++-------- 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 450a97d214..cd619e6632 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -45,55 +45,66 @@ public: // user-defined copy assignment (copy-and-swap idiom) Pair& operator=(Pair other); - - void lock(); - void unlock(); - void setImageOrder(int i, int order); - void removeHighlight(glm::ivec3 color); + // Target & Browser + void initialize(); + // Highlighting + void removeHighlight(glm::ivec3 color); void highlight(glm::ivec3 color); - void setEnabled(bool enable); - void disable(); - + // Animation void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); - void centerTargetOnScreen(); void incrementallyAnimateToCoordinate(double deltaTime); void incrementallyFade(float goalState, float fadeTime, float deltaTime); - bool hasFinishedFading(float goalState); - bool isCoordOnPair(glm::vec2 mousePosition); - bool isEnabled(); - bool isLocked(); - void initialize(); - glm::ivec3 borderColor(); - glm::dvec3 targetDirectionEquatorial(); - glm::dvec3 targetDirectionGalactic(); - std::string browserGuiName(); - const std::string& browserId() const; - const std::string& targetId() const; - float verticalFov(); - const std::deque& getSelectedImages(); - void selectImage(const ImageData& image, const int i); - void removeSelectedImage(const int i); - void loadImageCollection(std::string collection); - void setImageOpacity(const int i, float opacity); + // Browser void sendIdToBrowser(); void updateBrowserSize(); + + // Target + void centerTargetOnScreen(); + void lock(); + void unlock(); + + // Boolean functions + bool hasFinishedFading(float goalState) const; + bool isCoordOnPair(glm::vec2 mousePosition) const; + bool isEnabled() const; + bool isLocked() const; + + // Setters + void setEnabled(bool enable); void setIsSyncedWithWwt(bool isSynced); + // Getters by value + float verticalFov() const; + glm::ivec3 borderColor() const; + glm::dvec3 targetDirectionEquatorial() const; + glm::dvec3 targetDirectionGalactic() const; + std::string browserGuiName() const; + std::string browserId() const; + std::string targetId() const; + // Getters by reference ScreenSpaceSkyTarget* getTarget(); ScreenSpaceSkyBrowser* getBrowser(); + const std::deque& getSelectedImages() const; + // WorldWide Telescope image handling + void setImageOrder(int i, int order); + void selectImage(const ImageData& image, int i); + void removeSelectedImage(int i); + void loadImageCollection(const std::string& collection); + void setImageOpacity(int i, float opacity); + + // Comparision operators friend bool operator==(const Pair& lhs, const Pair& rhs); friend bool operator!=(const Pair& lhs, const Pair& rhs); private: - static std::string _selected; - bool isTargetFadeFinished(float goalState); - bool isBrowserFadeFinished(float goalState); + bool isTargetFadeFinished(float goalState) const; + bool isBrowserFadeFinished(float goalState) const; ScreenSpaceSkyTarget* _target{ nullptr }; ScreenSpaceSkyBrowser* _browser{ nullptr }; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index b3ab88a070..7494d5349a 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -130,7 +130,7 @@ namespace openspace { _target->highlight(color); } - bool Pair::isTargetFadeFinished(float goalState) + bool Pair::isTargetFadeFinished(float goalState) const { // Is fading finished? float targetDiff = abs(_target->opacity() - goalState); @@ -138,13 +138,13 @@ namespace openspace { return targetDiff < FadeThreshold; } - bool Pair::isBrowserFadeFinished(float goalState) + bool Pair::isBrowserFadeFinished(float goalState) const { float browserDiff = abs(_browser->opacity() - goalState); return browserDiff < FadeThreshold; } - bool Pair::isCoordOnPair(glm::vec2 mousePosition) + bool Pair::isCoordOnPair(glm::vec2 mousePosition) const { const bool onBrowser = _browser->coordIsInsideCornersScreenSpace(mousePosition); const bool onTarget = _target->coordIsInsideCornersScreenSpace(mousePosition); @@ -164,12 +164,12 @@ namespace openspace { _target->setEnabled(enable); } - bool Pair::isEnabled() + bool Pair::isEnabled() const { return _target->isEnabled() && _browser->isEnabled(); } - bool Pair::isLocked() + bool Pair::isLocked() const { return _target->isLocked(); } @@ -182,42 +182,42 @@ namespace openspace { _browser->updateBorderColor(); } - glm::ivec3 Pair::borderColor() + glm::ivec3 Pair::borderColor() const { return _browser->borderColor(); } - glm::dvec3 Pair::targetDirectionEquatorial() + glm::dvec3 Pair::targetDirectionEquatorial() const { return _target->equatorialAim(); } - glm::dvec3 Pair::targetDirectionGalactic() + glm::dvec3 Pair::targetDirectionGalactic() const { return _target->directionGalactic(); } - std::string Pair::browserGuiName() + std::string Pair::browserGuiName() const { return _browser->guiName(); } - const std::string& Pair::browserId() const + std::string Pair::browserId() const { return _browser->identifier(); } - const std::string& Pair::targetId() const + std::string Pair::targetId() const { return _target->identifier(); } - float Pair::verticalFov() + float Pair::verticalFov() const { return _browser->verticalFov(); } - const std::deque& Pair::getSelectedImages() + const std::deque& Pair::getSelectedImages() const { return _browser->getSelectedImages(); } @@ -236,17 +236,17 @@ namespace openspace { } } - void Pair::removeSelectedImage(const int i) + void Pair::removeSelectedImage(int i) { _browser->removeSelectedImage(i); } - void Pair::loadImageCollection(std::string collection) + void Pair::loadImageCollection(const std::string& collection) { _browser->loadImageCollection(collection); } - void Pair::setImageOpacity(const int i, float opacity) + void Pair::setImageOpacity(int i, float opacity) { _browser->setImageOpacity(i, opacity); } @@ -293,7 +293,7 @@ namespace openspace { startAnimation(viewDirection, currentFov, false); } - bool Pair::hasFinishedFading(float goalState) + bool Pair::hasFinishedFading(float goalState) const { return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); } From 1fe86fe843188abaaa3cc3effed021646cb3bec9 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 13:48:12 -0500 Subject: [PATCH 160/251] Cleanup, make hover circle add itself via lua function to the module. Make functions consistent how they interact with WWT --- data/assets/customization/gui.asset | 2 +- data/assets/hoverCircle.asset | 38 +++++++----- modules/skybrowser/include/wwtdatahandler.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 64 ++++++--------------- modules/skybrowser/skybrowsermodule.h | 8 +-- modules/skybrowser/skybrowsermodule_lua.inl | 44 ++++++++++++-- 6 files changed, 86 insertions(+), 72 deletions(-) diff --git a/data/assets/customization/gui.asset b/data/assets/customization/gui.asset index e18cd44a7f..6a43444b0a 100644 --- a/data/assets/customization/gui.asset +++ b/data/assets/customization/gui.asset @@ -1,4 +1,4 @@ -asset.export("webguiDevelopmentMode", false) +asset.export("webguiDevelopmentMode", true) -- To make changes to the webgui: diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index c43db9634c..23c7fd2fbb 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -1,15 +1,27 @@ local assetHelper = asset.require('util/asset_helper') - local spec = { - Identifier = "HoverCircle", - Type = "ScreenSpaceImageLocal", - Name = "HoverCircle", - FaceCamera = false, - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome - Scale= 0.015, - Enabled = false, - TexturePath = "${ASSETS}/circle.png", - CartesianPosition = { 0, 0, -2.1 }, - }; -assetHelper.registerScreenSpaceRenderables(asset, { spec }) +local id = "HoverCircle" + +local circle = { + Identifier = id, + Type = "ScreenSpaceImageLocal", + Name = "HoverCircle", + FaceCamera = false, + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome + Scale= 0.015, + Enabled = false, + TexturePath = "${ASSETS}/circle.png", + CartesianPosition = { 0, 0, -2.1 }, +}; + +asset.onInitialize(function () + openspace.addScreenSpaceRenderable(circle) + openspace.skybrowser.setHoverCircle(id) +end) + +asset.onDeinitialize(function () + openspace.removeScreenSpaceRenderable(circle) +end) + +asset.export("circle", {circle}) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 71ea59e3d7..ab765087ed 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -59,7 +59,7 @@ namespace openspace { void loadImages(const std::string& root, const std::string& directory, std::vector& speckFiles); int nLoadedImages() const; - const ImageData& getImage(const int i) const; + const ImageData& getImage(int i) const; private: diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 2a2f9affda..5935ef7991 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -57,6 +57,13 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "setHoverCircle", + &skybrowser::luascriptfunctions::setHoverCircle, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, { "moveCircleToHoverImage", &skybrowser::luascriptfunctions::moveCircleToHoverImage, @@ -209,15 +216,9 @@ namespace openspace { return res; } - - SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) { - // Find the hover circle - _hoverCircle = dynamic_cast( - global::renderEngine->screenSpaceRenderable("HoverCircle")); - // Set callback functions global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { @@ -499,7 +500,7 @@ void SkyBrowserModule::createTargetBrowserPair() { glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - //std::string localHostUrl = "http://localhost:8000"; + //std::string url = "http://localhost:8000"; const std::string browser = "{" "Identifier = '" + idBrowser + "'," @@ -575,42 +576,6 @@ void SkyBrowserModule::set3dBrowser(const std::string& id) } } -void SkyBrowserModule::selectImage2dBrowser(int i) -{ - Pair* selected = getPair(_selectedBrowser); - if (selected) { - - const ImageData& image = _dataHandler->getImage(i); - // Load image into browser - LINFO("Loading image " + image.name); - selected->selectImage(image, i); - - bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); - // If the coordinate is not in view, rotate camera - if (image.hasCelestialCoords) { - if(!isInView) { - startRotatingCamera( - skybrowser::equatorialToGalactic(image.equatorialCartesian) - ); - } - } - } -} - -void SkyBrowserModule::selectImage3dBrowser(int i) -{ - if (!_browser3dNode) { - return; - } - RenderableSkyBrowser* renderable = dynamic_cast( - _browser3dNode->renderable()); - if (renderable) { - const ImageData& image = _dataHandler->getImage(i); - renderable->displayImage(image.imageUrl, i); - } - -} - void SkyBrowserModule::lookAtTarget(std::string id) { Pair* pair = getPair(id); @@ -619,6 +584,11 @@ void SkyBrowserModule::lookAtTarget(std::string id) } } +void SkyBrowserModule::setHoverCircle(ScreenSpaceImageLocal* circle) +{ + _hoverCircle = circle; +} + void SkyBrowserModule::moveHoverCircle(int i) { const ImageData& image = _dataHandler->getImage(i); @@ -626,20 +596,20 @@ void SkyBrowserModule::moveHoverCircle(int i) // Only move and show circle if the image has coordinates if (_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem) { // Make circle visible - _hoverCircle->property("Enabled")->set(true); + _hoverCircle->setEnabled(true); // Calculate coords for the circle and translate glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace3d( image.equatorialCartesian ); - _hoverCircle->property("CartesianPosition")->set(coordsScreen); + _hoverCircle->setCartesianPosition(coordsScreen); } } void SkyBrowserModule::disableHoverCircle() { if (_hoverCircle && _hoverCircle->isEnabled()) { - _hoverCircle->property("Enabled")->set(false); + _hoverCircle->setEnabled(false); } } @@ -669,7 +639,7 @@ void SkyBrowserModule::add2dSelectedImagesTo3d(const std::string& pairId) } } -const std::unique_ptr& SkyBrowserModule::getWWTDataHandler() { +const std::unique_ptr& SkyBrowserModule::getWwtDataHandler() { return _dataHandler; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 500ee1efb5..9764582b95 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -61,18 +61,18 @@ public: SceneGraphNode* get3dBrowserNode(); RenderableSkyBrowser* get3dBrowser(); RenderableSkyBrowser* get3dBrowser(const std::string& id); - const std::unique_ptr& getWWTDataHandler(); + const std::unique_ptr& getWwtDataHandler(); std::string selectedBrowserId(); // Setters void set3dBrowser(const std::string& id); void setSelectedBrowser(const std::string& id); - void selectImage2dBrowser(int i); - void selectImage3dBrowser(int i); void setSelectedObject(); // Manage mouse interactions + void setHoverCircle(ScreenSpaceImageLocal* circle); // Rotation, animation, placement void lookAtTarget(std::string id); + void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate void incrementallyRotateCamera(double deltaTime); void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); void incrementallyAnimateTargets(double deltaTime); @@ -106,7 +106,7 @@ protected: private: - void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate + // The browsers and targets std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 7a6a2f38d0..1856c002a3 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -23,15 +23,47 @@ int selectImage(lua_State* L) { SkyBrowserModule* module = global::moduleEngine->module(); if (module->isCameraInSolarSystem()) { - module->selectImage2dBrowser(i); + Pair* selected = module->getPair(module->selectedBrowserId()); + if (selected) { + + const ImageData& image = module->getWwtDataHandler()->getImage(i); + // Load image into browser + LINFO("Loading image " + image.name); + selected->selectImage(image, i); + + bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); + // If the coordinate is not in view, rotate camera + if (image.hasCelestialCoords && !isInView) { + module->startRotatingCamera( + skybrowser::equatorialToGalactic(image.equatorialCartesian) + ); + } + } } - else { - module->selectImage3dBrowser(i); + else if (module->get3dBrowser()) { + RenderableSkyBrowser* renderable = dynamic_cast( + module->get3dBrowser()); + if (renderable) { + const ImageData& image = module->getWwtDataHandler()->getImage(i); + renderable->displayImage(image.imageUrl, i); + } } return 0; } +int setHoverCircle(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setHoverCircle"); + SkyBrowserModule* module = global::moduleEngine->module(); + std::string id = ghoul::lua::value(L, 1); + + ScreenSpaceImageLocal* circle = dynamic_cast( + global::renderEngine->screenSpaceRenderable(id)); + module->setHoverCircle(circle); + + return 0; +} + int moveCircleToHoverImage(lua_State* L) { // Load image ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); @@ -213,7 +245,7 @@ int getListOfImages(lua_State* L) { lua_newtable(L); for (int i = 0; i < module->nLoadedImages(); i++) { - const ImageData& img = module->getWWTDataHandler()->getImage(i); + const ImageData& img = module->getWwtDataHandler()->getImage(i); glm::dvec3 coords = img.equatorialCartesian; glm::dvec3 position = img.position3d; @@ -477,7 +509,7 @@ int place3dSkyBrowser(lua_State* L) { // Image index to place in 3D const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData image = module->getWWTDataHandler()->getImage(i); + const ImageData image = module->getWwtDataHandler()->getImage(i); module->place3dBrowser(image, i); @@ -491,7 +523,7 @@ int removeSelectedImageInBrowser(lua_State* L) { const std::string id = ghoul::lua::value(L, 1); // Get browser SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData& image = module->getWWTDataHandler()->getImage(i); + const ImageData& image = module->getWwtDataHandler()->getImage(i); Pair* pair = module->getPair(id); if (pair) { From fd58f9508ed975730014d91e11f46f5c08dcc65c Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 14:24:25 -0500 Subject: [PATCH 161/251] Make renderable sky browser not need to know about ImageData --- modules/skybrowser/include/renderableskybrowser.h | 9 +-------- modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/src/renderableskybrowser.cpp | 13 +++++-------- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index 448326d61b..f8664bf6f3 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -1,13 +1,9 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ -#include #include #include #include -#include -#include -#include #ifdef _MSC_VER #pragma warning (push) @@ -33,8 +29,6 @@ namespace ghoul::opengl { class Texture; } namespace openspace::documentation { struct Documentation; } -#pragma optimize("", off) - namespace openspace { class RenderableSkyBrowser : public RenderablePlane, public WwtCommunicator @@ -51,11 +45,10 @@ namespace openspace { void update(const UpdateData& data) override; // Set up initialization with wwt - void stopSyncingWwtView(); void setIdInBrowser(); // Place - void placeAt3dPosition(const ImageData& image); + void placeAt3dPosition(const glm::dvec3& positionSpeck, float verticalFov); private: diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 5935ef7991..02e2d62e12 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -712,7 +712,7 @@ void SkyBrowserModule::place3dBrowser(const ImageData& image, const int i) // If the image has a 3D position, add it to the scene graph if (image.has3dCoords && get3dBrowser()) { get3dBrowser()->displayImage(image.imageUrl, i); - get3dBrowser()->placeAt3dPosition(image); + get3dBrowser()->placeAt3dPosition(image.position3d, image.fov); } else { LINFO("Image has no 3D coordinate!"); diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 71e6fc21aa..88d6a4411b 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -98,17 +99,13 @@ namespace openspace { RenderablePlane::update(data); } - void RenderableSkyBrowser::stopSyncingWwtView() - { - - } - void RenderableSkyBrowser::setIdInBrowser() { WwtCommunicator::setIdInBrowser(identifier()); } - void RenderableSkyBrowser::placeAt3dPosition(const ImageData& image) + void RenderableSkyBrowser::placeAt3dPosition( + const glm::dvec3& positionSpeck, float verticalFov) { std::string renderableId = dynamic_cast( this)->renderable()->identifier(); @@ -117,7 +114,7 @@ namespace openspace { std::string positionUri = "Scene." + _identifier + ".Translation.Position"; std::string rotationUri = "Scene." + _identifier + ".Rotation.Rotation"; std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; - glm::dvec3 position = image.position3d * distanceconstants::Parsec; + glm::dvec3 position = positionSpeck * distanceconstants::Parsec; // Calculate the size of the plane with trigonometry // Calculate in equatorial coordinate system since the FOV is from Earth // /| @@ -126,7 +123,7 @@ namespace openspace { // \| glm::dvec3 j2000 = skybrowser::galacticToEquatorial(position); double adjacent = glm::length(j2000); - double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); + double opposite = 2 * adjacent * glm::tan(glm::radians(verticalFov * 0.5)); // Calculate rotation to make the plane face the solar system barycenter glm::dvec3 normal = glm::normalize(-position); From 9c160699fba31c2823e5d32a29a68e5ed6e638bf Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 14:25:32 -0500 Subject: [PATCH 162/251] Cleanup and make animation of FOV smoother --- modules/skybrowser/include/pair.h | 2 +- .../include/screenspaceskybrowser.h | 16 +++---- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- .../skybrowser/src/screenspaceskybrowser.cpp | 48 ++++++++++++------- .../skybrowser/src/screenspaceskytarget.cpp | 6 +-- 5 files changed, 43 insertions(+), 31 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index cd619e6632..6509d74ff0 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -38,7 +38,7 @@ class Pair { public: constexpr static const float FadeThreshold = 0.01f; - constexpr static const double AnimationThreshold = 0.0001f;; + constexpr static const double AnimationThreshold = 0.0001f; Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); Pair(Pair const&) = default; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 7de42f72a5..fad80755f8 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -1,21 +1,18 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ -#include -#include -#include #include +#include #include -#include -#include -#include -#include +#include namespace openspace { - //class ScreenSpaceSkyTarget; + class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator { public: + constexpr static const double FovThreshold = 0.001f; + // Constructor and destructor ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); ~ScreenSpaceSkyBrowser(); @@ -60,6 +57,8 @@ namespace openspace { void setIdInBrowser(); private: + properties::DoubleProperty _animationSpeed; + void bindTexture() override; // Flags @@ -68,7 +67,6 @@ namespace openspace { // Animation of browser float _endVfov{ 0.f }; - float _fovDiff{ 0.01f }; // Resizing of browser glm::vec2 _originalDimensions; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 1856c002a3..56ab2b2479 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -140,7 +140,7 @@ int loadImagesToWWT(lua_State* L) { else if (module->get3dBrowser(id)) { // Load Image collections - module->get3dBrowser(id)->stopSyncingWwtView(); + module->get3dBrowser(id)->setIsSyncedWithWwt(false); LINFO("Load images to " + module->get3dBrowser(id)->identifier()); module->get3dBrowser(id)->loadImageCollection(root); LINFO("Image collection loaded in " + module->get3dBrowser(id)->identifier()); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 669fa7c653..7e255245eb 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -28,6 +28,12 @@ namespace { "Vertical Field Of View", "The vertical field of view in degrees." }; + constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = + { + "AnimationSpeed", + "Field Of View Animation Speed", + "The factor which is multiplied with the animation of the field of view." + }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -36,6 +42,9 @@ namespace { // [[codegen::verbatim(BorderColorInfo.description)]] std::optional borderColor; + + // [[codegen::verbatim(AnimationSpeedInfo.description)]] + std::optional animationSpeed; }; #include "ScreenSpaceSkyBrowser_codegen.cpp" @@ -43,9 +52,23 @@ namespace { namespace openspace { + glm::ivec3 randomBorderColor() { + // Generate a random border color with sufficient lightness and a n + std::random_device rd; + // Hue is in the unit degrees [0, 360] + std::uniform_real_distribution hue(0.f, 360.f); + // Value in saturation are in the unit percent [0,1] + float value = 0.95f; // Brightness + float saturation = 0.5f; + glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); + glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); + return rgbColor; + } + ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) - : ScreenSpaceRenderable(dictionary), - WwtCommunicator(dictionary) + : ScreenSpaceRenderable(dictionary) + , WwtCommunicator(dictionary) + , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) { // Set a unique identifier std::string identifier; @@ -64,7 +87,7 @@ namespace openspace { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _verticalFov = p.verticalFov.value_or(_verticalFov); - _borderColor = p.borderColor.value_or(_borderColor); + _borderColor = p.borderColor.value_or(randomBorderColor()); addProperty(_url); addProperty(_dimensions); @@ -73,19 +96,9 @@ namespace openspace { addProperty(_borderColor); addProperty(_equatorialAim); + // Ensure that the browser is placed at the z-coordinate of the screen space plane glm::vec2 screenPosition = _cartesianPosition.value(); _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); - - // Generate a random border color with sufficient lightness and a n - std::random_device rd; - // Hue is in the unit degrees [0, 360] - std::uniform_real_distribution hue(0.f, 360.f); - // Value in saturation are in the unit percent [0,1] - float value = 0.95f; // Brightness - float saturation = 0.5f; - glm::vec3 hsvColor = glm::vec3(hue(rd), saturation , value); - glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor)*255.f); - _borderColor = rgbColor; } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { @@ -138,11 +151,12 @@ namespace openspace { void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { // If distance too large, keep animating. Else, stop animation - float diff = verticalFov() - _endVfov; - const bool shouldAnimate = abs(diff) > _fovDiff; + float diff = _endVfov - verticalFov(); + bool shouldAnimate = abs(diff) > FovThreshold; if (shouldAnimate) { - setVerticalFovWithScroll(diff); + float delta = _animationSpeed * (diff * deltaTime); + _verticalFov = std::clamp(_verticalFov + delta, 0.0001f, 70.0f); } else { _isFovAnimated = false; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 10283b0665..3b74fe6334 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -37,7 +37,7 @@ namespace { constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { "AnimationSpeed", - "Animation Speed", + "TrAnimation Speed", "The factor which is multiplied with the animation speed of the target." }; @@ -58,10 +58,10 @@ namespace { // [[codegen::verbatim(RectangleThresholdInfo.description)]] std::optional rectangleThreshold; - // [[codegen::verbatim(RectangleThresholdInfo.description)]] + // [[codegen::verbatim(AnimationSpeedInfo.description)]] std::optional animationSpeed; - // [[codegen::verbatim(RectangleThresholdInfo.description)]] + // [[codegen::verbatim(AnimationThresholdInfo.description)]] std::optional animationThreshold; }; From 696ee7f7e7fa1b8501a691db3b5dab432263851d Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 1 Dec 2021 14:40:31 -0500 Subject: [PATCH 163/251] Clean up includes --- modules/skybrowser/include/screenspaceskytarget.h | 3 +-- modules/skybrowser/include/wwtcommunicator.h | 5 ----- modules/skybrowser/include/wwtdatahandler.h | 9 --------- modules/skybrowser/skybrowsermodule.cpp | 12 +++++++++--- modules/skybrowser/skybrowsermodule.h | 13 +++++-------- modules/skybrowser/skybrowsermodule_lua.inl | 1 - modules/skybrowser/src/wwtdatahandler.cpp | 2 +- 7 files changed, 16 insertions(+), 29 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index b4fec5e27c..7c76816f3f 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -1,11 +1,10 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ +#include #include #include #include -#include -#include namespace openspace::documentation { struct Documentation; } diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index d47d7372c6..96237b1e40 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -31,16 +31,12 @@ #include #include #include -#include namespace openspace { -class ImageData; - class WwtCommunicator : public Browser { public: - WwtCommunicator(const ghoul::Dictionary& dictionary); WwtCommunicator(WwtCommunicator const&) = default; virtual ~WwtCommunicator(); @@ -80,7 +76,6 @@ protected: properties::DVec2Property _equatorialAim; properties::FloatProperty _verticalFov; properties::IVec3Property _borderColor; - std::deque _selectedImages; bool _hasLoadedImages{ false }; diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index ab765087ed..974ded0923 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -6,12 +6,6 @@ #include #include -// For speck loading -#include -#include -#include -#include - namespace openspace::documentation { struct Documentation; } namespace openspace::wwt { @@ -52,7 +46,6 @@ namespace openspace { class WwtDataHandler { public: - // Constructor and destructor WwtDataHandler() = default; ~WwtDataHandler(); @@ -62,7 +55,6 @@ namespace openspace { const ImageData& getImage(int i) const; private: - void saveImageFromNode(tinyxml2::XMLElement* node, std::string collection); void saveImagesFromXml(tinyxml2::XMLElement* root, std::string collection); @@ -73,7 +65,6 @@ namespace openspace { // 3D position data loaded from speck files std::unordered_map _3dPositions; - }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 02e2d62e12..736548efc8 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -27,7 +27,13 @@ #include #include +#include +#include +#include +#include #include "skybrowsermodule_lua.inl" +#include +#include #include #include #include @@ -710,9 +716,9 @@ void SkyBrowserModule::lookAt3dBrowser() { void SkyBrowserModule::place3dBrowser(const ImageData& image, const int i) { // If the image has a 3D position, add it to the scene graph - if (image.has3dCoords && get3dBrowser()) { - get3dBrowser()->displayImage(image.imageUrl, i); - get3dBrowser()->placeAt3dPosition(image.position3d, image.fov); + if (image.has3dCoords && _browser3d) { + _browser3d->displayImage(image.imageUrl, i); + _browser3d->placeAt3dPosition(image.position3d, image.fov); } else { LINFO("Image has no 3D coordinate!"); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 9764582b95..243682dbba 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -25,13 +25,7 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ - -#include -#include -#include -#include #include -#include #include #include #include @@ -39,6 +33,11 @@ namespace openspace { class RenderableSkyBrowser; +class ScreenSpaceImageLocal; +class WwtDataHandler; +class Pair; +class SceneGraphNode; +class ImageData; enum class Transparency { Transparent, @@ -105,8 +104,6 @@ protected: void internalDeinitialize() override; private: - - // The browsers and targets std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 56ab2b2479..220741f15c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index b8bf7e5516..91fceae7dc 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -1,7 +1,7 @@ #include #include - +#include #include // For downloading files from url #include #include From 57ff730851ae306463eef76dc714b56ff025a561 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 2 Dec 2021 11:29:21 -0500 Subject: [PATCH 164/251] Add property to lower resolution of texture of browser to increase performance --- .../include/screenspaceskybrowser.h | 6 +- .../skybrowser/src/screenspaceskybrowser.cpp | 57 ++++++++++++++++--- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index fad80755f8..9c747fb565 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace openspace { @@ -56,9 +57,12 @@ namespace openspace { glm::dvec2 fineTuneVector(glm::dvec2 drag); void setIdInBrowser(); + void updateTextureResolution(); + private: properties::DoubleProperty _animationSpeed; - + properties::FloatProperty _textureQuality; + void bindTexture() override; // Flags diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 7e255245eb..fca1471e4e 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -7,11 +7,12 @@ #include #include // formatJson #include -#include +#include // For hsv color #include #include +#include #pragma optimize("", off) namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -34,6 +35,14 @@ namespace { "Field Of View Animation Speed", "The factor which is multiplied with the animation of the field of view." }; + constexpr const openspace::properties::Property::PropertyInfo TextureQualityInfo = + { + "TextureQuality", + "Quality of Texture", + "A parameter to set the resolution of the texture. 1 is full resolution and " + "slower framerate. Lower value means lower resolution of texture and faster " + "frame rate." + }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -45,6 +54,9 @@ namespace { // [[codegen::verbatim(AnimationSpeedInfo.description)]] std::optional animationSpeed; + + // [[codegen::verbatim(TextureQualityInfo.description)]] + std::optional textureQuality; }; #include "ScreenSpaceSkyBrowser_codegen.cpp" @@ -69,6 +81,7 @@ namespace openspace { : ScreenSpaceRenderable(dictionary) , WwtCommunicator(dictionary) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) + , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) { // Set a unique identifier std::string identifier; @@ -88,6 +101,7 @@ namespace openspace { const Parameters p = codegen::bake(dictionary); _verticalFov = p.verticalFov.value_or(_verticalFov); _borderColor = p.borderColor.value_or(randomBorderColor()); + _textureQuality = p.textureQuality.value_or(_textureQuality); addProperty(_url); addProperty(_dimensions); @@ -95,6 +109,11 @@ namespace openspace { addProperty(_verticalFov); addProperty(_borderColor); addProperty(_equatorialAim); + addProperty(_textureQuality); + + _textureQuality.onChange([this]() { + updateTextureResolution(); + }); // Ensure that the browser is placed at the z-coordinate of the screen space plane glm::vec2 screenPosition = _cartesianPosition.value(); @@ -109,6 +128,7 @@ namespace openspace { Browser::initializeGL(); ScreenSpaceRenderable::initializeGL(); + updateTextureResolution(); return true; } @@ -131,6 +151,21 @@ namespace openspace { WwtCommunicator::setIdInBrowser(identifier()); } + void ScreenSpaceSkyBrowser::updateTextureResolution() + { + + // Scale texture depending on the height of the window + // Set texture size to the actual pixel size it covers + glm::vec2 pixels = glm::vec2(global::windowDelegate->currentSubwindowSize()); + glm::vec2 browserDim = screenSpaceDimensions(); + float newResY = pixels.y * browserDim.y; + float newResX = newResY * (_dimensions.value().x / _dimensions.value().y); + glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value(); + + _dimensions = glm::ivec2(newSize); + _texture->setDimensions(glm::ivec3(newSize, 1)); + } + bool ScreenSpaceSkyBrowser::deinitializeGL() { ScreenSpaceRenderable::deinitializeGL(); Browser::deinitializeGL(); @@ -176,11 +211,12 @@ namespace openspace { void ScreenSpaceSkyBrowser::update() { - _objectSize = _texture->dimensions(); - if (global::windowDelegate->windowHasResized()) { - // change the resolution of the texture + // Change the resolution of the texture + updateTextureResolution(); } + + _objectSize = _texture->dimensions(); WwtCommunicator::update(); ScreenSpaceRenderable::update(); @@ -225,6 +261,11 @@ namespace openspace { return resizePosition; } + + void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { + _scale = _originalScale * scalingFactor; + } + // Scales the ScreenSpaceBrowser to a new ratio void ScreenSpaceSkyBrowser::setScale(glm::vec2 scalingFactor) { @@ -251,8 +292,8 @@ namespace openspace { } void ScreenSpaceSkyBrowser::saveResizeStartSize() { - _originalDimensions = _dimensions.value(); - _originalScale = _scale.value(); + _originalDimensions = _dimensions; + _originalScale = _scale; } void ScreenSpaceSkyBrowser::setCallbackEquatorialAim( @@ -291,9 +332,7 @@ namespace openspace { f(_enabled); }); } - void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { - _scale = _originalScale * scalingFactor; - } + void ScreenSpaceSkyBrowser::setOpacity(float opacity) { From 816b394dc946701b395dcbcbfe3bf8ffaf3f2b23 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 2 Dec 2021 11:29:57 -0500 Subject: [PATCH 165/251] Set selection of target/browser in the Pair class instead of the module --- .../rendering/screenspacerenderable.h | 2 +- modules/skybrowser/include/pair.h | 11 ++- modules/skybrowser/skybrowsermodule.cpp | 80 +++++++------------ modules/skybrowser/skybrowsermodule.h | 2 - modules/skybrowser/src/pair.cpp | 30 +++++-- .../skybrowser/src/screenspaceskybrowser.cpp | 4 +- src/rendering/screenspacerenderable.cpp | 2 +- 7 files changed, 66 insertions(+), 65 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index bfa41ee975..311a8b8318 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -78,7 +78,7 @@ public: glm::vec2 screenSpaceDimensions(); glm::vec2 upperRightCornerScreenSpace(); glm::vec2 lowerLeftCornerScreenSpace(); - bool coordIsInsideCornersScreenSpace(glm::vec2 coord); + bool intersection(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); friend bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs); void setCartesianPosition(const glm::vec3& position); diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 6509d74ff0..2465c6587e 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -32,6 +32,7 @@ namespace openspace { class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget; +class ScreenSpaceRenderable; class ImageData; class Pair { @@ -54,6 +55,10 @@ public: void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(double deltaTime); void incrementallyFade(float goalState, float fadeTime, float deltaTime); + // Mouse interaction + bool checkMouseIntersection(glm::vec2 mousePosition); + glm::vec2 selectedScreenSpacePosition(); + bool isSelectedBrowser(); // Browser void sendIdToBrowser(); @@ -66,7 +71,7 @@ public: // Boolean functions bool hasFinishedFading(float goalState) const; - bool isCoordOnPair(glm::vec2 mousePosition) const; + bool isEnabled() const; bool isLocked() const; @@ -102,7 +107,9 @@ public: const Pair& rhs); private: - static std::string _selected; + ScreenSpaceRenderable* _selected; + bool _isSelectedBrowser; + bool isTargetFadeFinished(float goalState) const; bool isBrowserFadeFinished(float goalState) const; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 736548efc8..4d0a00f10d 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -232,22 +232,15 @@ SkyBrowserModule::SkyBrowserModule() if (_mouseOnPair && action == MouseAction::Press) { // Get the currently selected browser - setSelectedBrowser(_mouseOnPair->getBrowser()->identifier()); + setSelectedBrowser(_mouseOnPair->browserId()); if (button == MouseButton::Left) { _isCameraRotating = false; _startMousePosition = _mousePosition; - if (_isBrowser) { - _startDragPosition = _mouseOnPair->getBrowser()-> - screenSpacePosition(); - } - else { - _startDragPosition = _mouseOnPair->getTarget()-> - screenSpacePosition(); - } + _startDragPosition = _mouseOnPair->selectedScreenSpacePosition(); // If current object is browser, check for resizing - if (_isBrowser) { + if (_mouseOnPair->isSelectedBrowser()) { // Resize browser if mouse is over resize button _resizeDirection = _mouseOnPair->getBrowser()->isOnResizeArea( _mousePosition @@ -268,7 +261,8 @@ SkyBrowserModule::SkyBrowserModule() return true; } - else if (_isBrowser && button == MouseButton::Right) { + // Fine tuning mode of target + else if (_mouseOnPair->isSelectedBrowser() && button == MouseButton::Right) { // If you start dragging around on the browser, the target unlocks _mouseOnPair->unlock(); // Change view (by moving target) within browser if right mouse @@ -309,26 +303,27 @@ SkyBrowserModule::SkyBrowserModule() _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); glm::vec2 translation = _mousePosition - _startMousePosition; + if (_isResizing) { + // Calculate scaling factor + glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); + glm::vec2 scaling = mouseDragVector * glm::vec2(_resizeDirection); + glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / + _startBrowserSize; + // Scale the browser + _mouseOnPair->getBrowser()->setScale(newSizeRelToOld); + + // For dragging functionality, translate so it looks like the + // browser isn't moving. Make sure the browser doesn't move in + // directions it's not supposed to + translation = 0.5f * mouseDragVector * abs( + glm::vec2(_resizeDirection) + ); + + } if (_isDragging || _isResizing) { - if (_isResizing) { - // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition-_startMousePosition); - glm::vec2 scaling = mouseDragVector * glm::vec2(_resizeDirection); - glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / - _startBrowserSize; - // Scale the browser - _mouseOnPair->getBrowser()->setScale(newSizeRelToOld); - - // For dragging functionality, translate so it looks like the - // browser isn't moving. Make sure the browser doesn't move in - // directions it's not supposed to - translation = 0.5f * mouseDragVector * abs( - glm::vec2(_resizeDirection) - ); - - } + // Translate - if (_isBrowser) { + if (_mouseOnPair->isSelectedBrowser()) { _mouseOnPair->getBrowser()->translate( translation, _startDragPosition @@ -375,9 +370,8 @@ SkyBrowserModule::SkyBrowserModule() global::callback::preSync->emplace_back([this]() { // Disable browser and targets when camera is outside of solar system - glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); - double deltaTime = global::windowDelegate->deltaTime(); bool camWasInSolarSystem = _isCameraInSolarSystem; + glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); _isCameraInSolarSystem = glm::length(cameraPos) < SolarSystemRadius; // Fading flags @@ -389,7 +383,7 @@ SkyBrowserModule::SkyBrowserModule() _selectedBrowser = _browser3dNode->renderable()->identifier(); } } - + double deltaTime = global::windowDelegate->deltaTime(); // Fade pairs if the camera moved in or out the solar system if (_isTransitioningVizMode) { if (_isCameraInSolarSystem) { @@ -441,23 +435,12 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { void SkyBrowserModule::setSelectedObject() { // Save old selection for removing highlight - Pair* lastObj = _mouseOnPair; + Pair* previousPair = _mouseOnPair; // Find and save what mouse is currently hovering on auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&] (const std::unique_ptr &pair) { - bool onBrowser = pair->getBrowser()->coordIsInsideCornersScreenSpace( - _mousePosition - ); - bool onTarget = pair->getTarget()->coordIsInsideCornersScreenSpace( - _mousePosition - ); - if (onBrowser) { - _selectedBrowser = pair->getBrowser()->identifier(); - } - _isBrowser = onBrowser; - - return onBrowser || onTarget; + return pair->checkMouseIntersection(_mousePosition); }); if (it == std::end(_targetsBrowsers)) { @@ -468,17 +451,16 @@ void SkyBrowserModule::setSelectedObject() } // Selection has changed - if (lastObj != _mouseOnPair) { + if (previousPair != _mouseOnPair) { // Remove highlight - if (lastObj) { - lastObj->removeHighlight(_highlightAddition); + if (previousPair) { + previousPair->removeHighlight(_highlightAddition); } // Add highlight to new selection if (_mouseOnPair) { _mouseOnPair->highlight(_highlightAddition); } - } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 243682dbba..5135aa1be8 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -107,8 +107,6 @@ private: // The browsers and targets std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; - Pair* _selectedPair{ nullptr }; - bool _isBrowser{ false }; ScreenSpaceImageLocal* _hoverCircle{ nullptr }; SceneGraphNode* _browser3dNode{ nullptr }; RenderableSkyBrowser* _browser3d{ nullptr }; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 7494d5349a..57ca5f2e30 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -36,8 +37,6 @@ namespace openspace { - std::string Pair::_selected = ""; // Define the static variable in the global scope - Pair::Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) : _target(target), _browser(browser) { @@ -144,20 +143,35 @@ namespace openspace { return browserDiff < FadeThreshold; } - bool Pair::isCoordOnPair(glm::vec2 mousePosition) const + bool Pair::checkMouseIntersection(glm::vec2 mousePosition) { - const bool onBrowser = _browser->coordIsInsideCornersScreenSpace(mousePosition); - const bool onTarget = _target->coordIsInsideCornersScreenSpace(mousePosition); + bool onBrowser = _browser->intersection(mousePosition); + bool onTarget = _target->intersection(mousePosition); if (onBrowser) { - _selected = _browser->identifier(); + _selected = _browser; + _isSelectedBrowser = true; } else if (onTarget) { - _selected = _target->identifier(); + _selected = _target; + _isSelectedBrowser = false; + } + else { + _selected = nullptr; + _isSelectedBrowser = false; } - return onBrowser || onTarget; } + glm::vec2 Pair::selectedScreenSpacePosition() + { + return _selected->screenSpacePosition(); + } + + bool Pair::isSelectedBrowser() + { + return _isSelectedBrowser; + } + void Pair::setEnabled(bool enable) { _browser->setEnabled(enable); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index fca1471e4e..96e15bbfd7 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -89,7 +89,7 @@ namespace openspace { identifier = dictionary.value(KeyIdentifier); } else { - identifier = "ScreenSpaceSkyBrowser22"; + identifier = "ScreenSpaceSkyBrowser"; } identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); @@ -245,7 +245,7 @@ namespace openspace { glm::ivec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { glm::ivec2 resizePosition = glm::ivec2{ 0 }; // Make sure coordinate is on browser - if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition; + if (!intersection(coord)) return resizePosition; // TO DO: turn this into a vector and use prettier vector arithmetic float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index a4f7686855..10d46d1cd3 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -530,7 +530,7 @@ glm::vec2 ScreenSpaceRenderable::lowerLeftCornerScreenSpace() { return screenSpacePosition() - (screenSpaceDimensions() / 2.0f); } -bool ScreenSpaceRenderable::coordIsInsideCornersScreenSpace(glm::vec2 coord) { +bool ScreenSpaceRenderable::intersection(glm::vec2 coord) { bool lessThanUpperRight = coord.x < upperRightCornerScreenSpace().x && coord.y < upperRightCornerScreenSpace().y; bool moreThanLowerLeft = coord.x > lowerLeftCornerScreenSpace().x && coord.y > lowerLeftCornerScreenSpace().y; return lessThanUpperRight && moreThanLowerLeft; From 79e85c36dd23fb33f5451fc3cac7874d66d3c847 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 2 Dec 2021 11:55:21 -0500 Subject: [PATCH 166/251] Set max with to 90 columns --- .../rendering/screenspacerenderable.h | 1 - modules/skybrowser/include/utility.h | 10 +++++--- modules/skybrowser/skybrowsermodule.cpp | 7 +++--- modules/skybrowser/src/pair.cpp | 3 ++- .../skybrowser/src/screenspaceskytarget.cpp | 6 +++-- src/rendering/screenspacerenderable.cpp | 25 +++++++++++-------- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 311a8b8318..a7e5a7207d 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -80,7 +80,6 @@ public: glm::vec2 lowerLeftCornerScreenSpace(); bool intersection(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); - friend bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs); void setCartesianPosition(const glm::vec3& position); // End of addition by skybrowser team diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index a6086ce13e..1ba7ddc502 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -46,12 +46,14 @@ namespace openspace { // Window and field of view float windowRatio(); glm::dvec2 fovWindow(); - bool isCoordinateInView(const glm::dvec3& equatorial); + bool isCoordinateInView(const glm::dvec3& equatorial); // Animation for target and camera - double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); - glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, - double deltaTime, double speedFactor = 1.0); + double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); + glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, + const glm::dvec3& end, + double deltaTime, + double speedFactor = 1.0); } } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 4d0a00f10d..b5b2a354e7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -262,7 +262,8 @@ SkyBrowserModule::SkyBrowserModule() return true; } // Fine tuning mode of target - else if (_mouseOnPair->isSelectedBrowser() && button == MouseButton::Right) { + else if (_mouseOnPair->isSelectedBrowser() && + button == MouseButton::Right) { // If you start dragging around on the browser, the target unlocks _mouseOnPair->unlock(); // Change view (by moving target) within browser if right mouse @@ -717,9 +718,9 @@ void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleBetweenVectors(_startAnimation, _endAnimation); + double angle = skybrowser::angleBetweenVectors(_startAnimation, _endAnimation); - if(smallestAngle > _stopAnimationThreshold) { + if(angle > _stopAnimationThreshold) { glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( _startAnimation, diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 57ca5f2e30..97cc6adb4d 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -290,7 +290,8 @@ namespace openspace { } } - void Pair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, bool shouldLockAfter) + void Pair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, + bool shouldLockAfter) { _target->startAnimation(equatorialCoords, shouldLockAfter); _browser->startFovAnimation(fovEnd); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 3b74fe6334..1cf1c63ee3 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -250,7 +250,8 @@ namespace openspace { return _isAnimated; } - void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, bool shouldLockAfter) + void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, + bool shouldLockAfter) { _animationStart = glm::normalize(equatorialAim()); _animationEnd = glm::normalize(equatorialCoordsEnd); @@ -285,8 +286,9 @@ namespace openspace { _animationStart = glm::normalize(equatorialAim()); } else { + glm::dvec3 screenSpace = skybrowser::equatorialToScreenSpace3d(_animationEnd); // Set the exact target position - _cartesianPosition = glm::vec3(skybrowser::equatorialToScreenSpace3d(_animationEnd)); + _cartesianPosition = glm::vec3(screenSpace); _isAnimated = false; // Lock target when it first arrives to the position setLock(_shouldLockAfterAnimation); diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 10d46d1cd3..85000de3dd 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -519,7 +519,8 @@ glm::vec2 ScreenSpaceRenderable::screenSpacePosition() { } glm::vec2 ScreenSpaceRenderable::screenSpaceDimensions() { - return glm::vec2(2.f * _scale * static_cast(_objectSize.x) / static_cast(_objectSize.y), 2.f * _scale); + float ratio = static_cast(_objectSize.x) / static_cast(_objectSize.y); + return glm::vec2(2.f * _scale * ratio, 2.f * _scale); } glm::vec2 ScreenSpaceRenderable::upperRightCornerScreenSpace() { @@ -531,13 +532,22 @@ glm::vec2 ScreenSpaceRenderable::lowerLeftCornerScreenSpace() { } bool ScreenSpaceRenderable::intersection(glm::vec2 coord) { - bool lessThanUpperRight = coord.x < upperRightCornerScreenSpace().x && coord.y < upperRightCornerScreenSpace().y; - bool moreThanLowerLeft = coord.x > lowerLeftCornerScreenSpace().x && coord.y > lowerLeftCornerScreenSpace().y; - return lessThanUpperRight && moreThanLowerLeft; + bool isUnderTopBorder = coord.x < upperRightCornerScreenSpace().x; + bool isLeftToRightBorder = coord.y < upperRightCornerScreenSpace().y; + bool isRightToLeftBorder = coord.x > lowerLeftCornerScreenSpace().x; + bool isOverBottomBorder = coord.y > lowerLeftCornerScreenSpace().y; + + return isUnderTopBorder && isLeftToRightBorder && + isRightToLeftBorder && isOverBottomBorder; } void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) { - _cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, _cartesianPosition.value().z, 1.0f); + glm::mat4 translationMatrix = glm::translate( + glm::mat4(1.f), + glm::vec3(translation, 0.0f) + ); + glm::vec4 origin = glm::vec4(position, _cartesianPosition.value().z, 1.0f); + _cartesianPosition = translationMatrix * origin; } void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) @@ -545,11 +555,6 @@ void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) _cartesianPosition = position; } -bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs) { - // Sort on depth coordinate, larger values are closer to camera - return lhs._cartesianPosition.value().z > rhs._cartesianPosition.value().z; -} - glm::mat4 ScreenSpaceRenderable::globalRotationMatrix() { // We do not want the screen space planes to be affected by // 1) The global rotation of the view applied in the render engine From 148b68123c0811a9470a358dc843a59e989e75c2 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 2 Dec 2021 14:22:28 -0500 Subject: [PATCH 167/251] Fix bugs with 3D browser --- modules/skybrowser/skybrowsermodule.h | 2 +- .../skybrowser/src/renderableskybrowser.cpp | 32 +++++++++++++------ modules/skybrowser/src/wwtdatahandler.cpp | 1 + 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 5135aa1be8..85b9226ae7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -108,7 +108,7 @@ private: std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; ScreenSpaceImageLocal* _hoverCircle{ nullptr }; - SceneGraphNode* _browser3dNode{ nullptr }; + SceneGraphNode* _browser3dNode{ nullptr }; // Scene graph node is used for positioning RenderableSkyBrowser* _browser3d{ nullptr }; std::string _selectedBrowser{ "" }; // Currently selected browser (2D or 3D) diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 88d6a4411b..e2c63e4776 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -84,35 +84,41 @@ namespace openspace { } void RenderableSkyBrowser::initializeGL() { - Browser::initializeGL(); + WwtCommunicator::initializeGL(); RenderablePlane::initializeGL(); } void RenderableSkyBrowser::deinitializeGL() { RenderablePlane::deinitializeGL(); - Browser::deinitializeGL(); + WwtCommunicator::deinitializeGL(); } void RenderableSkyBrowser::update(const UpdateData& data) { - Browser::update(); + WwtCommunicator::update(); RenderablePlane::update(data); } + void RenderableSkyBrowser::render(const RenderData& data, RendererTasks& rendererTask) + { + glDisable(GL_CULL_FACE); + WwtCommunicator::render(); + RenderablePlane::render(data, rendererTask); + } + void RenderableSkyBrowser::setIdInBrowser() { WwtCommunicator::setIdInBrowser(identifier()); } void RenderableSkyBrowser::placeAt3dPosition( - const glm::dvec3& positionSpeck, float verticalFov) + const glm::dvec3& positionSpeck, float verticalFov, + const std::string& sceneGraphNodeId) { - std::string renderableId = dynamic_cast( - this)->renderable()->identifier(); // Uris for properties - std::string sizeUri = "Scene." + _identifier + "." + renderableId + ".Size"; - std::string positionUri = "Scene." + _identifier + ".Translation.Position"; - std::string rotationUri = "Scene." + _identifier + ".Rotation.Rotation"; + std::string sizeUri = "Scene." + sceneGraphNodeId + "." + _identifier + ".Size"; + std::string positionUri = "Scene." + sceneGraphNodeId + ".Translation.Position"; + std::string rotationUri = "Scene." + sceneGraphNodeId + ".Rotation.Rotation"; std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; glm::dvec3 position = positionSpeck * distanceconstants::Parsec; // Calculate the size of the plane with trigonometry @@ -152,4 +158,12 @@ namespace openspace { scripting::ScriptEngine::RemoteScripting::Yes ); } + void RenderableSkyBrowser::bindTexture() + { + _texture->bind(); + } + void RenderableSkyBrowser::unbindTexture() + { + + } } // namespace diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 91fceae7dc..a2d615c43e 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -355,6 +355,7 @@ namespace openspace { position3d = it->second; has3dCoords = true; _nMatched3dPositions++; + LINFO("3d position was found for " + name); } ImageData image = { From f5721cee1423a7697c49776e0ab6fb6af5a156ae Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 2 Dec 2021 14:55:15 -0500 Subject: [PATCH 168/251] Fix bugs with 3D browser scale and place synchronization of the target and browser in the targets update function --- .../skybrowser/include/renderableskybrowser.h | 7 ++- .../include/screenspaceskybrowser.h | 2 +- .../skybrowser/include/screenspaceskytarget.h | 8 +++ modules/skybrowser/include/wwtcommunicator.h | 13 +++-- modules/skybrowser/skybrowsermodule.cpp | 3 +- modules/skybrowser/skybrowsermodule_lua.inl | 10 ++-- modules/skybrowser/src/pair.cpp | 20 +------- .../skybrowser/src/renderableskybrowser.cpp | 5 +- .../skybrowser/src/screenspaceskybrowser.cpp | 6 +-- .../skybrowser/src/screenspaceskytarget.cpp | 25 ++++++++- modules/skybrowser/src/wwtcommunicator.cpp | 51 +++++++++++-------- 11 files changed, 88 insertions(+), 62 deletions(-) diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h index f8664bf6f3..3732da88db 100644 --- a/modules/skybrowser/include/renderableskybrowser.h +++ b/modules/skybrowser/include/renderableskybrowser.h @@ -43,15 +43,18 @@ namespace openspace { void initializeGL() override; void deinitializeGL() override; void update(const UpdateData& data) override; + void render(const RenderData& data, RendererTasks& rendererTask) override; // Set up initialization with wwt void setIdInBrowser(); // Place - void placeAt3dPosition(const glm::dvec3& positionSpeck, float verticalFov); + void placeAt3dPosition(const glm::dvec3& positionSpeck, float verticalFov, + const std::string& sceneGraphNodeId); private: - + void bindTexture() override; + void unbindTexture() override; }; } diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 9c747fb565..066b7c8555 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -80,7 +80,7 @@ namespace openspace { // Time variables // For capping the calls onchange properties from scrolling constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; - std::chrono::system_clock::time_point _lastUpdateTime; + std::chrono::system_clock::time_point _lastUpdateTime; }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 7c76816f3f..e0ac9abb58 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -42,6 +42,7 @@ namespace openspace { // Set callbacks void setCallbackEnabled(std::function function); void setCallbackPosition(std::function function); + void setSkyBrowser(ScreenSpaceSkyBrowser* browser); // Target directions glm::dvec3 directionGalactic() const; @@ -84,6 +85,7 @@ namespace openspace { // Sky browser glm::ivec3 _color; + ScreenSpaceSkyBrowser* _browser{ nullptr }; float _verticalFov{ 0.f }; // Lock target to a coordinate on the sky @@ -93,6 +95,12 @@ namespace openspace { glm::dvec3 _animationEnd; // Cartesian equatorial coordinates glm::dvec3 _animationStart; // Cartesian equatorial coordinates + // Time variables + // For capping the set equatorial coordinates to sky browser + const std::chrono::microseconds interval = std::chrono::microseconds(10000); + std::chrono::time_point latestCall; + constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; + std::chrono::system_clock::time_point _lastUpdateTime; }; } diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 96237b1e40..2d01a19a99 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -41,13 +41,17 @@ public: WwtCommunicator(WwtCommunicator const&) = default; virtual ~WwtCommunicator(); + void update(); + void render(); + void initializeGL(); + void deinitializeGL(); + // WorldWide Telescope communication void displayImage(const std::string& url, int i); void removeSelectedImage(const int i); void setImageOrder(int i, int order); void loadImageCollection(const std::string& collection); void setImageOpacity(int i, float opacity); - void update(); // Getters const std::deque& getSelectedImages(); @@ -67,6 +71,7 @@ public: void highlight(glm::ivec3 addition); void removeHighlight(glm::ivec3 removal); void updateBorderColor(); + void updateAim(); protected: @@ -82,16 +87,14 @@ protected: private: bool _isSyncedWithWwt{ false }; - const std::chrono::microseconds interval = std::chrono::microseconds(10000); - std::chrono::time_point latestCall; void setWebpageBorderColor(glm::ivec3 color); void sendMessageToWwt(const ghoul::Dictionary& msg); int messageCounter{ 0 }; - ghoul::Dictionary moveCamera(const glm::dvec2& celestCoords, const double fov, - const double roll, const bool shouldMoveInstantly = true); + ghoul::Dictionary moveCamera(const glm::dvec2& celestCoords, double fov, + double roll, bool shouldMoveInstantly = true); ghoul::Dictionary loadCollection(const std::string& url); ghoul::Dictionary setForeground(const std::string& name); ghoul::Dictionary addImage(const std::string& id, const std::string& url); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index b5b2a354e7..57c434196e 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -701,7 +701,8 @@ void SkyBrowserModule::place3dBrowser(const ImageData& image, const int i) // If the image has a 3D position, add it to the scene graph if (image.has3dCoords && _browser3d) { _browser3d->displayImage(image.imageUrl, i); - _browser3d->placeAt3dPosition(image.position3d, image.fov); + _browser3d->placeAt3dPosition(image.position3d, image.fov, + _browser3dNode->identifier()); } else { LINFO("Image has no 3D coordinate!"); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 220741f15c..24ce84f007 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -40,12 +40,10 @@ int selectImage(lua_State* L) { } } else if (module->get3dBrowser()) { - RenderableSkyBrowser* renderable = dynamic_cast( - module->get3dBrowser()); - if (renderable) { - const ImageData& image = module->getWwtDataHandler()->getImage(i); - renderable->displayImage(image.imageUrl, i); - } + const ImageData& image = module->getWwtDataHandler()->getImage(i); + module->get3dBrowser()->displayImage(image.imageUrl, i); + module->get3dBrowser()->setEquatorialAim(image.equatorialCartesian); + module->get3dBrowser()->setVerticalFov(image.fov); } return 0; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 97cc6adb4d..b8d7baff52 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -77,24 +77,8 @@ namespace openspace { } ); - // Set target callback functions - _target->setCallbackEnabled( - [&](bool enabled) { - _browser->setEnabled(enabled); - } - ); - _target->setCallbackPosition( - [&](glm::vec3 localCameraPosition) { - double diff = glm::length( - _browser->equatorialAim() - _target->equatorialAim() - ); - if (diff > AnimationThreshold) { - _browser->setEquatorialAim( - skybrowser::localCameraToEquatorial(localCameraPosition) - ); - } - } - ); + _target->setSkyBrowser(_browser); + } Pair& Pair::operator=(Pair other) diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index e2c63e4776..2c1dec682a 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -127,8 +127,7 @@ namespace openspace { // /_| Adjacent is the horizontal line, opposite the vertical // \ | Calculate for half the triangle first, then multiply with 2 // \| - glm::dvec3 j2000 = skybrowser::galacticToEquatorial(position); - double adjacent = glm::length(j2000); + double adjacent = glm::length(position); double opposite = 2 * adjacent * glm::tan(glm::radians(verticalFov * 0.5)); // Calculate rotation to make the plane face the solar system barycenter @@ -137,7 +136,7 @@ namespace openspace { glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) ); glm::dvec3 newUp = glm::cross(normal, newRight); - // Face the Solar System Barycenter + // Face the Solar System Barycenter as an approximation of Earth glm::dmat3 rotation = glm::dmat3(1.0); rotation[0] = newRight; rotation[1] = newUp; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 96e15bbfd7..2c52ef8ea8 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -126,7 +126,7 @@ namespace openspace { bool ScreenSpaceSkyBrowser::initializeGL() { - Browser::initializeGL(); + WwtCommunicator::initializeGL(); ScreenSpaceRenderable::initializeGL(); updateTextureResolution(); return true; @@ -168,7 +168,7 @@ namespace openspace { bool ScreenSpaceSkyBrowser::deinitializeGL() { ScreenSpaceRenderable::deinitializeGL(); - Browser::deinitializeGL(); + WwtCommunicator::deinitializeGL(); return true; } @@ -199,7 +199,7 @@ namespace openspace { } void ScreenSpaceSkyBrowser::render() { - Browser::render(); + WwtCommunicator::render(); draw( globalRotationMatrix() * diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 1cf1c63ee3..adb51f5218 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -211,6 +212,22 @@ namespace openspace { _lockedCoordinates ); } + if (_browser) { + const std::chrono::time_point + timeBefore = std::chrono::high_resolution_clock::now(); + + std::chrono::microseconds duration = + std::chrono::duration_cast( + timeBefore - latestCall + ); + + if (duration > interval) { + // Message WorldWide Telescope current view + _browser->setEquatorialAim(equatorialAim()); // Use camera roll + + latestCall = std::chrono::high_resolution_clock::now(); + } + } } void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { @@ -230,7 +247,6 @@ namespace openspace { // Update the scale of the target (the height of the target in relation to the // OpenSpace window) void ScreenSpaceSkyTarget::setScaleFromVfov(float verticalFov) { - _verticalFov = verticalFov; glm::dvec2 fovs = skybrowser::fovWindow(); @@ -339,4 +355,11 @@ namespace openspace { f(_cartesianPosition); }); } + void ScreenSpaceSkyTarget::setSkyBrowser(ScreenSpaceSkyBrowser* browser) + { + _browser = browser; + _enabled.onChange([this]() { + _browser->setEnabled(_enabled); + }); + } } diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 72a4e8fce4..5d6e9f5b6e 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -111,6 +111,7 @@ namespace openspace { void WwtCommunicator::setVerticalFov(float vfov) { _verticalFov = vfov; + updateAim(); } void WwtCommunicator::setWebpageBorderColor(glm::ivec3 color) { @@ -129,6 +130,7 @@ namespace openspace { void WwtCommunicator::setEquatorialAim(glm::dvec3 cartesian) { _equatorialAim = skybrowser::cartesianToSpherical(cartesian); + updateAim(); } void WwtCommunicator::highlight(glm::ivec3 addition) @@ -146,6 +148,18 @@ namespace openspace { setWebpageBorderColor(_borderColor); } + void WwtCommunicator::updateAim() + { + double roll = _isSyncedWithWwt ? skybrowser::cameraRoll() : 0.0; + // Message WorldWide Telescope current view + ghoul::Dictionary message = moveCamera( + _equatorialAim, + _verticalFov, + roll + ); + sendMessageToWwt(message); + } + glm::dvec2 WwtCommunicator::fieldsOfView() { glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio(), verticalFov()); @@ -194,31 +208,24 @@ namespace openspace { void WwtCommunicator::update() { - if (_isSyncedWithWwt) { - const std::chrono::time_point - timeBefore = std::chrono::high_resolution_clock::now(); - - std::chrono::microseconds duration = - std::chrono::duration_cast( - timeBefore - latestCall - ); - - if (duration > interval) { - // Message WorldWide Telescope current view - ghoul::Dictionary message = moveCamera( - _equatorialAim, - _verticalFov, - skybrowser::cameraRoll() - ); - sendMessageToWwt(message); - - latestCall = std::chrono::high_resolution_clock::now(); - } - } - Browser::update(); } + void WwtCommunicator::render() + { + Browser::render(); + } + + void WwtCommunicator::initializeGL() + { + Browser::initializeGL(); + } + + void WwtCommunicator::deinitializeGL() + { + Browser::deinitializeGL(); + } + void WwtCommunicator::setHasLoadedImages(bool isLoaded) { _hasLoadedImages = isLoaded; } From 7a0529b6d1efd9f410cc6209d810e30b21476636 Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 3 Dec 2021 13:36:20 -0500 Subject: [PATCH 169/251] Fix of hard crash when having a large screenspaceskybrowser and animating camera --- modules/skybrowser/include/screenspaceskytarget.h | 2 ++ modules/skybrowser/src/screenspaceskytarget.cpp | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index e0ac9abb58..00199bd6f1 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -15,6 +15,8 @@ namespace openspace { class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { public: + constexpr static const float DeltaTimeThreshold = 0.03f; + // Constructor & destructor ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); virtual ~ScreenSpaceSkyTarget(); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index adb51f5218..52bdb91956 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -212,7 +212,8 @@ namespace openspace { _lockedCoordinates ); } - if (_browser) { + // Optimization: Only pass messages to the browser when the target is not moving + if (_browser && !_isAnimated) { const std::chrono::time_point timeBefore = std::chrono::high_resolution_clock::now(); @@ -278,13 +279,15 @@ namespace openspace { void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { + // At fps that are too low, the animation stops working. Just place target instead + bool fpsTooLow = deltaTime > DeltaTimeThreshold; // Find smallest angle between the two vectors double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, _animationEnd); - const bool shouldAnimate = smallestAngle > _stopAnimationThreshold; + bool hasArrived = smallestAngle < _stopAnimationThreshold; // Only keep animating when target is not at goal position - if (shouldAnimate) { + if (!hasArrived && !fpsTooLow) { glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( _animationStart, _animationEnd, From 14c6760859fa2638c35fccd0ea7d760809a84c7e Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 3 Dec 2021 17:32:41 -0500 Subject: [PATCH 170/251] Cleanup of mouse interaction --- modules/skybrowser/include/pair.h | 7 +- .../include/screenspaceskybrowser.h | 16 +- modules/skybrowser/skybrowsermodule.cpp | 249 ++++++++---------- modules/skybrowser/skybrowsermodule.h | 26 +- modules/skybrowser/src/pair.cpp | 28 +- .../skybrowser/src/screenspaceskybrowser.cpp | 31 ++- 6 files changed, 199 insertions(+), 158 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 2465c6587e..bbf7c7b4b2 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -58,7 +58,11 @@ public: // Mouse interaction bool checkMouseIntersection(glm::vec2 mousePosition); glm::vec2 selectedScreenSpacePosition(); - bool isSelectedBrowser(); + bool isBrowserSelected(); + bool isTargetSelected(); + void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); + void translateSelected(const glm::vec2& start, const glm::vec2& translation); + void resizeBrowser(const glm::vec2& start, const glm::vec2& translation); // Browser void sendIdToBrowser(); @@ -71,6 +75,7 @@ public: // Boolean functions bool hasFinishedFading(float goalState) const; + bool isOnResizeArea(glm::vec2 mouseScreenSpaceCoords); bool isEnabled() const; bool isLocked() const; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 066b7c8555..a56ef2ab29 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -47,12 +47,8 @@ namespace openspace { // Interaction. Resize void saveResizeStartSize(); - // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in - // image if the mouse is on a side of the browser - // __1__ - // y| -1 |_____|1 - // |__x -1 - glm::ivec2 isOnResizeArea(glm::vec2 screenSpaceCoord); + bool isOnResizeArea(glm::vec2 screenSpaceCoord); + void resize(const glm::vec2& start, const glm::vec2& mouseDrag); glm::dvec2 fineTuneVector(glm::dvec2 drag); void setIdInBrowser(); @@ -69,13 +65,15 @@ namespace openspace { bool _isSyncedWithWwt{ false }; bool _isFovAnimated{ false }; - // Animation of browser + // Animation of fieldOfView float _endVfov{ 0.f }; - // Resizing of browser - glm::vec2 _originalDimensions; + // Resizing float _originalScale; float _resizeAreaPercentage{ 0.1f }; + glm::vec2 _originalDimensions; + glm::vec2 _originalScreenSpaceSize; + glm::ivec2 _resizeDirection; // Time variables // For capping the calls onchange properties from scrolling diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 57c434196e..90d8bc5b33 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -50,7 +50,7 @@ namespace { } // namespace namespace openspace { - + scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { scripting::LuaLibrary res; @@ -229,141 +229,77 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { - if (_mouseOnPair && action == MouseAction::Press) { - - // Get the currently selected browser - setSelectedBrowser(_mouseOnPair->browserId()); - - if (button == MouseButton::Left) { - _isCameraRotating = false; - _startMousePosition = _mousePosition; - _startDragPosition = _mouseOnPair->selectedScreenSpacePosition(); - - // If current object is browser, check for resizing - if (_mouseOnPair->isSelectedBrowser()) { - // Resize browser if mouse is over resize button - _resizeDirection = _mouseOnPair->getBrowser()->isOnResizeArea( - _mousePosition - ); - if (_resizeDirection != glm::ivec2{ 0 }) { - _mouseOnPair->getBrowser()->saveResizeStartSize(); - _startBrowserSize = _mouseOnPair->getBrowser()-> - screenSpaceDimensions(); - _isResizing = true; - return true; - } - } - // If you start dragging around the target, it should unlock - else { - _mouseOnPair->unlock(); - } - _isDragging = true; - - return true; - } - // Fine tuning mode of target - else if (_mouseOnPair->isSelectedBrowser() && - button == MouseButton::Right) { - // If you start dragging around on the browser, the target unlocks - _mouseOnPair->unlock(); - // Change view (by moving target) within browser if right mouse - // click on browser - _startMousePosition = _mousePosition; - _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); - _isFineTuneMode = true; - - return true; - } + if (!_isCameraInSolarSystem) { + return false; } - else if (action == MouseAction::Release) { - if (_isDragging) { - _isDragging = false; - return true; - } - if (_isFineTuneMode) { - _isFineTuneMode = false; - return true; - } - if (_isResizing) { - _isResizing = false; + if (action == MouseAction::Press && _mouseOnPair) { + handleMouseClick(button); + return true; + } + else if (_interactionMode != MouseInteraction::Hover && + action == MouseAction::Release) { + // Update browser size if it has been resized + if (_interactionMode == MouseInteraction::Resize) { _mouseOnPair->updateBrowserSize(); - return true; } - } - return false; + _interactionMode = MouseInteraction::Hover; + return true; + } + else { + return false; + } } ); global::callback::mousePosition->emplace_back( [&](double x, double y) { - if (_isCameraInSolarSystem) { - glm::vec2 pixel{ static_cast(x), static_cast(y) }; - _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); - glm::vec2 translation = _mousePosition - _startMousePosition; - - if (_isResizing) { - // Calculate scaling factor - glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition); - glm::vec2 scaling = mouseDragVector * glm::vec2(_resizeDirection); - glm::vec2 newSizeRelToOld = (_startBrowserSize + (scaling)) / - _startBrowserSize; - // Scale the browser - _mouseOnPair->getBrowser()->setScale(newSizeRelToOld); - - // For dragging functionality, translate so it looks like the - // browser isn't moving. Make sure the browser doesn't move in - // directions it's not supposed to - translation = 0.5f * mouseDragVector * abs( - glm::vec2(_resizeDirection) - ); - - } - if (_isDragging || _isResizing) { - - // Translate - if (_mouseOnPair->isSelectedBrowser()) { - _mouseOnPair->getBrowser()->translate( - translation, - _startDragPosition - ); - } - else { - _mouseOnPair->getTarget()->translate( - translation, - _startDragPosition - ); - } - } - else if (_isFineTuneMode) { - glm::vec2 fineTune = _mouseOnPair->getBrowser()->fineTuneVector( - translation - ); - _mouseOnPair->getTarget()->translate(fineTune, _startDragPosition); - } - // If there is no dragging or resizing, look for new objects - else { - setSelectedObject(); - } + if (!_isCameraInSolarSystem) { + return false; } - + + glm::vec2 pixel{ static_cast(x), static_cast(y) }; + _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); + glm::vec2 translation = _mousePosition - _startMousePosition; + + switch (_interactionMode) { + case MouseInteraction::Hover: + setSelectedObject(); + break; + + case MouseInteraction::Resize: + _mouseOnPair->resizeBrowser(_startDragPosition, translation); + break; + + case MouseInteraction::Drag: + _mouseOnPair->translateSelected(_startDragPosition, translation); + break; + + case MouseInteraction::FineTune: + _mouseOnPair->fineTuneTarget(_startDragPosition, translation); + break; + + default: + setSelectedObject(); + break; + } + return false; } ); global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - // If mouse is on browser or target, apply zoom - if (_mouseOnPair) { - _mouseOnPair->getBrowser()->setVerticalFovWithScroll( - static_cast(scroll) - ); - return true; + if (!_isCameraInSolarSystem || !_mouseOnPair) { + return false; } - - return false; + // If mouse is on browser or target, apply zoom + _mouseOnPair->getBrowser()->setVerticalFovWithScroll( + static_cast(scroll) + ); + return true; } ); @@ -374,27 +310,28 @@ SkyBrowserModule::SkyBrowserModule() bool camWasInSolarSystem = _isCameraInSolarSystem; glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); _isCameraInSolarSystem = glm::length(cameraPos) < SolarSystemRadius; + bool vizModeChanged = _isCameraInSolarSystem != camWasInSolarSystem; - // Fading flags - if (_isCameraInSolarSystem != camWasInSolarSystem) { - _isTransitioningVizMode = true; - - // Select the 3D browser when moving out of the solar system - if (!_isCameraInSolarSystem && _browser3dNode) { - _selectedBrowser = _browser3dNode->renderable()->identifier(); + // Visualization mode changed. Start fading + if (vizModeChanged) { + _isFading = true; + // Camera moved into the solar system + if (!_isCameraInSolarSystem) { + _goal = Transparency::Transparent; + // Select the 3D browser when moving out of the solar system + if (_browser3dNode) { + _selectedBrowser = _browser3dNode->renderable()->identifier(); + } + } + else { + _goal = Transparency::Opaque; } } double deltaTime = global::windowDelegate->deltaTime(); // Fade pairs if the camera moved in or out the solar system - if (_isTransitioningVizMode) { - if (_isCameraInSolarSystem) { - incrementallyFadeBrowserTargets(Transparency::Opaque, deltaTime); - } - else { - incrementallyFadeBrowserTargets(Transparency::Transparent, deltaTime); - } + if (_isFading) { + incrementallyFadeBrowserTargets(_goal, deltaTime); } - if (_isCameraInSolarSystem) { incrementallyAnimateTargets(deltaTime); } @@ -435,6 +372,9 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { void SkyBrowserModule::setSelectedObject() { + if (_interactionMode != MouseInteraction::Hover) { + return; + } // Save old selection for removing highlight Pair* previousPair = _mouseOnPair; @@ -488,8 +428,8 @@ void SkyBrowserModule::createTargetBrowserPair() { std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; - std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - //std::string url = "http://localhost:8000"; + //std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; + std::string url = "http://localhost:8000"; const std::string browser = "{" "Identifier = '" + idBrowser + "'," @@ -628,6 +568,45 @@ void SkyBrowserModule::add2dSelectedImagesTo3d(const std::string& pairId) } } +void SkyBrowserModule::handleMouseClick(const MouseButton& button) +{ + setSelectedBrowser(_mouseOnPair->browserId()); + + if (button == MouseButton::Left) { + _startMousePosition = _mousePosition; + _startDragPosition = _mouseOnPair->selectedScreenSpacePosition(); + + // If current object is browser, check for resizing + bool shouldResize = _mouseOnPair->isBrowserSelected() && + _mouseOnPair->isOnResizeArea(_mousePosition); + + if (shouldResize) { + _mouseOnPair->getBrowser()->saveResizeStartSize(); + _interactionMode = MouseInteraction::Resize; + return; + } + else { + // If it's not resize mode, it's drag mode + _interactionMode = MouseInteraction::Drag; + } + + // If target is clicked, it should unlock + if (_mouseOnPair->isTargetSelected()) { + _mouseOnPair->unlock(); + } + } + // Fine tuning mode of target + else if (button == MouseButton::Right && _mouseOnPair->isBrowserSelected()) { + // If you start dragging around on the browser, the target unlocks + _mouseOnPair->unlock(); + // Change view (by moving target) within browser if right mouse + // click on browser + _startMousePosition = _mousePosition; + _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); + _interactionMode = MouseInteraction::FineTune; + } +} + const std::unique_ptr& SkyBrowserModule::getWwtDataHandler() { return _dataHandler; } @@ -769,7 +748,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float // The transition is over when the fade is finished if (isAllFinished) { - _isTransitioningVizMode = false; + _isFading = false; } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 85b9226ae7..c1027cd5a7 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace openspace { @@ -44,6 +45,13 @@ enum class Transparency { Opaque }; +enum class MouseInteraction { + Hover, + Resize, + Drag, + FineTune, +}; + class SkyBrowserModule : public OpenSpaceModule { public: @@ -96,6 +104,9 @@ public: int nLoadedImages(); void add2dSelectedImagesTo3d(const std::string& pairId); + // Mouse interaction + void handleMouseClick(const MouseButton& button); + scripting::LuaLibrary luaLibrary() const override; //std::vector documentations() const override; @@ -114,24 +125,21 @@ private: // Fading double _fadingTime = 2.0; + Transparency _goal; // Flags - bool _isFineTuneMode{ false }; - bool _isResizing{ false }; - bool _isDragging{ false }; - bool _isCameraInSolarSystem{ true }; + bool _isCameraInSolarSystem{ true }; // Visualization modes + bool _isFading{ false }; bool _isCameraRotating = false; - bool _isTransitioningVizMode{ false }; - // Mouse interaction - dragging and resizing - glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers + // Mouse interaction + MouseInteraction _interactionMode; glm::vec2 _mousePosition; // Current mouse position in screen space coordinates glm::vec2 _startMousePosition; glm::vec2 _startDragPosition; - glm::vec2 _startBrowserSize; - glm::ivec2 _resizeDirection{ 0 }; // Animation of rotation of camera to look at coordinate galactic coordinates + glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers glm::dvec3 _startAnimation; glm::dvec3 _endAnimation; double _stopAnimationThreshold{ 0.05 }; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index b8d7baff52..b3bef60b1e 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -151,11 +151,32 @@ namespace openspace { return _selected->screenSpacePosition(); } - bool Pair::isSelectedBrowser() + bool Pair::isBrowserSelected() { return _isSelectedBrowser; } + bool Pair::isTargetSelected() + { + return _selected && !_isSelectedBrowser; + } + + void Pair::fineTuneTarget(const glm::vec2& start, const glm::vec2& translation) + { + glm::vec2 fineTune = _browser->fineTuneVector(translation); + _target->translate(fineTune, start); + } + + void Pair::translateSelected(const glm::vec2& start, const glm::vec2& translation) + { + _selected->translate(translation, start); + } + + void Pair::resizeBrowser(const glm::vec2& start, const glm::vec2& translation) + { + _browser->resize(start, translation); + } + void Pair::setEnabled(bool enable) { _browser->setEnabled(enable); @@ -297,6 +318,11 @@ namespace openspace { return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); } + bool Pair::isOnResizeArea(glm::vec2 mouseScreenSpaceCoords) + { + return _browser->isOnResizeArea(mouseScreenSpaceCoords); + } + ScreenSpaceSkyTarget* Pair::getTarget() { return _target; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 2c52ef8ea8..251398c7af 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -242,10 +242,15 @@ namespace openspace { _texture->bind(); } - glm::ivec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { + // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in + // image if the mouse is on a side of the browser + // __1__ + // y| -1 |_____|1 + // |__x -1 + bool ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { glm::ivec2 resizePosition = glm::ivec2{ 0 }; // Make sure coordinate is on browser - if (!intersection(coord)) return resizePosition; + if (!intersection(coord)) return false; // TO DO: turn this into a vector and use prettier vector arithmetic float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; @@ -259,7 +264,26 @@ namespace openspace { resizePosition.x = isOnRight ? 1 : isOnLeft ? -1 : 0; resizePosition.y = isOnTop ? 1 : isOnBottom ? -1 : 0; - return resizePosition; + _resizeDirection = resizePosition; + + return isOnRight || isOnLeft || isOnTop || isOnBottom; + } + + void ScreenSpaceSkyBrowser::resize(const glm::vec2& start, const glm::vec2& mouseDrag) + { + glm::vec2 scaling = mouseDrag * glm::vec2(_resizeDirection); + glm::vec2 newSizeRelToOld = (_originalScreenSpaceSize + (scaling)) / + _originalScreenSpaceSize; + // Scale the browser + setScale(newSizeRelToOld); + + // For dragging functionality, translate so it looks like the + // browser isn't moving. Make sure the browser doesn't move in + // directions it's not supposed to + glm::vec2 translation = 0.5f * mouseDrag * abs( + glm::vec2(_resizeDirection) + ); + translate(translation, start); } void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { @@ -292,6 +316,7 @@ namespace openspace { } void ScreenSpaceSkyBrowser::saveResizeStartSize() { + _originalScreenSpaceSize = screenSpaceDimensions(); _originalDimensions = _dimensions; _originalScale = _scale; } From 294ed90d391b90c95202953a96d96b395da48854 Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 6 Dec 2021 14:46:28 -0500 Subject: [PATCH 171/251] Make camera stop rotating upon mouse interaction --- modules/skybrowser/skybrowsermodule.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 90d8bc5b33..4ef1efa07d 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -233,9 +233,13 @@ SkyBrowserModule::SkyBrowserModule() return false; } - if (action == MouseAction::Press && _mouseOnPair) { - handleMouseClick(button); - return true; + if (action == MouseAction::Press) { + _isCameraRotating = false; + if (_mouseOnPair) { + handleMouseClick(button); + return true; + } + return false; } else if (_interactionMode != MouseInteraction::Hover && action == MouseAction::Release) { From b75e91d0c20f8e2fb8e774f84af3c0197d3c7f40 Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 6 Dec 2021 14:47:06 -0500 Subject: [PATCH 172/251] Add function to hide the wwt chrome interface (the white symbols) --- modules/skybrowser/include/pair.h | 1 + modules/skybrowser/include/wwtcommunicator.h | 2 ++ modules/skybrowser/skybrowsermodule_lua.inl | 2 ++ modules/skybrowser/src/pair.cpp | 5 +++++ modules/skybrowser/src/wwtcommunicator.cpp | 17 +++++++++++++++++ 5 files changed, 27 insertions(+) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index bbf7c7b4b2..994e945c07 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -104,6 +104,7 @@ public: void removeSelectedImage(int i); void loadImageCollection(const std::string& collection); void setImageOpacity(int i, float opacity); + void hideChromeInterface(bool shouldHide); // Comparision operators friend bool operator==(const Pair& lhs, diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 2d01a19a99..c22d88b2f3 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -52,6 +52,7 @@ public: void setImageOrder(int i, int order); void loadImageCollection(const std::string& collection); void setImageOpacity(int i, float opacity); + void hideChromeInterface(bool shouldHide); // Getters const std::deque& getSelectedImages(); @@ -102,6 +103,7 @@ private: ghoul::Dictionary setImageOpacity(const std::string& id, double opacity); ghoul::Dictionary setForegroundOpacity(double val); ghoul::Dictionary setLayerOrder(const std::string& id, int version); + ghoul::Dictionary hideChromeGui(bool isHidden); }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 24ce84f007..d42e1e1b90 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -132,11 +132,13 @@ int loadImagesToWWT(lua_State* L) { SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { + //module->getPair(id)->hideChromeInterface(true); module->getPair(id)->loadImageCollection(root); } else if (module->get3dBrowser(id)) { // Load Image collections + module->get3dBrowser(id)->hideChromeInterface(true); module->get3dBrowser(id)->setIsSyncedWithWwt(false); LINFO("Load images to " + module->get3dBrowser(id)->identifier()); module->get3dBrowser(id)->loadImageCollection(root); diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index b3bef60b1e..ef078b25ca 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -270,6 +270,11 @@ namespace openspace { _browser->setImageOpacity(i, opacity); } + void Pair::hideChromeInterface(bool shouldHide) + { + _browser->hideChromeInterface(shouldHide); + } + void Pair::sendIdToBrowser() { _browser->setIdInBrowser(); diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 5d6e9f5b6e..d1d55b7dc2 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -206,6 +206,12 @@ namespace openspace { sendMessageToWwt(msg); } + void WwtCommunicator::hideChromeInterface(bool shouldHide) + { + ghoul::Dictionary msg = hideChromeGui(shouldHide); + sendMessageToWwt(msg); + } + void WwtCommunicator::update() { Browser::update(); @@ -339,4 +345,15 @@ namespace openspace { return msg; } + ghoul::Dictionary WwtCommunicator::hideChromeGui(bool isHidden) + { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "modify_settings"s); + msg.setValue("settings", "[[\"hideAllChrome\", true]]"s); + msg.setValue("target", "app"s); + + return msg; + } + } // namespace openspace From fa5812c83a16e5577a06ff41238812ac724e1cb9 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 8 Dec 2021 11:03:29 -0500 Subject: [PATCH 173/251] Add properties for disabling mouse interaction and automatic camera rotation for dome purposes --- modules/skybrowser/skybrowsermodule.cpp | 67 ++++++++++++++++--- modules/skybrowser/skybrowsermodule.h | 3 + .../skybrowser/src/screenspaceskybrowser.cpp | 20 +----- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 4ef1efa07d..c89861600f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -40,15 +40,39 @@ #include #include #include +#include // For hsv color +#include // For random color namespace { - struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { + constexpr const openspace::properties::Property::PropertyInfo AllowInteractionInfo = + { + "AllowMouseInteraction", + "Allow Mouse Interaction", + "Toggles if it is possible to interact with the sky browser and sky targets with " + "the mouse or not." + }; + + constexpr const openspace::properties::Property::PropertyInfo AllowRotationInfo = + { + "AllowCameraRotation", + "Allow Camera Rotation", + "Toggles if the camera should rotate to look at the sky target if it is going " + "outside of the current field of view." + }; + + struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { + // [[codegen::verbatim(AllowInteractionInfo.description)]] + std::optional allowMouseInteraction; + + // [[codegen::verbatim(AllowRotationInfo.description)]] + std::optional allowCameraRotation; }; #include "skybrowsermodule_codegen.cpp" } // namespace + namespace openspace { scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { @@ -222,14 +246,32 @@ namespace openspace { return res; } +glm::ivec3 randomBorderColor() { + // Generate a random border color with sufficient lightness and a n + std::random_device rd; + // Hue is in the unit degrees [0, 360] + std::uniform_real_distribution hue(0.f, 360.f); + // Value in saturation are in the unit percent [0,1] + float value = 0.95f; // Brightness + float saturation = 0.5f; + glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); + glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); + return rgbColor; +} + SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) + , _allowMouseInteraction(AllowInteractionInfo, true) + , _allowCameraRotation(AllowRotationInfo, true) { + addProperty(_allowMouseInteraction); + addProperty(_allowCameraRotation); + // Set callback functions global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { - if (!_isCameraInSolarSystem) { + if (!_isCameraInSolarSystem || !_allowMouseInteraction) { return false; } @@ -260,7 +302,7 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mousePosition->emplace_back( [&](double x, double y) { - if (!_isCameraInSolarSystem) { + if (!_isCameraInSolarSystem || !_allowMouseInteraction) { return false; } @@ -296,7 +338,7 @@ SkyBrowserModule::SkyBrowserModule() global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - if (!_isCameraInSolarSystem || !_mouseOnPair) { + if (!_isCameraInSolarSystem || !_mouseOnPair || !_allowMouseInteraction) { return false; } // If mouse is on browser or target, apply zoom @@ -339,7 +381,7 @@ SkyBrowserModule::SkyBrowserModule() if (_isCameraInSolarSystem) { incrementallyAnimateTargets(deltaTime); } - if (_isCameraRotating) { + if (_isCameraRotating && _allowCameraRotation) { incrementallyRotateCamera(deltaTime); } }); @@ -432,8 +474,10 @@ void SkyBrowserModule::createTargetBrowserPair() { std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; - //std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - std::string url = "http://localhost:8000"; + std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; + //std::string url = "http://localhost:8000"; // check webgl version + //std::string url = "https://get.webgl.org"; + glm::ivec3 color = randomBorderColor(); const std::string browser = "{" "Identifier = '" + idBrowser + "'," @@ -442,6 +486,7 @@ void SkyBrowserModule::createTargetBrowserPair() { "Url = '"+ url +"'," "FaceCamera = false," "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," + "BorderColor = " + ghoul::to_string(color) + "," "}"; const std::string target = "{" "Identifier = '" + idTarget + "'," @@ -452,23 +497,23 @@ void SkyBrowserModule::createTargetBrowserPair() { openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + browser + ");", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + target + ");", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index c1027cd5a7..0bf2f9db0b 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace openspace { @@ -115,6 +116,8 @@ protected: void internalDeinitialize() override; private: + properties::BoolProperty _allowMouseInteraction; + properties::BoolProperty _allowCameraRotation; // The browsers and targets std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 251398c7af..3370239c4c 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -7,10 +7,7 @@ #include #include // formatJson #include -#include // For hsv color #include -#include - #include #pragma optimize("", off) @@ -64,19 +61,6 @@ namespace { namespace openspace { - glm::ivec3 randomBorderColor() { - // Generate a random border color with sufficient lightness and a n - std::random_device rd; - // Hue is in the unit degrees [0, 360] - std::uniform_real_distribution hue(0.f, 360.f); - // Value in saturation are in the unit percent [0,1] - float value = 0.95f; // Brightness - float saturation = 0.5f; - glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); - glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); - return rgbColor; - } - ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) , WwtCommunicator(dictionary) @@ -100,7 +84,7 @@ namespace openspace { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _verticalFov = p.verticalFov.value_or(_verticalFov); - _borderColor = p.borderColor.value_or(randomBorderColor()); + _borderColor = p.borderColor.value_or(_borderColor); _textureQuality = p.textureQuality.value_or(_textureQuality); addProperty(_url); @@ -117,7 +101,7 @@ namespace openspace { // Ensure that the browser is placed at the z-coordinate of the screen space plane glm::vec2 screenPosition = _cartesianPosition.value(); - _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { From efddc8bc46c4ba14f0292331de732f46131989d2 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 14 Dec 2021 11:21:46 -0500 Subject: [PATCH 174/251] Change equatorial aim to be vec2 and fix hard crash bug with texture resolution and scaling --- modules/skybrowser/include/browser.h | 2 +- modules/skybrowser/include/pair.h | 2 +- .../include/screenspaceskybrowser.h | 9 +- .../skybrowser/include/screenspaceskytarget.h | 4 +- modules/skybrowser/include/wwtcommunicator.h | 4 +- modules/skybrowser/skybrowsermodule_lua.inl | 5 +- modules/skybrowser/src/browser.cpp | 21 ++-- modules/skybrowser/src/pair.cpp | 20 ++-- .../skybrowser/src/renderableskybrowser.cpp | 4 +- .../skybrowser/src/screenspaceskybrowser.cpp | 96 ++++++++++++------- .../skybrowser/src/screenspaceskytarget.cpp | 29 +++--- modules/skybrowser/src/wwtcommunicator.cpp | 8 +- 12 files changed, 113 insertions(+), 91 deletions(-) diff --git a/modules/skybrowser/include/browser.h b/modules/skybrowser/include/browser.h index 6a5f4639d7..192258d23d 100644 --- a/modules/skybrowser/include/browser.h +++ b/modules/skybrowser/include/browser.h @@ -80,7 +80,7 @@ public: void setCallbackDimensions(const std::function& function); protected: - properties::Vec2Property _dimensions; + properties::Vec2Property _browserPixeldimensions; properties::StringProperty _url; properties::TriggerProperty _reload; diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 994e945c07..8bc5a795e5 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -87,7 +87,7 @@ public: // Getters by value float verticalFov() const; glm::ivec3 borderColor() const; - glm::dvec3 targetDirectionEquatorial() const; + glm::dvec2 targetDirectionEquatorial() const; glm::dvec3 targetDirectionGalactic() const; std::string browserGuiName() const; std::string browserId() const; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index a56ef2ab29..efd4e82304 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace openspace { @@ -35,11 +36,11 @@ namespace openspace { // Setters void setVerticalFovWithScroll(float scroll); - void setScale(glm::vec2 scalingFactor); - void setScale(float scalingFactor); void setOpacity(float opacity); + void setScreenSpaceSize(const glm::vec2& newSize); + // Set callback functions - void setCallbackEquatorialAim(std::function function); + void setCallbackEquatorialAim(std::function function); void setCallbackVerticalFov(std::function function); void setCallbackDimensions(std::function function); void setCallbackBorderColor(std::function function); @@ -58,12 +59,14 @@ namespace openspace { private: properties::DoubleProperty _animationSpeed; properties::FloatProperty _textureQuality; + properties::Vec2Property _size; void bindTexture() override; // Flags bool _isSyncedWithWwt{ false }; bool _isFovAnimated{ false }; + bool _textureDimensionsIsDirty{ false }; // Animation of fieldOfView float _endVfov{ 0.f }; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 00199bd6f1..0a90c65e50 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -42,13 +42,11 @@ namespace openspace { void setLock(bool isLocked); // Set callbacks - void setCallbackEnabled(std::function function); - void setCallbackPosition(std::function function); void setSkyBrowser(ScreenSpaceSkyBrowser* browser); // Target directions glm::dvec3 directionGalactic() const; - glm::dvec3 equatorialAim() const; + glm::dvec2 equatorialAim() const; // Locking functionality bool isLocked() const; diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index c22d88b2f3..9b1983d3d3 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -60,13 +60,13 @@ public: float verticalFov() const; glm::dvec2 fieldsOfView(); bool hasLoadedImages() const; - glm::dvec3 equatorialAim() const; + glm::dvec2 equatorialAim() const; // Setters void setHasLoadedImages(bool isLoaded); void setVerticalFov(float vfov); void setIsSyncedWithWwt(bool isSynced); - void setEquatorialAim(glm::dvec3 cartesian); + void setEquatorialAim(const glm::dvec2& equatorial); // Display void highlight(glm::ivec3 addition); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index d42e1e1b90..6522a33f64 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -337,8 +337,9 @@ int getTargetData(lua_State* L) { selectedImagesVector.push_back(i); }); - glm::dvec3 cartesian = pair->targetDirectionEquatorial(); - glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); + glm::dvec2 spherical = pair->targetDirectionEquatorial(); + glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical); + std::vector cartesianVec = { cartesian.x, diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index 9d9ff9c733..ed536a17d4 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -69,7 +69,7 @@ namespace openspace { Browser::Browser(const ghoul::Dictionary& dictionary) : _url(UrlInfo) - , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) + , _browserPixeldimensions(DimensionsInfo, glm::vec2(500.f), glm::vec2(10.f), glm::vec2(3000.f)) , _reload(ReloadInfo) { if (dictionary.hasValue(UrlInfo.identifier)) { @@ -77,10 +77,10 @@ namespace openspace { } glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); - _dimensions = windowDimensions; + _browserPixeldimensions = windowDimensions; _url.onChange([this]() { _isUrlDirty = true; }); - _dimensions.onChange([this]() { _isDimensionsDirty = true; }); + _browserPixeldimensions.onChange([this]() { _isDimensionsDirty = true; }); _reload.onChange([this]() { _shouldReload = true; }); // Create browser and render handler @@ -103,7 +103,7 @@ namespace openspace { bool Browser::initializeGL() { _texture = std::make_unique( - glm::uvec3(_dimensions.value(), 1.0f) + glm::uvec3(_browserPixeldimensions.value(), 1.0f) ); _renderHandler->setTexture(*_texture); @@ -153,7 +153,10 @@ namespace openspace { } if (_isDimensionsDirty) { - _browserInstance->reshape(_dimensions.value()); + ghoul_assert(_browserPixeldimensions.value().x > 0 && + _browserPixeldimensions.value().y > 0); + + _browserInstance->reshape(_browserPixeldimensions.value()); _isDimensionsDirty = false; } @@ -168,12 +171,12 @@ namespace openspace { } glm::vec2 Browser::browserPixelDimensions() const { - return _dimensions.value(); + return _browserPixeldimensions.value(); } // Updates the browser size to match the size of the texture void Browser::updateBrowserSize() { - _dimensions = _texture->dimensions(); + _browserPixeldimensions = _texture->dimensions(); } float Browser::browserRatio() const @@ -185,8 +188,8 @@ namespace openspace { void Browser::setCallbackDimensions( const std::function& function) { - _dimensions.onChange([&]() { - function(_dimensions.value()); + _browserPixeldimensions.onChange([&]() { + function(_browserPixeldimensions.value()); }); } diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index ef078b25ca..f207916b97 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -46,13 +46,14 @@ namespace openspace { // Set browser callback functions // Set callback functions so that the target and the browser update each other _browser->setCallbackEquatorialAim( - [&](const glm::dvec3& equatorialAim, bool) { - double diff = glm::length(equatorialAim - _target->equatorialAim()); - if ( diff > AnimationThreshold) { - _target->setCartesianPosition( - skybrowser::equatorialToScreenSpace3d(equatorialAim) - ); - } + [&](const glm::dvec2& equatorialAim) { + glm::dvec3 cartesian = skybrowser::sphericalToCartesian( + equatorialAim + ); + _target->setCartesianPosition( + skybrowser::equatorialToScreenSpace3d(cartesian) + ); + } ); _browser->setCallbackBorderColor( @@ -75,10 +76,9 @@ namespace openspace { [&](bool enabled) { _target->setEnabled(enabled); } - ); + ); _target->setSkyBrowser(_browser); - } Pair& Pair::operator=(Pair other) @@ -206,7 +206,7 @@ namespace openspace { return _browser->borderColor(); } - glm::dvec3 Pair::targetDirectionEquatorial() const + glm::dvec2 Pair::targetDirectionEquatorial() const { return _target->equatorialAim(); } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 2c1dec682a..727c39fa19 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -69,10 +69,10 @@ namespace openspace { // Maybe change later glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); float maxDimension = std::max(windowDimensions.x, windowDimensions.y); - _dimensions = { maxDimension, maxDimension }; + _browserPixeldimensions = { maxDimension, maxDimension }; addProperty(_url); - addProperty(_dimensions); + addProperty(_browserPixeldimensions); addProperty(_reload); addProperty(_verticalFov); addProperty(_borderColor); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 3370239c4c..bfb4e646c6 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -40,6 +40,16 @@ namespace { "slower framerate. Lower value means lower resolution of texture and faster " "frame rate." }; + constexpr const openspace::properties::Property::PropertyInfo SizeInfo = + { + "Size", + "Screen space size of the sky browser", + "The size of the sky browser determines how large is on screen. The y parameter " + "determines the percentage of the screen the browser will cover in the " + "y-direction. The x parameter determines how large the sky browser will be in " + "the x direction." + }; + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -66,6 +76,7 @@ namespace openspace { , WwtCommunicator(dictionary) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) + , _size(SizeInfo, glm::vec2(0.5f), glm::vec2(0.f), glm::vec2(2.f)) { // Set a unique identifier std::string identifier; @@ -88,20 +99,25 @@ namespace openspace { _textureQuality = p.textureQuality.value_or(_textureQuality); addProperty(_url); - addProperty(_dimensions); + addProperty(_browserPixeldimensions); addProperty(_reload); addProperty(_verticalFov); addProperty(_borderColor); addProperty(_equatorialAim); addProperty(_textureQuality); + addProperty(_size); _textureQuality.onChange([this]() { - updateTextureResolution(); + _textureDimensionsIsDirty = true; + }); + _size.onChange([this]() { + setScreenSpaceSize(_size); }); // Ensure that the browser is placed at the z-coordinate of the screen space plane glm::vec2 screenPosition = _cartesianPosition.value(); - _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { @@ -137,16 +153,16 @@ namespace openspace { void ScreenSpaceSkyBrowser::updateTextureResolution() { - // Scale texture depending on the height of the window // Set texture size to the actual pixel size it covers glm::vec2 pixels = glm::vec2(global::windowDelegate->currentSubwindowSize()); - glm::vec2 browserDim = screenSpaceDimensions(); - float newResY = pixels.y * browserDim.y; - float newResX = newResY * (_dimensions.value().x / _dimensions.value().y); + + // If the scale is 1, it covers half the window. Hence multiplication with 2 + float newResY = pixels.y * 2.f * _scale; + float newResX = newResY * (_browserPixeldimensions.value().x / _browserPixeldimensions.value().y); glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value(); - _dimensions = glm::ivec2(newSize); + _browserPixeldimensions = glm::ivec2(newSize); _texture->setDimensions(glm::ivec3(newSize, 1)); } @@ -194,14 +210,16 @@ namespace openspace { } void ScreenSpaceSkyBrowser::update() { - - if (global::windowDelegate->windowHasResized()) { - // Change the resolution of the texture + // Texture of window is 1x1 when minimized + bool isWindow = global::windowDelegate->currentSubwindowSize() != glm::ivec2(1); + bool isWindowResized = global::windowDelegate->windowHasResized(); + if ((isWindowResized && isWindow) || _textureDimensionsIsDirty) { updateTextureResolution(); + _textureDimensionsIsDirty = false; } - - _objectSize = _texture->dimensions(); + _objectSize = _texture->dimensions(); + WwtCommunicator::update(); ScreenSpaceRenderable::update(); } @@ -258,8 +276,15 @@ namespace openspace { glm::vec2 scaling = mouseDrag * glm::vec2(_resizeDirection); glm::vec2 newSizeRelToOld = (_originalScreenSpaceSize + (scaling)) / _originalScreenSpaceSize; + + _scale = _originalScale * abs(newSizeRelToOld.y); + // Resize the dimensions of the texture on the x axis + glm::vec2 newDimensions = abs(newSizeRelToOld) * _originalDimensions; // Scale the browser - setScale(newSizeRelToOld); + // Scale on the y axis, this is to ensure that _scale = 1 is + // equal to the height of the window + _texture->setDimensions(glm::ivec3(newDimensions, 1)); + _objectSize = _texture->dimensions(); // For dragging functionality, translate so it looks like the // browser isn't moving. Make sure the browser doesn't move in @@ -270,22 +295,6 @@ namespace openspace { translate(translation, start); } - void ScreenSpaceSkyBrowser::setScale(float scalingFactor) { - _scale = _originalScale * scalingFactor; - } - - // Scales the ScreenSpaceBrowser to a new ratio - void ScreenSpaceSkyBrowser::setScale(glm::vec2 scalingFactor) { - - // Scale on the y axis, this is to ensure that _scale = 1 is - // equal to the height of the window - setScale(abs(scalingFactor.y)); - // Resize the dimensions of the texture on the x axis - glm::vec2 newSize = abs(scalingFactor) * _originalDimensions; - _texture->setDimensions(glm::ivec3(newSize, 1)); - _objectSize = _texture->dimensions(); - } - glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { // To ensure the plane has the right ratio // The _scale tells us how much of the windows height the @@ -301,15 +310,15 @@ namespace openspace { void ScreenSpaceSkyBrowser::saveResizeStartSize() { _originalScreenSpaceSize = screenSpaceDimensions(); - _originalDimensions = _dimensions; + _originalDimensions = _browserPixeldimensions; _originalScale = _scale; } void ScreenSpaceSkyBrowser::setCallbackEquatorialAim( - std::function function) + std::function function) { _equatorialAim.onChange([this, f = std::move(function)]() { - f(skybrowser::sphericalToCartesian(_equatorialAim), false); + f(_equatorialAim); }); } @@ -324,8 +333,8 @@ namespace openspace { void ScreenSpaceSkyBrowser::setCallbackDimensions( std::function function) { - _dimensions.onChange([this, f = std::move(function)]() { - f(_dimensions); + _browserPixeldimensions.onChange([this, f = std::move(function)]() { + f(_browserPixeldimensions); }); } @@ -342,12 +351,27 @@ namespace openspace { }); } - void ScreenSpaceSkyBrowser::setOpacity(float opacity) { _opacity = opacity; } + void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) + { + _scale = abs(newSize.y) * 0.5f; + glm::vec2 newSizeRelToOld = abs((screenSpaceDimensions() + newSize) / + screenSpaceDimensions()); + glm::vec2 newDimensions = newSizeRelToOld * glm::vec2(_texture->dimensions()); + // Scale the browser + // Scale on the y axis, this is to ensure that _scale = 1 is + // equal to the height of the window + _browserPixeldimensions = glm::ivec2(newDimensions); + _texture->setDimensions(glm::ivec3(newDimensions, 1)); + _objectSize = _texture->dimensions(); + + updateTextureResolution(); + } + float ScreenSpaceSkyBrowser::opacity() const { return _opacity; } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 52bdb91956..1cfafa35de 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -270,7 +270,9 @@ namespace openspace { void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, bool shouldLockAfter) { - _animationStart = glm::normalize(equatorialAim()); + _animationStart = glm::normalize( + skybrowser::sphericalToCartesian(equatorialAim()) + ); _animationEnd = glm::normalize(equatorialCoordsEnd); _shouldLockAfterAnimation = shouldLockAfter; _isAnimated = true; @@ -302,7 +304,8 @@ namespace openspace { _cartesianPosition = skybrowser::equatorialToScreenSpace3d(newDir); // Update position - _animationStart = glm::normalize(equatorialAim()); + glm::dvec3 cartesian = skybrowser::sphericalToCartesian(equatorialAim()); + _animationStart = glm::normalize(cartesian); } else { glm::dvec3 screenSpace = skybrowser::equatorialToScreenSpace3d(_animationEnd); @@ -314,10 +317,13 @@ namespace openspace { } } - glm::dvec3 ScreenSpaceSkyTarget::equatorialAim() const { + glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const { // Calculate the galactic coordinate of the target direction // projected onto the celestial sphere - return skybrowser::localCameraToEquatorial(_cartesianPosition.value()); + glm::dvec3 cartesian = skybrowser::localCameraToEquatorial( + _cartesianPosition.value() + ); + return skybrowser::cartesianToSpherical(cartesian); } @@ -342,22 +348,9 @@ namespace openspace { { _isLocked = isLocked; if (_isLocked) { - _lockedCoordinates = equatorialAim(); + _lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim()); } } - void ScreenSpaceSkyTarget::setCallbackEnabled(std::function function) - { - _enabled.onChange([this, f = std::move(function)]() { - f(_enabled); - }); - } - void ScreenSpaceSkyTarget::setCallbackPosition( - std::function function) - { - _cartesianPosition.onChange([this, f = std::move(function)]() { - f(_cartesianPosition); - }); - } void ScreenSpaceSkyTarget::setSkyBrowser(ScreenSpaceSkyBrowser* browser) { _browser = browser; diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index d1d55b7dc2..d635e365bf 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -127,9 +127,9 @@ namespace openspace { _isSyncedWithWwt = isSynced; } - void WwtCommunicator::setEquatorialAim(glm::dvec3 cartesian) + void WwtCommunicator::setEquatorialAim(const glm::dvec2& equatorial) { - _equatorialAim = skybrowser::cartesianToSpherical(cartesian); + _equatorialAim = equatorial; updateAim(); } @@ -170,9 +170,9 @@ namespace openspace { return _hasLoadedImages; } - glm::dvec3 WwtCommunicator::equatorialAim() const + glm::dvec2 WwtCommunicator::equatorialAim() const { - return skybrowser::sphericalToCartesian(_equatorialAim); + return _equatorialAim; } void WwtCommunicator::setImageOrder(int i, int order) { From e95287399c764a958e9d4f63179f0116735b1685 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 14 Dec 2021 11:31:33 -0500 Subject: [PATCH 175/251] Remove mouse drag resizing functionality --- modules/skybrowser/include/pair.h | 2 - .../include/screenspaceskybrowser.h | 12 ---- modules/skybrowser/skybrowsermodule.cpp | 25 +------- modules/skybrowser/skybrowsermodule.h | 1 - modules/skybrowser/src/pair.cpp | 10 ---- .../skybrowser/src/screenspaceskybrowser.cpp | 57 ------------------- 6 files changed, 3 insertions(+), 104 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 8bc5a795e5..6fffd23e22 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -62,7 +62,6 @@ public: bool isTargetSelected(); void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); void translateSelected(const glm::vec2& start, const glm::vec2& translation); - void resizeBrowser(const glm::vec2& start, const glm::vec2& translation); // Browser void sendIdToBrowser(); @@ -75,7 +74,6 @@ public: // Boolean functions bool hasFinishedFading(float goalState) const; - bool isOnResizeArea(glm::vec2 mouseScreenSpaceCoords); bool isEnabled() const; bool isLocked() const; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index efd4e82304..62855fd4a5 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -46,11 +46,6 @@ namespace openspace { void setCallbackBorderColor(std::function function); void setCallbackEnabled(std::function function); - // Interaction. Resize - void saveResizeStartSize(); - bool isOnResizeArea(glm::vec2 screenSpaceCoord); - void resize(const glm::vec2& start, const glm::vec2& mouseDrag); - glm::dvec2 fineTuneVector(glm::dvec2 drag); void setIdInBrowser(); @@ -71,13 +66,6 @@ namespace openspace { // Animation of fieldOfView float _endVfov{ 0.f }; - // Resizing - float _originalScale; - float _resizeAreaPercentage{ 0.1f }; - glm::vec2 _originalDimensions; - glm::vec2 _originalScreenSpaceSize; - glm::ivec2 _resizeDirection; - // Time variables // For capping the calls onchange properties from scrolling constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index c89861600f..eb8e1ae9d2 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -285,11 +285,7 @@ SkyBrowserModule::SkyBrowserModule() } else if (_interactionMode != MouseInteraction::Hover && action == MouseAction::Release) { - // Update browser size if it has been resized - if (_interactionMode == MouseInteraction::Resize) { - _mouseOnPair->updateBrowserSize(); - } - + _interactionMode = MouseInteraction::Hover; return true; } @@ -315,10 +311,6 @@ SkyBrowserModule::SkyBrowserModule() setSelectedObject(); break; - case MouseInteraction::Resize: - _mouseOnPair->resizeBrowser(_startDragPosition, translation); - break; - case MouseInteraction::Drag: _mouseOnPair->translateSelected(_startDragPosition, translation); break; @@ -625,19 +617,8 @@ void SkyBrowserModule::handleMouseClick(const MouseButton& button) _startMousePosition = _mousePosition; _startDragPosition = _mouseOnPair->selectedScreenSpacePosition(); - // If current object is browser, check for resizing - bool shouldResize = _mouseOnPair->isBrowserSelected() && - _mouseOnPair->isOnResizeArea(_mousePosition); - - if (shouldResize) { - _mouseOnPair->getBrowser()->saveResizeStartSize(); - _interactionMode = MouseInteraction::Resize; - return; - } - else { - // If it's not resize mode, it's drag mode - _interactionMode = MouseInteraction::Drag; - } + // If it's not resize mode, it's drag mode + _interactionMode = MouseInteraction::Drag; // If target is clicked, it should unlock if (_mouseOnPair->isTargetSelected()) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 0bf2f9db0b..81ca6183b1 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -48,7 +48,6 @@ enum class Transparency { enum class MouseInteraction { Hover, - Resize, Drag, FineTune, }; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index f207916b97..9b1bcc6c1d 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -172,11 +172,6 @@ namespace openspace { _selected->translate(translation, start); } - void Pair::resizeBrowser(const glm::vec2& start, const glm::vec2& translation) - { - _browser->resize(start, translation); - } - void Pair::setEnabled(bool enable) { _browser->setEnabled(enable); @@ -323,11 +318,6 @@ namespace openspace { return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); } - bool Pair::isOnResizeArea(glm::vec2 mouseScreenSpaceCoords) - { - return _browser->isOnResizeArea(mouseScreenSpaceCoords); - } - ScreenSpaceSkyTarget* Pair::getTarget() { return _target; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index bfb4e646c6..aab1129940 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -244,57 +244,6 @@ namespace openspace { _texture->bind(); } - // Mouse interaction with the browser. Returns 1 or -1 at the coordinate in - // image if the mouse is on a side of the browser - // __1__ - // y| -1 |_____|1 - // |__x -1 - bool ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 coord) { - glm::ivec2 resizePosition = glm::ivec2{ 0 }; - // Make sure coordinate is on browser - if (!intersection(coord)) return false; - - // TO DO: turn this into a vector and use prettier vector arithmetic - float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage; - float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage; - - const bool isOnTop = coord.y > upperRightCornerScreenSpace().y - resizeAreaY; - const bool isOnBottom = coord.y < lowerLeftCornerScreenSpace().y + resizeAreaY; - const bool isOnRight = coord.x > upperRightCornerScreenSpace().x - resizeAreaX; - const bool isOnLeft = coord.x < lowerLeftCornerScreenSpace().x + resizeAreaX; - - resizePosition.x = isOnRight ? 1 : isOnLeft ? -1 : 0; - resizePosition.y = isOnTop ? 1 : isOnBottom ? -1 : 0; - - _resizeDirection = resizePosition; - - return isOnRight || isOnLeft || isOnTop || isOnBottom; - } - - void ScreenSpaceSkyBrowser::resize(const glm::vec2& start, const glm::vec2& mouseDrag) - { - glm::vec2 scaling = mouseDrag * glm::vec2(_resizeDirection); - glm::vec2 newSizeRelToOld = (_originalScreenSpaceSize + (scaling)) / - _originalScreenSpaceSize; - - _scale = _originalScale * abs(newSizeRelToOld.y); - // Resize the dimensions of the texture on the x axis - glm::vec2 newDimensions = abs(newSizeRelToOld) * _originalDimensions; - // Scale the browser - // Scale on the y axis, this is to ensure that _scale = 1 is - // equal to the height of the window - _texture->setDimensions(glm::ivec3(newDimensions, 1)); - _objectSize = _texture->dimensions(); - - // For dragging functionality, translate so it looks like the - // browser isn't moving. Make sure the browser doesn't move in - // directions it's not supposed to - glm::vec2 translation = 0.5f * mouseDrag * abs( - glm::vec2(_resizeDirection) - ); - translate(translation, start); - } - glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { // To ensure the plane has the right ratio // The _scale tells us how much of the windows height the @@ -308,12 +257,6 @@ namespace openspace { return scale; } - void ScreenSpaceSkyBrowser::saveResizeStartSize() { - _originalScreenSpaceSize = screenSpaceDimensions(); - _originalDimensions = _browserPixeldimensions; - _originalScale = _scale; - } - void ScreenSpaceSkyBrowser::setCallbackEquatorialAim( std::function function) { From ad997e64e6dd6b84ae21016a344eb44f4ed46298 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 14 Dec 2021 11:38:33 -0500 Subject: [PATCH 176/251] Update field of view when scale of target is changed --- modules/skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/src/screenspaceskytarget.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 0a90c65e50..4674e1d1cb 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -36,6 +36,7 @@ namespace openspace { // Setters void setScaleFromVfov(float verticalFov); + void setFovFromScale(); void setDimensions(glm::vec2 dimensions); void setColor(glm::ivec3 color); void setOpacity(float opacity); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 1cfafa35de..dbe253f458 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -108,6 +108,7 @@ namespace openspace { skybrowser::ScreenSpaceZ }; _cartesianPosition.setValue(startPos); + } ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { @@ -258,6 +259,12 @@ namespace openspace { _scale = std::max(heightRatio, smallestHeightRatio); } + void ScreenSpaceSkyTarget::setFovFromScale() + { + glm::dvec2 fovs = skybrowser::fovWindow(); + _verticalFov = _scale * fovs.y; + } + bool ScreenSpaceSkyTarget::isLocked() const { return _isLocked; } @@ -357,5 +364,9 @@ namespace openspace { _enabled.onChange([this]() { _browser->setEnabled(_enabled); }); + _scale.onChange([&]() { + setFovFromScale(); + _browser->setVerticalFov(_verticalFov); + }); } } From 733dc09a30329a360866f6fa248b1c4f62c40c76 Mon Sep 17 00:00:00 2001 From: "ENG-VIDAVIZ-0\\ylvas" Date: Wed, 15 Dec 2021 11:21:38 -0500 Subject: [PATCH 177/251] Move lua scripting to create target browser pair to lua functions --- modules/skybrowser/skybrowsermodule.cpp | 85 ++------------------ modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 86 ++++++++++++++++++++- 3 files changed, 92 insertions(+), 81 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index eb8e1ae9d2..1ec41ce4b9 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -37,11 +37,9 @@ #include #include #include -#include #include #include -#include // For hsv color -#include // For random color + namespace { @@ -246,18 +244,7 @@ namespace openspace { return res; } -glm::ivec3 randomBorderColor() { - // Generate a random border color with sufficient lightness and a n - std::random_device rd; - // Hue is in the unit degrees [0, 360] - std::uniform_real_distribution hue(0.f, 360.f); - // Value in saturation are in the unit percent [0,1] - float value = 0.95f; // Brightness - float saturation = 0.5f; - glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); - glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); - return rgbColor; -} + SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) @@ -458,57 +445,6 @@ void SkyBrowserModule::addTargetBrowserPair(std::string targetId, std::string br } } -void SkyBrowserModule::createTargetBrowserPair() { - int noOfPairs = static_cast(_targetsBrowsers.size()) + 1; - std::string nameBrowser = "Sky Browser " + std::to_string(noOfPairs); - std::string nameTarget = "Sky Target " + std::to_string(noOfPairs); - std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); - std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); - glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; - std::string guiPath = "/SkyBrowser"; - std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - //std::string url = "http://localhost:8000"; // check webgl version - //std::string url = "https://get.webgl.org"; - glm::ivec3 color = randomBorderColor(); - - const std::string browser = "{" - "Identifier = '" + idBrowser + "'," - "Type = 'ScreenSpaceSkyBrowser'," - "Name = '" + nameBrowser + "'," - "Url = '"+ url +"'," - "FaceCamera = false," - "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," - "BorderColor = " + ghoul::to_string(color) + "," - "}"; - const std::string target = "{" - "Identifier = '" + idTarget + "'," - "Type = 'ScreenSpaceSkyTarget'," - "Name = '" + nameTarget + "'," - "FaceCamera = false," - "}"; - - openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + browser + ");", - scripting::ScriptEngine::RemoteScripting::No - ); - - openspace::global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + target + ");", - scripting::ScriptEngine::RemoteScripting::No - ); - - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" - + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::No - ); - - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::No - ); -} - void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { Pair* found = getPair(id); @@ -519,18 +455,6 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { [&](const std::unique_ptr& pair) { return *found == *(pair.get()); }); - - std::string targetId = found->getTarget()->identifier(); - // Remove from engine - openspace::global::scriptEngine->queueScript( - "openspace.removeScreenSpaceRenderable('" + found->browserId() + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - - openspace::global::scriptEngine->queueScript( - "openspace.removeScreenSpaceRenderable('" + targetId + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); _targetsBrowsers.erase(it, std::end(_targetsBrowsers)); _mouseOnPair = nullptr; @@ -646,6 +570,11 @@ std::vector>& SkyBrowserModule::getPairs() return _targetsBrowsers; } +int SkyBrowserModule::nPairs() +{ + return static_cast(_targetsBrowsers.size()); +} + Pair* SkyBrowserModule::getPair(const std::string& id) { auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 81ca6183b1..248765caf6 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -64,6 +64,7 @@ public: // Getters std::vector>& getPairs(); + int nPairs(); Pair* getPair(const std::string& id); SceneGraphNode* get3dBrowserNode(); RenderableSkyBrowser* get3dBrowser(); @@ -90,7 +91,6 @@ public: bool isCameraInSolarSystem(); // Managing the target browser pairs - void createTargetBrowserPair(); void removeTargetBrowserPair(std::string& browserId); void addTargetBrowserPair(std::string targetId, std::string browserId); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 6522a33f64..23b85e52e8 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -4,14 +4,29 @@ #include #include #include +#include #include #include #include +#include // For hsv color +#include // For random color namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; } // namespace +glm::ivec3 randomBorderColor() { + // Generate a random border color with sufficient lightness and a n + std::random_device rd; + // Hue is in the unit degrees [0, 360] + std::uniform_real_distribution hue(0.f, 360.f); + // Value in saturation are in the unit percent [0,1] + float value = 0.95f; // Brightness + float saturation = 0.5f; + glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); + glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); + return rgbColor; +} namespace openspace::skybrowser::luascriptfunctions { @@ -490,7 +505,55 @@ int setSelectedBrowser(lua_State* L) { int createTargetBrowserPair(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createTargetBrowserPair"); SkyBrowserModule* module = global::moduleEngine->module(); - module->createTargetBrowserPair(); + + int noOfPairs = module->nPairs(); + std::string nameBrowser = "Sky Browser " + std::to_string(noOfPairs); + std::string nameTarget = "Sky Target " + std::to_string(noOfPairs); + std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); + std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); + glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; + std::string guiPath = "/SkyBrowser"; + std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; + //std::string url = "http://localhost:8000"; // check webgl version + //std::string url = "https://get.webgl.org"; + glm::ivec3 color = randomBorderColor(); + + const std::string browser = "{" + "Identifier = '" + idBrowser + "'," + "Type = 'ScreenSpaceSkyBrowser'," + "Name = '" + nameBrowser + "'," + "Url = '" + url + "'," + "FaceCamera = false," + "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," + "BorderColor = " + ghoul::to_string(color) + "," + "}"; + const std::string target = "{" + "Identifier = '" + idTarget + "'," + "Type = 'ScreenSpaceSkyTarget'," + "Name = '" + nameTarget + "'," + "FaceCamera = false," + "}"; + + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + browser + ");", + scripting::ScriptEngine::RemoteScripting::No + ); + + openspace::global::scriptEngine->queueScript( + "openspace.addScreenSpaceRenderable(" + target + ");", + scripting::ScriptEngine::RemoteScripting::No + ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + + idBrowser + "');", + scripting::ScriptEngine::RemoteScripting::No + ); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", + scripting::ScriptEngine::RemoteScripting::No + ); return 0; } @@ -499,7 +562,26 @@ int removeTargetBrowserPair(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeTargetBrowserPair"); std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - module->removeTargetBrowserPair(id); + Pair* found = module->getPair(id); + if (found) { + std::string browser = found->browserId(); + std::string target = found->targetId(); + found = nullptr; + + module->removeTargetBrowserPair(id); + + // Remove from engine + openspace::global::scriptEngine->queueScript( + "openspace.removeScreenSpaceRenderable('" + browser + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + + openspace::global::scriptEngine->queueScript( + "openspace.removeScreenSpaceRenderable('" + target + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + return 0; } From e839ee05b73d613711a42126fb80f5136f3a21c8 Mon Sep 17 00:00:00 2001 From: "ENG-VIDAVIZ-0\\ylvas" Date: Thu, 16 Dec 2021 10:32:06 -0500 Subject: [PATCH 178/251] Make target work with RAE coordinates so it can be used in a dome setup --- .../rendering/screenspacerenderable.h | 5 +- .../skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/include/utility.h | 3 +- modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/src/pair.cpp | 10 +-- .../skybrowser/src/screenspaceskytarget.cpp | 85 +++++++++++++++---- modules/skybrowser/src/utility.cpp | 33 ++++--- src/rendering/screenspacerenderable.cpp | 12 ++- 8 files changed, 114 insertions(+), 37 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index a7e5a7207d..0881eaf718 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -80,7 +80,7 @@ public: glm::vec2 lowerLeftCornerScreenSpace(); bool intersection(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); - void setCartesianPosition(const glm::vec3& position); + void setPosition(const glm::vec3& position); // End of addition by skybrowser team @@ -95,6 +95,9 @@ protected: glm::mat4 translationMatrix(); glm::mat4 localRotationMatrix(); + glm::vec3 raeToCartesian(const glm::vec3& rae) const; + glm::vec3 cartesianToRae(const glm::vec3& cartesian) const; + void draw(glm::mat4 modelTransform); virtual void bindTexture() = 0; diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 4674e1d1cb..b1da07bc97 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -41,6 +41,7 @@ namespace openspace { void setColor(glm::ivec3 color); void setOpacity(float opacity); void setLock(bool isLocked); + void setEquatorialAim(const glm::dvec2& aim); // Set callbacks void setSkyBrowser(ScreenSpaceSkyBrowser* browser); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 1ba7ddc502..60eb5bc256 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -30,10 +30,11 @@ namespace openspace { // Conversion to screen space from J2000 equatorial / galactic / pixels glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords); - glm::dvec3 galacticToScreenSpace3d(const glm::dvec3& coords); + glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords); glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate); // Conversion local camera space <-> galactic / equatorial + glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords); glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords); glm::dvec3 localCameraToGalactic(const glm::dvec3& coords); glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1ec41ce4b9..ccedd65484 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -496,7 +496,7 @@ void SkyBrowserModule::moveHoverCircle(int i) glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace3d( image.equatorialCartesian ); - _hoverCircle->setCartesianPosition(coordsScreen); + _hoverCircle->setPosition(coordsScreen); } } diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 9b1bcc6c1d..f567ea5e5b 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -45,17 +45,13 @@ namespace openspace { // Set browser callback functions // Set callback functions so that the target and the browser update each other + /* _browser->setCallbackEquatorialAim( [&](const glm::dvec2& equatorialAim) { - glm::dvec3 cartesian = skybrowser::sphericalToCartesian( - equatorialAim - ); - _target->setCartesianPosition( - skybrowser::equatorialToScreenSpace3d(cartesian) - ); - + _target->setEquatorialAim(equatorialAim); } ); + */ _browser->setCallbackBorderColor( [&](const glm::ivec3& color) { _target->setColor(color); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index dbe253f458..52ea9d121e 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -209,9 +209,21 @@ namespace openspace { void ScreenSpaceSkyTarget::update() { if (_isLocked) { - _cartesianPosition = skybrowser::equatorialToScreenSpace3d( + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera( _lockedCoordinates ); + + if (_useRadiusAzimuthElevation) { + // Keep the set radius + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d( + localCamera + ); + } + } // Optimization: Only pass messages to the browser when the target is not moving if (_browser && !_isAnimated) { @@ -238,10 +250,18 @@ namespace openspace { glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { + + glm::vec3 localCamera = _cartesianPosition.value(); + + if (_useRadiusAzimuthElevation) { + + localCamera = raeToCartesian(_raePosition.value()); + } + glm::dmat4 rotation = glm::inverse( global::navigationHandler->camera()->viewRotationMatrix() ); - glm::dvec4 position = glm::dvec4(_cartesianPosition.value(), 1.0); + glm::dvec4 position = glm::dvec4(localCamera, 1.0); return glm::normalize(rotation * position); } @@ -305,19 +325,34 @@ namespace openspace { ); // Rotate target direction - glm::dvec3 newDir = rotMat * glm::dvec4(_animationStart, 1.0); - + glm::dvec3 equatorial = glm::dvec3(rotMat * glm::dvec4(_animationStart, 1.0)); + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(equatorial); // Convert to screen space - _cartesianPosition = skybrowser::equatorialToScreenSpace3d(newDir); + if (_useRadiusAzimuthElevation) { + // Keep the radius + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + } // Update position glm::dvec3 cartesian = skybrowser::sphericalToCartesian(equatorialAim()); _animationStart = glm::normalize(cartesian); } else { - glm::dvec3 screenSpace = skybrowser::equatorialToScreenSpace3d(_animationEnd); // Set the exact target position - _cartesianPosition = glm::vec3(screenSpace); + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(_animationEnd); + + if (_useRadiusAzimuthElevation) { + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + } + _isAnimated = false; // Lock target when it first arrives to the position setLock(_shouldLockAfterAnimation); @@ -325,12 +360,18 @@ namespace openspace { } glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const { - // Calculate the galactic coordinate of the target direction - // projected onto the celestial sphere - glm::dvec3 cartesian = skybrowser::localCameraToEquatorial( - _cartesianPosition.value() - ); - return skybrowser::cartesianToSpherical(cartesian); + + // Get the local camera coordinates of the target + if (_useRadiusAzimuthElevation) { + glm::vec3 cartesian = raeToCartesian(_raePosition.value()); + glm::dvec3 equatorial = skybrowser::localCameraToEquatorial(cartesian); + return skybrowser::cartesianToSpherical(equatorial); + + } + else { + glm::dvec3 cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value()); + return skybrowser::cartesianToSpherical(cartesian); + } } @@ -358,15 +399,29 @@ namespace openspace { _lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim()); } } + void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) + { + glm::dvec3 cartesianAim = skybrowser::sphericalToCartesian(aim); + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(cartesianAim); + if (_useRadiusAzimuthElevation) { + // Keep the set radius + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + } + } void ScreenSpaceSkyTarget::setSkyBrowser(ScreenSpaceSkyBrowser* browser) { _browser = browser; _enabled.onChange([this]() { _browser->setEnabled(_enabled); }); - _scale.onChange([&]() { + /* _scale.onChange([&]() { + setFovFromScale(); _browser->setVerticalFov(_verticalFov); - }); + }); */ } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 4836649779..86c687e81b 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -9,8 +9,10 @@ #define _USE_MATH_DEFINES #include // For M_PI + namespace openspace::skybrowser { + // Converts from spherical coordinates in the unit of degrees to cartesian coordianates glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) { glm::dvec2 coordsRadians = glm::radians(coords); @@ -24,7 +26,8 @@ namespace openspace::skybrowser { return cartesian; } - glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) { + // Converts from cartesian coordianates to spherical in the unit of degrees + glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) { // Equatorial coordinates RA = right ascension, Dec = declination double ra = atan2(coord.y, coord.x); double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y))); @@ -36,26 +39,25 @@ namespace openspace::skybrowser { return glm::degrees(celestialCoords); } - glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) { + glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) { return glm::transpose(conversionMatrix) * glm::normalize(coords); } - glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) { + glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) { // On the unit sphere glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); return rGalactic * CelestialSphereRadius; } - glm::dvec3 galacticToScreenSpace3d(const glm::dvec3& coords) { + glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) { - glm::dvec3 localCameraSpace = galacticToLocalCamera(coords); // Ensure that if the coord is behind the camera, // the converted coordinate will be there too - double zCoord = localCameraSpace.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ; + double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ; // Calculate screen space coords x and y - double tan_x = localCameraSpace.x / localCameraSpace.z; - double tan_y = localCameraSpace.y / localCameraSpace.z; + double tan_x = coords.x / coords.z; + double tan_y = coords.y / coords.z; glm::dvec3 screenSpace = glm::dvec3(zCoord * tan_x, zCoord * tan_y, zCoord); @@ -79,6 +81,14 @@ namespace openspace::skybrowser { return skybrowser::galacticToEquatorial(galactic); } + glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) + { + // Transform equatorial J2000 to galactic coord with infinite radius + glm::dvec3 galactic = equatorialToGalactic(coords); + glm::dvec3 localCamera = galacticToLocalCamera(galactic); + return localCamera; + } + glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) { // Transform vector to camera's local coordinate system glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); @@ -89,11 +99,12 @@ namespace openspace::skybrowser { return glm::normalize(viewDirectionLocal); } - glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords) { + glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords) { // Transform equatorial J2000 to galactic coord with infinite radius glm::dvec3 galactic = equatorialToGalactic(coords); + glm::dvec3 localCameraSpace = galacticToLocalCamera(coords); // Transform galactic coord to screen space - return galacticToScreenSpace3d(galactic); + return localCameraToScreenSpace3d(localCameraSpace); } double cameraRoll() { @@ -186,6 +197,6 @@ namespace openspace::skybrowser { } - + diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 85000de3dd..c7f5018048 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -550,7 +550,7 @@ void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) _cartesianPosition = translationMatrix * origin; } -void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) +void ScreenSpaceRenderable::setPosition(const glm::vec3& position) { _cartesianPosition = position; } @@ -589,6 +589,16 @@ glm::mat4 ScreenSpaceRenderable::localRotationMatrix() { return rotation * glm::mat4(glm::quat(glm::vec3(pitch, yaw, roll))); } +glm::vec3 ScreenSpaceRenderable::raeToCartesian(const glm::vec3& rae) const +{ + return sphericalToCartesian(raeToSpherical(rae)); +} + +glm::vec3 ScreenSpaceRenderable::cartesianToRae(const glm::vec3& cartesian) const +{ + return sphericalToRae(cartesianToSpherical(cartesian)); +} + glm::mat4 ScreenSpaceRenderable::translationMatrix() { glm::vec3 translation = _useRadiusAzimuthElevation ? sphericalToCartesian(raeToSpherical(_raePosition)) : From e923f9c8054dc398a0113068a9c84a858fdcb3b7 Mon Sep 17 00:00:00 2001 From: "ENG-VIDAVIZ-0\\ylvas" Date: Thu, 16 Dec 2021 11:43:02 -0500 Subject: [PATCH 179/251] Remove pair from module when one of them are deleted --- modules/skybrowser/skybrowsermodule.cpp | 6 ++++-- modules/skybrowser/skybrowsermodule.h | 4 ++-- modules/skybrowser/skybrowsermodule_lua.inl | 8 ++++---- modules/skybrowser/src/screenspaceskybrowser.cpp | 6 ++++++ modules/skybrowser/src/screenspaceskytarget.cpp | 6 ++++++ 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index ccedd65484..7e486c2fbf 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -430,7 +430,7 @@ void SkyBrowserModule::setSelectedObject() } } -void SkyBrowserModule::addTargetBrowserPair(std::string targetId, std::string browserId) { +void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const std::string& browserId) { ScreenSpaceSkyTarget* target = dynamic_cast( global::renderEngine->screenSpaceRenderable(targetId) @@ -445,12 +445,14 @@ void SkyBrowserModule::addTargetBrowserPair(std::string targetId, std::string br } } -void SkyBrowserModule::removeTargetBrowserPair(std::string& id) { +void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) { Pair* found = getPair(id); if (!found) { return; } + found->getTarget()->setSkyBrowser(nullptr); + auto it = std::remove_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&](const std::unique_ptr& pair) { return *found == *(pair.get()); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 248765caf6..ac78f37d87 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -91,8 +91,8 @@ public: bool isCameraInSolarSystem(); // Managing the target browser pairs - void removeTargetBrowserPair(std::string& browserId); - void addTargetBrowserPair(std::string targetId, std::string browserId); + void removeTargetBrowserPair(const std::string& browserId); + void addTargetBrowserPair(const std::string& targetId, const std::string& browserId); // Hover circle void moveHoverCircle(int i); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 23b85e52e8..b1b01298a6 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -536,23 +536,23 @@ int createTargetBrowserPair(lua_State* L) { openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + browser + ");", - scripting::ScriptEngine::RemoteScripting::No + scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + target + ");", - scripting::ScriptEngine::RemoteScripting::No + scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::No + scripting::ScriptEngine::RemoteScripting::Yes ); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::No + scripting::ScriptEngine::RemoteScripting::Yes ); return 0; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index aab1129940..d79301f159 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -1,8 +1,10 @@ #include +#include #include #include #include +#include #include #include #include // formatJson @@ -121,7 +123,11 @@ namespace openspace { } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(identifier())) { + module->removeTargetBrowserPair(identifier()); + } } bool ScreenSpaceSkyBrowser::initializeGL() { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 52ea9d121e..60f4218cde 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,8 +1,10 @@ #include +#include #include #include #include +#include #include #include #include @@ -112,7 +114,11 @@ namespace openspace { } ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { + SkyBrowserModule* module = global::moduleEngine->module(); + if (module->getPair(identifier())) { + module->removeTargetBrowserPair(identifier()); + } } // Pure virtual in the screen space renderable class and hence must be defined From 2ee0ae03875d38edb682be7240c33bf244be6cad Mon Sep 17 00:00:00 2001 From: "ENG-VIDAVIZ-0\\ylvas" Date: Fri, 17 Dec 2021 11:11:23 -0500 Subject: [PATCH 180/251] Cleanup, set constants as static const expr --- modules/skybrowser/skybrowsermodule.cpp | 6 +++--- modules/skybrowser/skybrowsermodule.h | 9 +++++---- modules/skybrowser/skybrowsermodule_lua.inl | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 7e486c2fbf..f677834a30 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -661,13 +661,13 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { // Find smallest angle between the two vectors double angle = skybrowser::angleBetweenVectors(_startAnimation, _endAnimation); - if(angle > _stopAnimationThreshold) { + if(angle > StopAnimationThreshold) { glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( _startAnimation, _endAnimation, deltaTime, - _animationSpeed + AnimationSpeed ); // Rotate @@ -698,7 +698,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float if (pair->isEnabled()) { bool isPairFinished = pair->hasFinishedFading(transparency); if (!isPairFinished) { - pair->incrementallyFade(transparency, _fadingTime, deltaTime); + pair->incrementallyFade(transparency, FadingTime, deltaTime); } else if (isPairFinished && goal == Transparency::Transparent) { pair->setEnabled(false); diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index ac78f37d87..5d4c5f83be 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -56,6 +56,9 @@ class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; + constexpr static const double StopAnimationThreshold{ 0.0005 }; + constexpr static const double FadingTime = { 2.0 }; + constexpr static const double AnimationSpeed = { 1.0 }; const double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; // Constructor & destructor @@ -117,6 +120,8 @@ protected: private: properties::BoolProperty _allowMouseInteraction; properties::BoolProperty _allowCameraRotation; + glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers + // The browsers and targets std::vector> _targetsBrowsers; Pair* _mouseOnPair{ nullptr }; @@ -126,7 +131,6 @@ private: std::string _selectedBrowser{ "" }; // Currently selected browser (2D or 3D) // Fading - double _fadingTime = 2.0; Transparency _goal; // Flags @@ -141,11 +145,8 @@ private: glm::vec2 _startDragPosition; // Animation of rotation of camera to look at coordinate galactic coordinates - glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers glm::dvec3 _startAnimation; glm::dvec3 _endAnimation; - double _stopAnimationThreshold{ 0.05 }; - double _animationSpeed{ 1.0 }; // Data handler for the image collections std::unique_ptr _dataHandler; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index b1b01298a6..23b85e52e8 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -536,23 +536,23 @@ int createTargetBrowserPair(lua_State* L) { openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + browser + ");", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); openspace::global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + target + ");", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", - scripting::ScriptEngine::RemoteScripting::Yes + scripting::ScriptEngine::RemoteScripting::No ); return 0; From f2690909378831e53d34d467e8906ce897c85ae1 Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 17 Dec 2021 14:21:30 -0500 Subject: [PATCH 181/251] Change update structure from onChange functions to Pair so that Pair handles all communication between the target and browser --- modules/skybrowser/include/pair.h | 11 +++ .../include/screenspaceskybrowser.h | 13 +-- .../skybrowser/include/screenspaceskytarget.h | 12 ++- modules/skybrowser/include/wwtcommunicator.h | 9 +++ modules/skybrowser/skybrowsermodule.cpp | 33 +++++++- modules/skybrowser/skybrowsermodule_lua.inl | 81 ++++++++++++++++++- modules/skybrowser/src/pair.cpp | 69 ++++++++-------- .../skybrowser/src/screenspaceskybrowser.cpp | 64 +++------------ .../skybrowser/src/screenspaceskytarget.cpp | 46 +++-------- modules/skybrowser/src/wwtcommunicator.cpp | 28 ++++++- 10 files changed, 221 insertions(+), 145 deletions(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 6fffd23e22..f1a16d7c8b 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -62,6 +62,7 @@ public: bool isTargetSelected(); void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); void translateSelected(const glm::vec2& start, const glm::vec2& translation); + void synchronizeAim(); // Browser void sendIdToBrowser(); @@ -81,6 +82,10 @@ public: // Setters void setEnabled(bool enable); void setIsSyncedWithWwt(bool isSynced); + void setVerticalFov(float vfov); + void setEquatorialAim(const glm::dvec2& aim); + void setBorderColor(const glm::ivec3& color); + void setScreenSpaceSize(const glm::vec2& dimensions); // Getters by value float verticalFov() const; @@ -119,6 +124,12 @@ private: ScreenSpaceSkyTarget* _target{ nullptr }; ScreenSpaceSkyBrowser* _browser{ nullptr }; + + // Shared properties between the target and the browser + float _verticalFov{ 70.0f }; + glm::dvec2 _equatorialAim{ 0.0 }; + glm::ivec3 _borderColor{ 255 }; + glm::vec2 _dimensions{ 0.5f, 0.5f }; }; } // namespace openspace diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 62855fd4a5..7de2843a16 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -39,13 +39,6 @@ namespace openspace { void setOpacity(float opacity); void setScreenSpaceSize(const glm::vec2& newSize); - // Set callback functions - void setCallbackEquatorialAim(std::function function); - void setCallbackVerticalFov(std::function function); - void setCallbackDimensions(std::function function); - void setCallbackBorderColor(std::function function); - void setCallbackEnabled(std::function function); - glm::dvec2 fineTuneVector(glm::dvec2 drag); void setIdInBrowser(); @@ -62,14 +55,10 @@ namespace openspace { bool _isSyncedWithWwt{ false }; bool _isFovAnimated{ false }; bool _textureDimensionsIsDirty{ false }; + bool _sizeIsDirty{ false }; // Animation of fieldOfView float _endVfov{ 0.f }; - - // Time variables - // For capping the calls onchange properties from scrolling - constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; - std::chrono::system_clock::time_point _lastUpdateTime; }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index b1da07bc97..7b7b7fedc1 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -43,9 +43,6 @@ namespace openspace { void setLock(bool isLocked); void setEquatorialAim(const glm::dvec2& aim); - // Set callbacks - void setSkyBrowser(ScreenSpaceSkyBrowser* browser); - // Target directions glm::dvec3 directionGalactic() const; glm::dvec2 equatorialAim() const; @@ -86,10 +83,11 @@ namespace openspace { GLuint _vertexBuffer = 0; // Sky browser - glm::ivec3 _color; - ScreenSpaceSkyBrowser* _browser{ nullptr }; - float _verticalFov{ 0.f }; - + float _verticalFov{ 70.0f }; + glm::dvec2 _equatorialAim{ 0.0 }; + glm::ivec3 _borderColor{ 255 }; + glm::vec2 _dimensions{ 0.5f, 0.5f }; + // Lock target to a coordinate on the sky glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 9b1983d3d3..d9b1908889 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -67,6 +67,7 @@ public: void setVerticalFov(float vfov); void setIsSyncedWithWwt(bool isSynced); void setEquatorialAim(const glm::dvec2& equatorial); + void setBorderColor(const glm::ivec3& color); // Display void highlight(glm::ivec3 addition); @@ -89,6 +90,9 @@ protected: private: bool _isSyncedWithWwt{ false }; + bool _borderColorIsDirty{ false }; + bool _equatorialAimIsDirty{ false }; + void setWebpageBorderColor(glm::ivec3 color); void sendMessageToWwt(const ghoul::Dictionary& msg); @@ -105,6 +109,11 @@ private: ghoul::Dictionary setLayerOrder(const std::string& id, int version); ghoul::Dictionary hideChromeGui(bool isHidden); + // Time variables + // For capping the message passing to WWT + constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; + std::chrono::system_clock::time_point _lastUpdateTime; + }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index f677834a30..54304495e9 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -239,6 +239,34 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "setEquatorialAim", + &skybrowser::luascriptfunctions::setEquatorialAim, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "setVerticalFov", + &skybrowser::luascriptfunctions::setVerticalFov, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "setBorderColor", + &skybrowser::luascriptfunctions::setBorderColor, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, + { + "setScreenSpaceSize", + &skybrowser::luascriptfunctions::setScreenSpaceSize, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, }; return res; @@ -358,6 +386,10 @@ SkyBrowserModule::SkyBrowserModule() incrementallyFadeBrowserTargets(_goal, deltaTime); } if (_isCameraInSolarSystem) { + std::for_each(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + [&](const std::unique_ptr& pair) { + pair->synchronizeAim(); + }); incrementallyAnimateTargets(deltaTime); } if (_isCameraRotating && _allowCameraRotation) { @@ -451,7 +483,6 @@ void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) { if (!found) { return; } - found->getTarget()->setSkyBrowser(nullptr); auto it = std::remove_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&](const std::unique_ptr& pair) { diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 23b85e52e8..142836713d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -114,7 +114,6 @@ int unlockTarget(lua_State* L) { return 0; } - int setImageLayerOrder(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); const std::string id = ghoul::lua::value(L, 1); @@ -616,6 +615,86 @@ int removeSelectedImageInBrowser(lua_State* L) { } return 0; } + +int setEquatorialAim(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setEquatorialAim"); + // Browser id + const std::string id = ghoul::lua::value(L, 1); + double ra = ghoul::lua::value(L, 1); + double dec = ghoul::lua::value(L, 1); + + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + Pair* pair = module->getPair(id); + if (pair) { + pair->setEquatorialAim(glm::dvec2(ra, dec)); + } + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->setEquatorialAim(glm::dvec2(ra, dec)); + } + + return 0; +} + +int setVerticalFov(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setVerticalFov"); + // Browser id + const std::string id = ghoul::lua::value(L, 1); + float vfov = ghoul::lua::value(L, 1); + + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + Pair* pair = module->getPair(id); + if (pair) { + pair->setVerticalFov(vfov); + } + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->setVerticalFov(vfov); + } + + return 0; +} + +int setBorderColor(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::setBorderColor"); + // Browser id + const std::string id = ghoul::lua::value(L, 1); + int r = ghoul::lua::value(L, 1); + int g = ghoul::lua::value(L, 1); + int b = ghoul::lua::value(L, 1); + glm::ivec3 color{ r, g, b }; + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + Pair* pair = module->getPair(id); + if (pair) { + pair->setBorderColor(color); + } + else if (module->get3dBrowser(id)) { + module->get3dBrowser(id)->setBorderColor(color); + } + + return 0; +} + +int setScreenSpaceSize(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setBorderColor"); + // Browser id + const std::string id = ghoul::lua::value(L, 1); + float sizeX = ghoul::lua::value(L, 1); + float sizeY = ghoul::lua::value(L, 1); + + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + Pair* pair = module->getPair(id); + if (pair) { + pair->setScreenSpaceSize(glm::vec2(sizeX, sizeY)); + } + return 0; +} } diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index f567ea5e5b..5bf9de0d36 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -42,39 +42,6 @@ namespace openspace { { ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); ghoul_assert(target != nullptr, "Sky target is null pointer!"); - - // Set browser callback functions - // Set callback functions so that the target and the browser update each other - /* - _browser->setCallbackEquatorialAim( - [&](const glm::dvec2& equatorialAim) { - _target->setEquatorialAim(equatorialAim); - } - ); - */ - _browser->setCallbackBorderColor( - [&](const glm::ivec3& color) { - _target->setColor(color); - } - ); - _browser->setCallbackVerticalFov( - [&](float vfov) { - _target->setScaleFromVfov(vfov); - } - ); - _browser->setCallbackDimensions( - [&](const glm::vec2& dimensions) { - _target->setDimensions(dimensions); - } - ); - // Always make sure that the target and browser are visible together - _browser->setCallbackEnabled( - [&](bool enabled) { - _target->setEnabled(enabled); - } - ); - - _target->setSkyBrowser(_browser); } Pair& Pair::operator=(Pair other) @@ -168,6 +135,14 @@ namespace openspace { _selected->translate(translation, start); } + void Pair::synchronizeAim() + { + if (!_target->isAnimated()) { + _browser->setEquatorialAim(_target->equatorialAim()); + _target->setScaleFromVfov(_browser->verticalFov()); + } + } + void Pair::setEnabled(bool enable) { _browser->setEnabled(enable); @@ -280,6 +255,34 @@ namespace openspace { _browser->setIsSyncedWithWwt(isSynced); } + void Pair::setVerticalFov(float vfov) + { + _verticalFov = vfov; + _browser->setVerticalFov(vfov); + _target->setScaleFromVfov(vfov); + } + + void Pair::setEquatorialAim(const glm::dvec2& aim) + { + _equatorialAim = aim; + _target->setEquatorialAim(aim); + _browser->setEquatorialAim(aim); + } + + void Pair::setBorderColor(const glm::ivec3& color) + { + _borderColor = color; + _target->setColor(color); + _browser->setBorderColor(color); + } + + void Pair::setScreenSpaceSize(const glm::vec2& dimensions) + { + _dimensions = dimensions; + _target->setDimensions(dimensions); + _browser->setScreenSpaceSize(dimensions); + } + void Pair::incrementallyAnimateToCoordinate(double deltaTime) { // Animate the target before the field of view starts to animate diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index d79301f159..01016eade1 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -113,7 +113,7 @@ namespace openspace { _textureDimensionsIsDirty = true; }); _size.onChange([this]() { - setScreenSpaceSize(_size); + _sizeIsDirty = true; }); // Ensure that the browser is placed at the z-coordinate of the screen space plane @@ -125,7 +125,7 @@ namespace openspace { ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(identifier())) { + if (module && module->getPair(identifier())) { module->removeTargetBrowserPair(identifier()); } } @@ -175,6 +175,7 @@ namespace openspace { bool ScreenSpaceSkyBrowser::deinitializeGL() { ScreenSpaceRenderable::deinitializeGL(); WwtCommunicator::deinitializeGL(); + return true; } @@ -223,7 +224,10 @@ namespace openspace { updateTextureResolution(); _textureDimensionsIsDirty = false; } - + if (_sizeIsDirty) { + setScreenSpaceSize(_size); + _sizeIsDirty = false; + } _objectSize = _texture->dimensions(); WwtCommunicator::update(); @@ -231,18 +235,11 @@ namespace openspace { } void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { - // Cap how often the zoom is allowed to update - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; - - if (timeSinceLastUpdate > _timeUpdateInterval) { - // Make scroll more sensitive the smaller the FOV - float x = _verticalFov; - float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; - float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); - _lastUpdateTime = std::chrono::system_clock::now(); - } + // Make scroll more sensitive the smaller the FOV + float x = _verticalFov; + float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; + float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; + _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); } void ScreenSpaceSkyBrowser::bindTexture() @@ -263,43 +260,6 @@ namespace openspace { return scale; } - void ScreenSpaceSkyBrowser::setCallbackEquatorialAim( - std::function function) - { - _equatorialAim.onChange([this, f = std::move(function)]() { - f(_equatorialAim); - }); - - } - void ScreenSpaceSkyBrowser::setCallbackVerticalFov( - std::function function) - { - _verticalFov.onChange([this, f = std::move(function)]() { - f(_verticalFov.value()); - }); - - } - void ScreenSpaceSkyBrowser::setCallbackDimensions( - std::function function) - { - _browserPixeldimensions.onChange([this, f = std::move(function)]() { - f(_browserPixeldimensions); - }); - - } - void ScreenSpaceSkyBrowser::setCallbackBorderColor( - std::function function) { - _borderColor.onChange([this, f = std::move(function)]() { - f(_borderColor.value()); - }); - } - void ScreenSpaceSkyBrowser::setCallbackEnabled(std::function function) - { - _enabled.onChange([this, f = std::move(function)]() { - f(_enabled); - }); - } - void ScreenSpaceSkyBrowser::setOpacity(float opacity) { _opacity = opacity; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 60f4218cde..ab0b5ff4bd 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -80,7 +80,7 @@ namespace openspace { , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) - , _color(220, 220, 220) + , _borderColor(220, 220, 220) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); @@ -116,7 +116,7 @@ namespace openspace { ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(identifier())) { + if (module && module->getPair(identifier())) { module->removeTargetBrowserPair(identifier()); } } @@ -173,11 +173,11 @@ namespace openspace { } void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) { - _color = color; + _borderColor = color; } glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { - return _color; + return _borderColor; } void ScreenSpaceSkyTarget::render() { @@ -185,7 +185,7 @@ namespace openspace { bool showCrosshair = _verticalFov < _showCrosshairThreshold; bool showRectangle = _verticalFov > _showRectangleThreshold; - glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() }; + glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); float lineWidth = 0.0016f/_scale.value(); @@ -231,23 +231,6 @@ namespace openspace { } } - // Optimization: Only pass messages to the browser when the target is not moving - if (_browser && !_isAnimated) { - const std::chrono::time_point - timeBefore = std::chrono::high_resolution_clock::now(); - - std::chrono::microseconds duration = - std::chrono::duration_cast( - timeBefore - latestCall - ); - - if (duration > interval) { - // Message WorldWide Telescope current view - _browser->setEquatorialAim(equatorialAim()); // Use camera roll - - latestCall = std::chrono::high_resolution_clock::now(); - } - } } void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { @@ -383,12 +366,12 @@ namespace openspace { void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) { - _color += addition; + _borderColor += addition; } void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal) { - _color -= removal; + _borderColor -= removal; } float ScreenSpaceSkyTarget::opacity() const { @@ -407,6 +390,9 @@ namespace openspace { } void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) { + _isAnimated = false; + _isLocked = false; + glm::dvec3 cartesianAim = skybrowser::sphericalToCartesian(aim); glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(cartesianAim); if (_useRadiusAzimuthElevation) { @@ -418,16 +404,4 @@ namespace openspace { _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); } } - void ScreenSpaceSkyTarget::setSkyBrowser(ScreenSpaceSkyBrowser* browser) - { - _browser = browser; - _enabled.onChange([this]() { - _browser->setEnabled(_enabled); - }); - /* _scale.onChange([&]() { - - setFovFromScale(); - _browser->setVerticalFov(_verticalFov); - }); */ - } } diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index d635e365bf..bc61db694d 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -69,7 +69,7 @@ namespace openspace { glm::dvec2(360.0, 90.0)) { _borderColor.onChange([this]() { - updateBorderColor(); + _borderColorIsDirty = true; }); } @@ -111,7 +111,7 @@ namespace openspace { void WwtCommunicator::setVerticalFov(float vfov) { _verticalFov = vfov; - updateAim(); + _equatorialAimIsDirty = true; } void WwtCommunicator::setWebpageBorderColor(glm::ivec3 color) { @@ -130,7 +130,13 @@ namespace openspace { void WwtCommunicator::setEquatorialAim(const glm::dvec2& equatorial) { _equatorialAim = equatorial; - updateAim(); + _equatorialAimIsDirty = true; + } + + void WwtCommunicator::setBorderColor(const glm::ivec3& color) + { + _borderColor = color; + _borderColorIsDirty = true; } void WwtCommunicator::highlight(glm::ivec3 addition) @@ -215,6 +221,22 @@ namespace openspace { void WwtCommunicator::update() { Browser::update(); + // Cap how messages are passed + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; + + if (timeSinceLastUpdate > _timeUpdateInterval) { + + if (_equatorialAimIsDirty) { + updateAim(); + _equatorialAimIsDirty = false; + } + if (_borderColorIsDirty) { + updateBorderColor(); + _borderColorIsDirty = false; + } + _lastUpdateTime = std::chrono::system_clock::now(); + } } void WwtCommunicator::render() From 63ac90b93f61e19710d8dc007f81214b24e9c198 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 28 Dec 2021 07:29:39 -0500 Subject: [PATCH 182/251] Fix "drag" in wwt position that is created when moving the camera around --- modules/skybrowser/include/screenspaceskytarget.h | 1 + modules/skybrowser/src/pair.cpp | 12 +++++++++++- modules/skybrowser/src/screenspaceskytarget.cpp | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 7b7b7fedc1..65a68fa2af 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -33,6 +33,7 @@ namespace openspace { glm::ivec3 borderColor() const; float opacity() const; + glm::dvec2 lockedCoordinates() const; // Setters void setScaleFromVfov(float verticalFov); diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 5bf9de0d36..571de20c83 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -138,7 +138,17 @@ namespace openspace { void Pair::synchronizeAim() { if (!_target->isAnimated()) { - _browser->setEquatorialAim(_target->equatorialAim()); + glm::dvec2 aim; + // To remove the lag effect when moving the camera while having a locked + // target, send the locked coordinates to wwt + if (_target->isLocked()) { + aim = _target->lockedCoordinates(); + } + else { + aim = _target->equatorialAim(); + } + + _browser->setEquatorialAim(aim); _target->setScaleFromVfov(_browser->verticalFov()); } } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index ab0b5ff4bd..db94466536 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -378,6 +378,11 @@ namespace openspace { return _opacity.value(); } + glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const + { + return skybrowser::cartesianToSpherical(_lockedCoordinates); + } + void ScreenSpaceSkyTarget::setOpacity(float opacity) { _opacity = opacity; } From a07b4a5afeb4fd933382d45d6885afa6df63f20d Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 28 Dec 2021 08:09:31 -0500 Subject: [PATCH 183/251] Ensure all nodes in a cluster establish contact with their own instance of the wwt application (needs an updated website version - this update will not work with the current website version on the server) --- modules/skybrowser/skybrowsermodule.cpp | 7 +++++++ modules/skybrowser/skybrowsermodule_lua.inl | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 54304495e9..bbe5e6a34f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -267,6 +267,13 @@ namespace openspace { "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, + { + "startSetup", + &skybrowser::luascriptfunctions::startSetup, + "string or list of strings", + "Add one or multiple exoplanet systems to the scene, as specified by the " + "input. An input string should be the name of the system host star" + }, }; return res; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 142836713d..3ede08a758 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -163,6 +163,20 @@ int loadImagesToWWT(lua_State* L) { return 0; } +int startSetup(lua_State* L) { + // This is called when the sky_browser website is connected to OpenSpace + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::startSetup"); + + // To ensure each node in a cluster calls its own instance of the wwt application + // Do not send this script to the other nodes + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.sendOutIdsToBrowsers();", + scripting::ScriptEngine::RemoteScripting::No + ); + + return 0; +} + int sendOutIdsToBrowsers(lua_State* L) { // This is called when the sky_browser website is connected to OpenSpace ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers"); @@ -512,8 +526,8 @@ int createTargetBrowserPair(lua_State* L) { std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; - std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - //std::string url = "http://localhost:8000"; // check webgl version + //std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; + std::string url = "http://localhost:8000"; // check webgl version //std::string url = "https://get.webgl.org"; glm::ivec3 color = randomBorderColor(); From dbd69cdd73c0295be78e5dd0166c5f08b1dce810 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 25 Jan 2022 09:33:02 -0500 Subject: [PATCH 184/251] Add size getter and pass size and color to gui --- modules/skybrowser/include/pair.h | 1 + modules/skybrowser/include/screenspaceskybrowser.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 6 ++++++ modules/skybrowser/src/pair.cpp | 5 +++++ modules/skybrowser/src/screenspaceskybrowser.cpp | 7 ++++++- 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index f1a16d7c8b..7f799ef21b 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -95,6 +95,7 @@ public: std::string browserGuiName() const; std::string browserId() const; std::string targetId() const; + glm::vec2 size() const; // Getters by reference ScreenSpaceSkyTarget* getTarget(); diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 7de2843a16..0e446577eb 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -33,6 +33,7 @@ namespace openspace { // Getters float opacity() const; + glm::vec2 size() const; // Setters void setVerticalFovWithScroll(float scroll); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 3ede08a758..0b2009c116 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -378,6 +378,10 @@ int getTargetData(lua_State* L) { glm::ivec3 color = pair->borderColor(); std::vector colorVec = { color.r, color.g, color.b }; + // Convert color to vector so ghoul can read it + glm::vec2 size = pair->size(); + std::vector sizeVec = { size.x, size.y }; + ghoul::lua::push(L, id); lua_newtable(L); // Push ("Key", value) @@ -399,6 +403,8 @@ int getTargetData(lua_State* L) { lua_settable(L, -3); ghoul::lua::push(L, "isLocked", pair->isLocked()); lua_settable(L, -3); + ghoul::lua::push(L, "size", sizeVec); + lua_settable(L, -3); // Set table for the current target lua_settable(L, -3); diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 571de20c83..056fe67865 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -207,6 +207,11 @@ namespace openspace { return _target->identifier(); } + glm::vec2 Pair::size() const + { + return _browser->size(); + } + float Pair::verticalFov() const { return _browser->verticalFov(); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 01016eade1..b67bc4a347 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -266,7 +266,8 @@ namespace openspace { } void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) - { + { + _size = newSize; _scale = abs(newSize.y) * 0.5f; glm::vec2 newSizeRelToOld = abs((screenSpaceDimensions() + newSize) / screenSpaceDimensions()); @@ -284,4 +285,8 @@ namespace openspace { float ScreenSpaceSkyBrowser::opacity() const { return _opacity; } + glm::vec2 ScreenSpaceSkyBrowser::size() const + { + return _size; + } } From 779a56662e78d6531e48c3102f01532555cf60a4 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 26 Jan 2022 03:37:52 -0500 Subject: [PATCH 185/251] Create set vertical fov function in pair --- modules/skybrowser/include/pair.h | 2 ++ modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/src/pair.cpp | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 7f799ef21b..7b427d4a39 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -86,6 +86,7 @@ public: void setEquatorialAim(const glm::dvec2& aim); void setBorderColor(const glm::ivec3& color); void setScreenSpaceSize(const glm::vec2& dimensions); + void setVerticalFovWithScroll(float scroll); // Getters by value float verticalFov() const; @@ -97,6 +98,7 @@ public: std::string targetId() const; glm::vec2 size() const; + // Getters by reference ScreenSpaceSkyTarget* getTarget(); ScreenSpaceSkyBrowser* getBrowser(); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index bbe5e6a34f..02fce4435b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -356,7 +356,7 @@ SkyBrowserModule::SkyBrowserModule() return false; } // If mouse is on browser or target, apply zoom - _mouseOnPair->getBrowser()->setVerticalFovWithScroll( + _mouseOnPair->setVerticalFovWithScroll( static_cast(scroll) ); return true; diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 056fe67865..666f2ac65d 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -298,6 +298,11 @@ namespace openspace { _browser->setScreenSpaceSize(dimensions); } + void Pair::setVerticalFovWithScroll(float scroll) + { + _browser->setVerticalFovWithScroll(scroll); + } + void Pair::incrementallyAnimateToCoordinate(double deltaTime) { // Animate the target before the field of view starts to animate From 835e8d2f428822f6f129c0c587a00d1f54d90a4f Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 26 Jan 2022 03:38:33 -0500 Subject: [PATCH 186/251] Fix bugs with resizing browser --- modules/skybrowser/include/screenspaceskytarget.h | 1 - modules/skybrowser/src/browser.cpp | 13 ++++++------- modules/skybrowser/src/screenspaceskybrowser.cpp | 3 ++- modules/skybrowser/src/screenspaceskytarget.cpp | 5 +++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 65a68fa2af..e8238fb2ad 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -87,7 +87,6 @@ namespace openspace { float _verticalFov{ 70.0f }; glm::dvec2 _equatorialAim{ 0.0 }; glm::ivec3 _borderColor{ 255 }; - glm::vec2 _dimensions{ 0.5f, 0.5f }; // Lock target to a coordinate on the sky glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index ed536a17d4..e235fe0845 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -151,19 +151,18 @@ namespace openspace { _browserInstance->loadUrl(_url); _isUrlDirty = false; } - if (_isDimensionsDirty) { - ghoul_assert(_browserPixeldimensions.value().x > 0 && - _browserPixeldimensions.value().y > 0); - - _browserInstance->reshape(_browserPixeldimensions.value()); - _isDimensionsDirty = false; + if (_browserPixeldimensions.value().x > 0 && + _browserPixeldimensions.value().y > 0) { + _browserInstance->reshape(_browserPixeldimensions.value()); + _isDimensionsDirty = false; + } } if (_shouldReload) { _browserInstance->reloadBrowser(); _shouldReload = false; - } + } } bool Browser::isReady() const { diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index b67bc4a347..d18b6ff721 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -267,7 +267,7 @@ namespace openspace { void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) { - _size = newSize; + _scale = abs(newSize.y) * 0.5f; glm::vec2 newSizeRelToOld = abs((screenSpaceDimensions() + newSize) / screenSpaceDimensions()); @@ -280,6 +280,7 @@ namespace openspace { _objectSize = _texture->dimensions(); updateTextureResolution(); + _size = newSize; } float ScreenSpaceSkyBrowser::opacity() const { diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index db94466536..3c884b52bb 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -234,12 +234,13 @@ namespace openspace { } void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { - _objectSize = dimensions; + // To avoid flooring of the size of the target, multiply by factor of 100 + // Object size is really the pixel size so this calculation is not exact + _objectSize = glm::ivec2(dimensions * 100.f); } glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { - glm::vec3 localCamera = _cartesianPosition.value(); if (_useRadiusAzimuthElevation) { From f8936db40cfdd9992f3517a8c4b2fabb522fbb0d Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 26 Jan 2022 05:41:16 -0500 Subject: [PATCH 187/251] Remove sky browser properties from the screen space renderables --- .../include/screenspaceskybrowser.h | 3 +- .../skybrowser/include/screenspaceskytarget.h | 2 +- modules/skybrowser/include/wwtcommunicator.h | 6 +- modules/skybrowser/skybrowsermodule_lua.inl | 19 +--- .../skybrowser/src/renderableskybrowser.cpp | 3 - .../skybrowser/src/screenspaceskybrowser.cpp | 91 +++++++------------ modules/skybrowser/src/wwtcommunicator.cpp | 34 +------ 7 files changed, 41 insertions(+), 117 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 0e446577eb..e79bc50265 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -39,6 +39,7 @@ namespace openspace { void setVerticalFovWithScroll(float scroll); void setOpacity(float opacity); void setScreenSpaceSize(const glm::vec2& newSize); + void updateScreenSpaceSize(); glm::dvec2 fineTuneVector(glm::dvec2 drag); void setIdInBrowser(); @@ -48,7 +49,6 @@ namespace openspace { private: properties::DoubleProperty _animationSpeed; properties::FloatProperty _textureQuality; - properties::Vec2Property _size; void bindTexture() override; @@ -60,6 +60,7 @@ namespace openspace { // Animation of fieldOfView float _endVfov{ 0.f }; + glm::vec2 _size{ 0.5f }; }; } diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index e8238fb2ad..7a475ea0db 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -96,7 +96,7 @@ namespace openspace { glm::dvec3 _animationStart; // Cartesian equatorial coordinates // Time variables - // For capping the set equatorial coordinates to sky browser + // For capping sending of equatorial coordinates to sky browser const std::chrono::microseconds interval = std::chrono::microseconds(10000); std::chrono::time_point latestCall; constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index d9b1908889..1cc582e293 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -80,9 +80,9 @@ protected: // Web page communication void setIdInBrowser(const std::string& id); - properties::DVec2Property _equatorialAim; - properties::FloatProperty _verticalFov; - properties::IVec3Property _borderColor; + glm::dvec2 _equatorialAim; + float _verticalFov{ 10.f }; + glm::ivec3 _borderColor; std::deque _selectedImages; bool _hasLoadedImages{ false }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 0b2009c116..9973fd6ddb 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -8,26 +8,11 @@ #include #include #include -#include // For hsv color -#include // For random color namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; } // namespace -glm::ivec3 randomBorderColor() { - // Generate a random border color with sufficient lightness and a n - std::random_device rd; - // Hue is in the unit degrees [0, 360] - std::uniform_real_distribution hue(0.f, 360.f); - // Value in saturation are in the unit percent [0,1] - float value = 0.95f; // Brightness - float saturation = 0.5f; - glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); - glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); - return rgbColor; -} - namespace openspace::skybrowser::luascriptfunctions { int selectImage(lua_State* L) { @@ -535,7 +520,6 @@ int createTargetBrowserPair(lua_State* L) { //std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; std::string url = "http://localhost:8000"; // check webgl version //std::string url = "https://get.webgl.org"; - glm::ivec3 color = randomBorderColor(); const std::string browser = "{" "Identifier = '" + idBrowser + "'," @@ -543,8 +527,7 @@ int createTargetBrowserPair(lua_State* L) { "Name = '" + nameBrowser + "'," "Url = '" + url + "'," "FaceCamera = false," - "CartesianPosition = " + ghoul::to_string(positionBrowser) + "," - "BorderColor = " + ghoul::to_string(color) + "," + "CartesianPosition = " + ghoul::to_string(positionBrowser) + "}"; const std::string target = "{" "Identifier = '" + idTarget + "'," diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp index 727c39fa19..662f4305b9 100644 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ b/modules/skybrowser/src/renderableskybrowser.cpp @@ -74,9 +74,6 @@ namespace openspace { addProperty(_url); addProperty(_browserPixeldimensions); addProperty(_reload); - addProperty(_verticalFov); - addProperty(_borderColor); - addProperty(_equatorialAim); } RenderableSkyBrowser::~RenderableSkyBrowser() { diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index d18b6ff721..f2af2b017f 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -10,24 +10,14 @@ #include // formatJson #include #include +#include // For hsv color +#include // For random color #include #pragma optimize("", off) namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; - constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = - { - "BorderColor", - "Border Color", - "The color of the border of the sky browser." - }; - constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = - { - "VerticalFieldOfView", - "Vertical Field Of View", - "The vertical field of view in degrees." - }; constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { "AnimationSpeed", @@ -42,35 +32,32 @@ namespace { "slower framerate. Lower value means lower resolution of texture and faster " "frame rate." }; - constexpr const openspace::properties::Property::PropertyInfo SizeInfo = - { - "Size", - "Screen space size of the sky browser", - "The size of the sky browser determines how large is on screen. The y parameter " - "determines the percentage of the screen the browser will cover in the " - "y-direction. The x parameter determines how large the sky browser will be in " - "the x direction." - }; - struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - // [[codegen::verbatim(VerticalFovInfo.description)]] - std::optional verticalFov; - - // [[codegen::verbatim(BorderColorInfo.description)]] - std::optional borderColor; - // [[codegen::verbatim(AnimationSpeedInfo.description)]] std::optional animationSpeed; // [[codegen::verbatim(TextureQualityInfo.description)]] - std::optional textureQuality; + std::optional textureQuality; }; #include "ScreenSpaceSkyBrowser_codegen.cpp" } // namespace +glm::ivec3 randomBorderColor() { + // Generate a random border color with sufficient lightness and a n + std::random_device rd; + // Hue is in the unit degrees [0, 360] + std::uniform_real_distribution hue(0.f, 360.f); + // Value in saturation are in the unit percent [0,1] + float value = 0.95f; // Brightness + float saturation = 0.5f; + glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); + glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); + return rgbColor; +} + namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) @@ -78,7 +65,6 @@ namespace openspace { , WwtCommunicator(dictionary) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) - , _size(SizeInfo, glm::vec2(0.5f), glm::vec2(0.f), glm::vec2(2.f)) { // Set a unique identifier std::string identifier; @@ -91,35 +77,25 @@ namespace openspace { identifier = makeUniqueIdentifier(identifier); setIdentifier(identifier); - // Make the color property display a color picker in the GUI - _borderColor.setViewOption(properties::Property::ViewOptions::Color, true); - // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _verticalFov = p.verticalFov.value_or(_verticalFov); - _borderColor = p.borderColor.value_or(_borderColor); _textureQuality = p.textureQuality.value_or(_textureQuality); + _animationSpeed = p.animationSpeed.value_or(_animationSpeed); addProperty(_url); addProperty(_browserPixeldimensions); addProperty(_reload); - addProperty(_verticalFov); - addProperty(_borderColor); - addProperty(_equatorialAim); addProperty(_textureQuality); - addProperty(_size); _textureQuality.onChange([this]() { _textureDimensionsIsDirty = true; }); - _size.onChange([this]() { - _sizeIsDirty = true; - }); // Ensure that the browser is placed at the z-coordinate of the screen space plane glm::vec2 screenPosition = _cartesianPosition.value(); - _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); - + _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + + _borderColor = randomBorderColor(); } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { @@ -165,7 +141,8 @@ namespace openspace { // If the scale is 1, it covers half the window. Hence multiplication with 2 float newResY = pixels.y * 2.f * _scale; - float newResX = newResY * (_browserPixeldimensions.value().x / _browserPixeldimensions.value().y); + float ratio = _size.x / _size.y; + float newResX = newResY * ratio; glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value(); _browserPixeldimensions = glm::ivec2(newSize); @@ -225,10 +202,9 @@ namespace openspace { _textureDimensionsIsDirty = false; } if (_sizeIsDirty) { - setScreenSpaceSize(_size); + updateScreenSpaceSize(); _sizeIsDirty = false; } - _objectSize = _texture->dimensions(); WwtCommunicator::update(); ScreenSpaceRenderable::update(); @@ -267,20 +243,15 @@ namespace openspace { void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) { - - _scale = abs(newSize.y) * 0.5f; - glm::vec2 newSizeRelToOld = abs((screenSpaceDimensions() + newSize) / - screenSpaceDimensions()); - glm::vec2 newDimensions = newSizeRelToOld * glm::vec2(_texture->dimensions()); - // Scale the browser - // Scale on the y axis, this is to ensure that _scale = 1 is - // equal to the height of the window - _browserPixeldimensions = glm::ivec2(newDimensions); - _texture->setDimensions(glm::ivec3(newDimensions, 1)); - _objectSize = _texture->dimensions(); - - updateTextureResolution(); _size = newSize; + _sizeIsDirty = true; + } + + void ScreenSpaceSkyBrowser::updateScreenSpaceSize() + { + _scale = abs(_size.y) * 0.5f; + updateTextureResolution(); + _objectSize = _texture->dimensions(); } float ScreenSpaceSkyBrowser::opacity() const { diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index bc61db694d..227a96f6e8 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -37,41 +37,13 @@ namespace { constexpr const char* _loggerCat = "WwtCommunicator"; - constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo = - { - "BorderColor", - "Border Color", - "The color of the border of the sky browser." - }; - constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo = - { - "VerticalFieldOfView", - "Vertical Field Of View", - "The vertical field of view in degrees." - }; - constexpr const openspace::properties::Property::PropertyInfo EquatorialAimInfo = - { - "EquatorialAim", - "Equatorial aim of the sky browser", - "The aim of the sky browser given in spherical equatorial coordinates right " - "ascension (RA) and declination (Dec) in epoch J2000. The unit is degrees." - }; } // namespace namespace openspace { WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary) - : Browser(dictionary), - _verticalFov(VerticalFovInfo, 10.f, 0.01f, 70.0f), - _borderColor(BorderColorInfo, glm::ivec3(200), glm::ivec3(0), glm::ivec3(255)), - _equatorialAim(EquatorialAimInfo, glm::dvec2(0.0), glm::dvec2(0.0, -90.0), - glm::dvec2(360.0, 90.0)) - { - _borderColor.onChange([this]() { - _borderColorIsDirty = true; - }); - } + : Browser(dictionary) {} WwtCommunicator::~WwtCommunicator() { @@ -141,12 +113,12 @@ namespace openspace { void WwtCommunicator::highlight(glm::ivec3 addition) { - setWebpageBorderColor(_borderColor.value() + addition); + setWebpageBorderColor(_borderColor + addition); } void WwtCommunicator::removeHighlight(glm::ivec3 removal) { - setWebpageBorderColor(_borderColor.value() - removal); + setWebpageBorderColor(_borderColor - removal); } void WwtCommunicator::updateBorderColor() From 51280562721f903f720eaa567af2cfcd587af66c Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 26 Jan 2022 05:41:46 -0500 Subject: [PATCH 188/251] Make hover circle work again and remove unneccessary conversion function --- data/assets/hoverCircle.asset | 2 +- .../openspace/rendering/screenspacerenderable.h | 6 ++++-- modules/skybrowser/include/utility.h | 3 +-- modules/skybrowser/skybrowsermodule.cpp | 17 ++++++++++++----- modules/skybrowser/src/utility.cpp | 13 +++---------- src/rendering/screenspacerenderable.cpp | 16 +++++++++++++++- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index 23c7fd2fbb..4110a238ed 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -9,7 +9,7 @@ local circle = { FaceCamera = false, UseRadiusAzimuthElevation = false, RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome - Scale= 0.015, + Scale= 0.025, Enabled = false, TexturePath = "${ASSETS}/circle.png", CartesianPosition = { 0, 0, -2.1 }, diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 0881eaf718..123b294936 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -69,6 +69,7 @@ public: virtual void update(); virtual bool isReady() const; bool isEnabled() const; + bool isUsingRaeCoords() const; void setEnabled(bool isEnabled); float depth(); @@ -80,8 +81,9 @@ public: glm::vec2 lowerLeftCornerScreenSpace(); bool intersection(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); - void setPosition(const glm::vec3& position); - + void setCartesianPosition(const glm::vec3& position); + void setRaeFromCartesianPosition(const glm::vec3& position); + glm::vec3 raePosition() const; // End of addition by skybrowser team static documentation::Documentation Documentation(); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 60eb5bc256..c8c394a411 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -28,8 +28,7 @@ namespace openspace { glm::dvec3 galacticToEquatorial(const glm::dvec3& coords); glm::dvec3 equatorialToGalactic(const glm::dvec3& coords); - // Conversion to screen space from J2000 equatorial / galactic / pixels - glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords); + // Conversion to screen space from local camera / pixels glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords); glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 02fce4435b..d711a770f8 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -532,11 +532,18 @@ void SkyBrowserModule::moveHoverCircle(int i) // Make circle visible _hoverCircle->setEnabled(true); - // Calculate coords for the circle and translate - glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace3d( - image.equatorialCartesian - ); - _hoverCircle->setPosition(coordsScreen); + // Set the exact target position + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(image.equatorialCartesian); + + if (_hoverCircle->isUsingRaeCoords()) { + glm::vec3 position = _hoverCircle->raePosition().x * glm::vec3(localCamera); + _hoverCircle->setRaeFromCartesianPosition(position); + } + else { + _hoverCircle->setCartesianPosition( + skybrowser::localCameraToScreenSpace3d(localCamera) + ); + } } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 86c687e81b..2003724fb0 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -99,14 +99,6 @@ namespace openspace::skybrowser { return glm::normalize(viewDirectionLocal); } - glm::dvec3 equatorialToScreenSpace3d(const glm::dvec3& coords) { - // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 galactic = equatorialToGalactic(coords); - glm::dvec3 localCameraSpace = galacticToLocalCamera(coords); - // Transform galactic coord to screen space - return localCameraToScreenSpace3d(localCameraSpace); - } - double cameraRoll() { openspace::Camera* camera = global::navigationHandler->camera(); glm::dvec3 upWorld = camera->lookUpVectorWorldSpace(); @@ -141,9 +133,10 @@ namespace openspace::skybrowser { return windowRatio.x / windowRatio.y; } - bool isCoordinateInView(const glm::dvec3& equatorial) { + bool isCoordinateInView(const glm::dvec3& equatorial) { // Check if image coordinate is within current FOV - glm::dvec3 coordsScreen = equatorialToScreenSpace3d(equatorial); + glm::dvec3 localCamera = equatorialToLocalCamera(equatorial); + glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera); double r = static_cast(windowRatio()); bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f && diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index c7f5018048..411d6aa630 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -460,6 +460,10 @@ void ScreenSpaceRenderable::update() {} bool ScreenSpaceRenderable::isEnabled() const { return _enabled; } +bool ScreenSpaceRenderable::isUsingRaeCoords() const +{ + return _useRadiusAzimuthElevation; +} void ScreenSpaceRenderable::setEnabled(bool isEnabled) { _enabled = isEnabled; @@ -550,11 +554,21 @@ void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) _cartesianPosition = translationMatrix * origin; } -void ScreenSpaceRenderable::setPosition(const glm::vec3& position) +void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) { _cartesianPosition = position; } +void ScreenSpaceRenderable::setRaeFromCartesianPosition(const glm::vec3& position) +{ + _raePosition = cartesianToRae(position); +} + +glm::vec3 ScreenSpaceRenderable::raePosition() const +{ + return _raePosition; +} + glm::mat4 ScreenSpaceRenderable::globalRotationMatrix() { // We do not want the screen space planes to be affected by // 1) The global rotation of the view applied in the render engine From d28de2e9ef97bb9afd8739c16e5806a67d579977 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 26 Jan 2022 08:54:53 -0500 Subject: [PATCH 189/251] Fix bug with translation --- modules/skybrowser/src/screenspaceskybrowser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index f2af2b017f..8a41ddc13c 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -147,6 +147,7 @@ namespace openspace { _browserPixeldimensions = glm::ivec2(newSize); _texture->setDimensions(glm::ivec3(newSize, 1)); + _objectSize = glm::ivec3(_texture->dimensions()); } bool ScreenSpaceSkyBrowser::deinitializeGL() { @@ -251,7 +252,6 @@ namespace openspace { { _scale = abs(_size.y) * 0.5f; updateTextureResolution(); - _objectSize = _texture->dimensions(); } float ScreenSpaceSkyBrowser::opacity() const { From 51496956fc82883ffccfb4bf9735b48ef4ac7aea Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 7 Feb 2022 09:46:00 -0500 Subject: [PATCH 190/251] Pass data regarding if sky browser and target are facing camera and using radius azimuth elevation to gui --- .../rendering/screenspacerenderable.h | 1 + modules/skybrowser/include/pair.h | 3 +- modules/skybrowser/skybrowsermodule.cpp | 30 +++++++++++++++++++ modules/skybrowser/skybrowsermodule.h | 3 ++ modules/skybrowser/skybrowsermodule_lua.inl | 6 ++++ modules/skybrowser/src/pair.cpp | 10 +++++++ src/rendering/screenspacerenderable.cpp | 4 +++ 7 files changed, 56 insertions(+), 1 deletion(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 123b294936..d074ca35e8 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -70,6 +70,7 @@ public: virtual bool isReady() const; bool isEnabled() const; bool isUsingRaeCoords() const; + bool isFacingCamera() const; void setEnabled(bool isEnabled); float depth(); diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h index 7b427d4a39..ed6028bedd 100644 --- a/modules/skybrowser/include/pair.h +++ b/modules/skybrowser/include/pair.h @@ -75,7 +75,8 @@ public: // Boolean functions bool hasFinishedFading(float goalState) const; - + bool isFacingCamera() const; + bool isUsingRadiusAzimuthElevation() const; bool isEnabled() const; bool isLocked() const; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index d711a770f8..1aae807a4b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -777,10 +777,40 @@ std::string SkyBrowserModule::selectedBrowserId() { return _selectedBrowser; } +std::string SkyBrowserModule::selectedTargetId() +{ + if (getPair(_selectedBrowser)) { + return getPair(_selectedBrowser)->targetId(); + } + else { + return ""; + } +} + bool SkyBrowserModule::isCameraInSolarSystem() { return _isCameraInSolarSystem; } +bool SkyBrowserModule::isSelectedPairUsingRae() +{ + if (getPair(_selectedBrowser)) { + return getPair(_selectedBrowser)->isUsingRadiusAzimuthElevation(); + } + else { + return false; + } +} + +bool SkyBrowserModule::isSelectedPairFacingCamera() +{ + if (getPair(_selectedBrowser)) { + return getPair(_selectedBrowser)->isFacingCamera(); + } + else { + return false; + } +} + //std::vector SkyBrowserModule::documentations() const { // return { // ExoplanetsDataPreparationTask::documentation(), diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 5d4c5f83be..6374b8e515 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -74,6 +74,7 @@ public: RenderableSkyBrowser* get3dBrowser(const std::string& id); const std::unique_ptr& getWwtDataHandler(); std::string selectedBrowserId(); + std::string selectedTargetId(); // Setters void set3dBrowser(const std::string& id); @@ -92,6 +93,8 @@ public: // Boolean functions bool isCameraInSolarSystem(); + bool isSelectedPairFacingCamera(); + bool isSelectedPairUsingRae(); // Managing the target browser pairs void removeTargetBrowserPair(const std::string& browserId); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 9973fd6ddb..83f7fb8827 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -332,6 +332,12 @@ int getTargetData(lua_State* L) { lua_settable(L, -3); ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); lua_settable(L, -3); + ghoul::lua::push(L, "selectedTargetId", module->selectedTargetId()); + lua_settable(L, -3); + ghoul::lua::push(L, "isFacingCamera", module->isSelectedPairFacingCamera()); + lua_settable(L, -3); + ghoul::lua::push(L, "isUsingRadiusAzimuthElevation", module->isSelectedPairUsingRae()); + lua_settable(L, -3); ghoul::lua::push(L, "cameraInSolarSystem", module->isCameraInSolarSystem()); lua_settable(L, -3); // Set table for the current ImageData diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp index 666f2ac65d..b50e5d830b 100644 --- a/modules/skybrowser/src/pair.cpp +++ b/modules/skybrowser/src/pair.cpp @@ -337,6 +337,16 @@ namespace openspace { return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); } + bool Pair::isFacingCamera() const + { + return _browser->isFacingCamera() || _target->isFacingCamera(); + } + + bool Pair::isUsingRadiusAzimuthElevation() const + { + return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); + } + ScreenSpaceSkyTarget* Pair::getTarget() { return _target; } diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 411d6aa630..dd7285006c 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -464,6 +464,10 @@ bool ScreenSpaceRenderable::isUsingRaeCoords() const { return _useRadiusAzimuthElevation; } +bool ScreenSpaceRenderable::isFacingCamera() const +{ + return _faceCamera; +} void ScreenSpaceRenderable::setEnabled(bool isEnabled) { _enabled = isEnabled; From 07c17be12c41f5e79de5140da802b0cf45866a21 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 10 Feb 2022 07:01:18 -0500 Subject: [PATCH 191/251] Ensure all lua functions accepts the browser id as the first argument (except when there is a target id as well) --- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 83f7fb8827..a05b91b8cc 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -608,9 +608,9 @@ int place3dSkyBrowser(lua_State* L) { int removeSelectedImageInBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); + const std::string id = ghoul::lua::value(L, 1); // Image index const int i = ghoul::lua::value(L, 1); - const std::string id = ghoul::lua::value(L, 1); // Get browser SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& image = module->getWwtDataHandler()->getImage(i); From a88246c56b6ec64d35e9c1c61f7468d68c83c387 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 10 Feb 2022 07:11:39 -0500 Subject: [PATCH 192/251] Rename "Pair" to "TargetBrowserPair" --- modules/skybrowser/CMakeLists.txt | 4 +- modules/skybrowser/include/pair.h | 141 ------- modules/skybrowser/skybrowsermodule.cpp | 28 +- modules/skybrowser/skybrowsermodule.h | 10 +- modules/skybrowser/skybrowsermodule_lua.inl | 24 +- modules/skybrowser/src/pair.cpp | 388 -------------------- 6 files changed, 33 insertions(+), 562 deletions(-) delete mode 100644 modules/skybrowser/include/pair.h delete mode 100644 modules/skybrowser/src/pair.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 10d8708415..972e28bbfd 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -30,7 +30,7 @@ set(HEADER_FILES include/screenspaceskytarget.h include/wwtdatahandler.h include/utility.h - include/pair.h + include/targetbrowserpair.h include/wwtcommunicator.h include/browser.h include/screenspaceskybrowser.h @@ -48,7 +48,7 @@ set(SOURCE_FILES src/wwtdatahandler.cpp src/utility.cpp src/renderableskybrowser.cpp - src/pair.cpp + src/targetbrowserpair.cpp src/wwtcommunicator.cpp src/browser.cpp src/screenspaceskybrowser.cpp diff --git a/modules/skybrowser/include/pair.h b/modules/skybrowser/include/pair.h deleted file mode 100644 index ed6028bedd..0000000000 --- a/modules/skybrowser/include/pair.h +++ /dev/null @@ -1,141 +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_SKYBROWSER___PAIR___H__ -#define __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ - -#include -#include - -namespace openspace { - -class ScreenSpaceSkyBrowser; -class ScreenSpaceSkyTarget; -class ScreenSpaceRenderable; -class ImageData; - -class Pair { -public: - - constexpr static const float FadeThreshold = 0.01f; - constexpr static const double AnimationThreshold = 0.0001f; - - Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); - Pair(Pair const&) = default; - // user-defined copy assignment (copy-and-swap idiom) - Pair& operator=(Pair other); - - // Target & Browser - void initialize(); - // Highlighting - void removeHighlight(glm::ivec3 color); - void highlight(glm::ivec3 color); - // Animation - void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); - void incrementallyAnimateToCoordinate(double deltaTime); - void incrementallyFade(float goalState, float fadeTime, float deltaTime); - // Mouse interaction - bool checkMouseIntersection(glm::vec2 mousePosition); - glm::vec2 selectedScreenSpacePosition(); - bool isBrowserSelected(); - bool isTargetSelected(); - void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); - void translateSelected(const glm::vec2& start, const glm::vec2& translation); - void synchronizeAim(); - - // Browser - void sendIdToBrowser(); - void updateBrowserSize(); - - // Target - void centerTargetOnScreen(); - void lock(); - void unlock(); - - // Boolean functions - bool hasFinishedFading(float goalState) const; - bool isFacingCamera() const; - bool isUsingRadiusAzimuthElevation() const; - bool isEnabled() const; - bool isLocked() const; - - // Setters - void setEnabled(bool enable); - void setIsSyncedWithWwt(bool isSynced); - void setVerticalFov(float vfov); - void setEquatorialAim(const glm::dvec2& aim); - void setBorderColor(const glm::ivec3& color); - void setScreenSpaceSize(const glm::vec2& dimensions); - void setVerticalFovWithScroll(float scroll); - - // Getters by value - float verticalFov() const; - glm::ivec3 borderColor() const; - glm::dvec2 targetDirectionEquatorial() const; - glm::dvec3 targetDirectionGalactic() const; - std::string browserGuiName() const; - std::string browserId() const; - std::string targetId() const; - glm::vec2 size() const; - - - // Getters by reference - ScreenSpaceSkyTarget* getTarget(); - ScreenSpaceSkyBrowser* getBrowser(); - const std::deque& getSelectedImages() const; - - // WorldWide Telescope image handling - void setImageOrder(int i, int order); - void selectImage(const ImageData& image, int i); - void removeSelectedImage(int i); - void loadImageCollection(const std::string& collection); - void setImageOpacity(int i, float opacity); - void hideChromeInterface(bool shouldHide); - - // Comparision operators - friend bool operator==(const Pair& lhs, - const Pair& rhs); - friend bool operator!=(const Pair& lhs, - const Pair& rhs); - -private: - ScreenSpaceRenderable* _selected; - bool _isSelectedBrowser; - - bool isTargetFadeFinished(float goalState) const; - bool isBrowserFadeFinished(float goalState) const; - - ScreenSpaceSkyTarget* _target{ nullptr }; - ScreenSpaceSkyBrowser* _browser{ nullptr }; - - // Shared properties between the target and the browser - float _verticalFov{ 70.0f }; - glm::dvec2 _equatorialAim{ 0.0 }; - glm::ivec3 _borderColor{ 255 }; - glm::vec2 _dimensions{ 0.5f, 0.5f }; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_SKYBROWSER___PAIR___H__ diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 1aae807a4b..2171158229 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -394,7 +394,7 @@ SkyBrowserModule::SkyBrowserModule() } if (_isCameraInSolarSystem) { std::for_each(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - [&](const std::unique_ptr& pair) { + [&](const std::unique_ptr& pair) { pair->synchronizeAim(); }); incrementallyAnimateTargets(deltaTime); @@ -440,11 +440,11 @@ void SkyBrowserModule::setSelectedObject() return; } // Save old selection for removing highlight - Pair* previousPair = _mouseOnPair; + TargetBrowserPair* previousPair = _mouseOnPair; // Find and save what mouse is currently hovering on auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - [&] (const std::unique_ptr &pair) { + [&] (const std::unique_ptr &pair) { return pair->checkMouseIntersection(_mousePosition); }); @@ -480,19 +480,19 @@ void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const s // Assert pair to have both target and browser if (browser && target) { - _targetsBrowsers.push_back(std::make_unique(browser, target)); + _targetsBrowsers.push_back(std::make_unique(browser, target)); } } void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) { - Pair* found = getPair(id); + TargetBrowserPair* found = getPair(id); if (!found) { return; } auto it = std::remove_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - [&](const std::unique_ptr& pair) { + [&](const std::unique_ptr& pair) { return *found == *(pair.get()); }); @@ -512,7 +512,7 @@ void SkyBrowserModule::set3dBrowser(const std::string& id) void SkyBrowserModule::lookAtTarget(std::string id) { - Pair* pair = getPair(id); + TargetBrowserPair* pair = getPair(id); if (pair) { startRotatingCamera(pair->targetDirectionGalactic()); } @@ -567,7 +567,7 @@ int SkyBrowserModule::nLoadedImages() void SkyBrowserModule::add2dSelectedImagesTo3d(const std::string& pairId) { - Pair* pair = getPair(pairId); + TargetBrowserPair* pair = getPair(pairId); if (pair && get3dBrowser()) { @@ -612,7 +612,7 @@ const std::unique_ptr& SkyBrowserModule::getWwtDataHandler() { return _dataHandler; } -std::vector>& SkyBrowserModule::getPairs() +std::vector>& SkyBrowserModule::getPairs() { return _targetsBrowsers; } @@ -622,10 +622,10 @@ int SkyBrowserModule::nPairs() return static_cast(_targetsBrowsers.size()); } -Pair* SkyBrowserModule::getPair(const std::string& id) +TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) { auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), - [&](const std::unique_ptr& pair) { + [&](const std::unique_ptr& pair) { bool foundBrowser = pair->browserId() == id; bool foundTarget = pair->targetId() == id; return foundBrowser || foundTarget; @@ -739,7 +739,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float }(goal); bool isAllFinished{ false }; - for (std::unique_ptr& pair : _targetsBrowsers) { + for (std::unique_ptr& pair : _targetsBrowsers) { if (pair->isEnabled()) { bool isPairFinished = pair->hasFinishedFading(transparency); if (!isPairFinished) { @@ -760,7 +760,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) { - for (std::unique_ptr& pair : _targetsBrowsers) { + for (std::unique_ptr& pair : _targetsBrowsers) { if (pair->isEnabled()) { pair->incrementallyAnimateToCoordinate(deltaTime); } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 6374b8e515..7cba102ca4 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -37,7 +37,7 @@ namespace openspace { class RenderableSkyBrowser; class ScreenSpaceImageLocal; class WwtDataHandler; -class Pair; +class TargetBrowserPair; class SceneGraphNode; class ImageData; @@ -66,9 +66,9 @@ public: virtual ~SkyBrowserModule(); // Getters - std::vector>& getPairs(); + std::vector>& getPairs(); int nPairs(); - Pair* getPair(const std::string& id); + TargetBrowserPair* getPair(const std::string& id); SceneGraphNode* get3dBrowserNode(); RenderableSkyBrowser* get3dBrowser(); RenderableSkyBrowser* get3dBrowser(const std::string& id); @@ -126,8 +126,8 @@ private: glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers // The browsers and targets - std::vector> _targetsBrowsers; - Pair* _mouseOnPair{ nullptr }; + std::vector> _targetsBrowsers; + TargetBrowserPair* _mouseOnPair{ nullptr }; ScreenSpaceImageLocal* _hoverCircle{ nullptr }; SceneGraphNode* _browser3dNode{ nullptr }; // Scene graph node is used for positioning RenderableSkyBrowser* _browser3d{ nullptr }; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index a05b91b8cc..01908a5a5e 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -22,7 +22,7 @@ int selectImage(lua_State* L) { SkyBrowserModule* module = global::moduleEngine->module(); if (module->isCameraInSolarSystem()) { - Pair* selected = module->getPair(module->selectedBrowserId()); + TargetBrowserPair* selected = module->getPair(module->selectedBrowserId()); if (selected) { const ImageData& image = module->getWwtDataHandler()->getImage(i); @@ -168,8 +168,8 @@ int sendOutIdsToBrowsers(lua_State* L) { // Send out ID's to the browsers SkyBrowserModule* module = global::moduleEngine->module(); - std::vector>& pairs = module->getPairs(); - for (std::unique_ptr& pair : pairs) { + std::vector>& pairs = module->getPairs(); + for (std::unique_ptr& pair : pairs) { pair->sendIdToBrowser(); } if(module->get3dBrowser()) { @@ -345,9 +345,9 @@ int getTargetData(lua_State* L) { // Pass data for all the browsers and the corresponding targets if (module->isCameraInSolarSystem()) { - std::vector>& pairs = module->getPairs(); + std::vector>& pairs = module->getPairs(); - for (std::unique_ptr& pair : pairs) { + for (std::unique_ptr& pair : pairs) { std::string id = pair->browserId(); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; @@ -494,7 +494,7 @@ int centerTargetOnScreen(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); + TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->centerTargetOnScreen(); } @@ -570,7 +570,7 @@ int removeTargetBrowserPair(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeTargetBrowserPair"); std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - Pair* found = module->getPair(id); + TargetBrowserPair* found = module->getPair(id); if (found) { std::string browser = found->browserId(); std::string target = found->targetId(); @@ -615,7 +615,7 @@ int removeSelectedImageInBrowser(lua_State* L) { SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& image = module->getWwtDataHandler()->getImage(i); - Pair* pair = module->getPair(id); + TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->removeSelectedImage(i); } @@ -635,7 +635,7 @@ int setEquatorialAim(lua_State* L) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); + TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->setEquatorialAim(glm::dvec2(ra, dec)); } @@ -655,7 +655,7 @@ int setVerticalFov(lua_State* L) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); + TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->setVerticalFov(vfov); } @@ -677,7 +677,7 @@ int setBorderColor(lua_State* L) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); + TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->setBorderColor(color); } @@ -698,7 +698,7 @@ int setScreenSpaceSize(lua_State* L) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); - Pair* pair = module->getPair(id); + TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->setScreenSpaceSize(glm::vec2(sizeX, sizeY)); } diff --git a/modules/skybrowser/src/pair.cpp b/modules/skybrowser/src/pair.cpp deleted file mode 100644 index b50e5d830b..0000000000 --- a/modules/skybrowser/src/pair.cpp +++ /dev/null @@ -1,388 +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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma optimize("", off) - -namespace openspace { - - Pair::Pair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) - : _target(target), _browser(browser) - { - ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); - ghoul_assert(target != nullptr, "Sky target is null pointer!"); - } - - Pair& Pair::operator=(Pair other) - { - std::swap(_target, other._target); - std::swap(_browser, other._browser); - return *this; - - } - - void Pair::lock() { - _target->setLock(true); - } - - void Pair::unlock() { - _target->setLock(false); - } - - void Pair::setImageOrder(int i, int order) { - _browser->setImageOrder(i, order); - } - - void Pair::removeHighlight(glm::ivec3 color) - { - _target->removeHighlight(color); - _browser->removeHighlight(color); - } - - void Pair::highlight(glm::ivec3 color) - { - _browser->highlight(color); - _target->highlight(color); - } - - bool Pair::isTargetFadeFinished(float goalState) const - { - // Is fading finished? - float targetDiff = abs(_target->opacity() - goalState); - - return targetDiff < FadeThreshold; - } - - bool Pair::isBrowserFadeFinished(float goalState) const - { - float browserDiff = abs(_browser->opacity() - goalState); - return browserDiff < FadeThreshold; - } - - bool Pair::checkMouseIntersection(glm::vec2 mousePosition) - { - bool onBrowser = _browser->intersection(mousePosition); - bool onTarget = _target->intersection(mousePosition); - if (onBrowser) { - _selected = _browser; - _isSelectedBrowser = true; - } - else if (onTarget) { - _selected = _target; - _isSelectedBrowser = false; - } - else { - _selected = nullptr; - _isSelectedBrowser = false; - } - return onBrowser || onTarget; - } - - glm::vec2 Pair::selectedScreenSpacePosition() - { - return _selected->screenSpacePosition(); - } - - bool Pair::isBrowserSelected() - { - return _isSelectedBrowser; - } - - bool Pair::isTargetSelected() - { - return _selected && !_isSelectedBrowser; - } - - void Pair::fineTuneTarget(const glm::vec2& start, const glm::vec2& translation) - { - glm::vec2 fineTune = _browser->fineTuneVector(translation); - _target->translate(fineTune, start); - } - - void Pair::translateSelected(const glm::vec2& start, const glm::vec2& translation) - { - _selected->translate(translation, start); - } - - void Pair::synchronizeAim() - { - if (!_target->isAnimated()) { - glm::dvec2 aim; - // To remove the lag effect when moving the camera while having a locked - // target, send the locked coordinates to wwt - if (_target->isLocked()) { - aim = _target->lockedCoordinates(); - } - else { - aim = _target->equatorialAim(); - } - - _browser->setEquatorialAim(aim); - _target->setScaleFromVfov(_browser->verticalFov()); - } - } - - void Pair::setEnabled(bool enable) - { - _browser->setEnabled(enable); - _target->setEnabled(enable); - } - - bool Pair::isEnabled() const - { - return _target->isEnabled() && _browser->isEnabled(); - } - - bool Pair::isLocked() const - { - return _target->isLocked(); - } - - void Pair::initialize() - { - _target->setColor(_browser->borderColor()); - _target->setDimensions(_browser->browserPixelDimensions()); - _target->setScaleFromVfov(_browser->verticalFov()); - _browser->updateBorderColor(); - } - - glm::ivec3 Pair::borderColor() const - { - return _browser->borderColor(); - } - - glm::dvec2 Pair::targetDirectionEquatorial() const - { - return _target->equatorialAim(); - } - - glm::dvec3 Pair::targetDirectionGalactic() const - { - return _target->directionGalactic(); - } - - std::string Pair::browserGuiName() const - { - return _browser->guiName(); - } - - std::string Pair::browserId() const - { - return _browser->identifier(); - } - - std::string Pair::targetId() const - { - return _target->identifier(); - } - - glm::vec2 Pair::size() const - { - return _browser->size(); - } - - float Pair::verticalFov() const - { - return _browser->verticalFov(); - } - - const std::deque& Pair::getSelectedImages() const - { - return _browser->getSelectedImages(); - } - - void Pair::selectImage(const ImageData& image, int i) - { - // Load image into browser - _browser->displayImage(image.imageUrl, i); - - // If the image has coordinates, move the target - if (image.hasCelestialCoords) { - - // Animate the target to the image coordinate position - unlock(); - startAnimation(image.equatorialCartesian, image.fov, true); - } - } - - void Pair::removeSelectedImage(int i) - { - _browser->removeSelectedImage(i); - } - - void Pair::loadImageCollection(const std::string& collection) - { - _browser->loadImageCollection(collection); - } - - void Pair::setImageOpacity(int i, float opacity) - { - _browser->setImageOpacity(i, opacity); - } - - void Pair::hideChromeInterface(bool shouldHide) - { - _browser->hideChromeInterface(shouldHide); - } - - void Pair::sendIdToBrowser() - { - _browser->setIdInBrowser(); - } - - void Pair::updateBrowserSize() { - _browser->updateBrowserSize(); - } - - void Pair::setIsSyncedWithWwt(bool isSynced) - { - _browser->setIsSyncedWithWwt(isSynced); - } - - void Pair::setVerticalFov(float vfov) - { - _verticalFov = vfov; - _browser->setVerticalFov(vfov); - _target->setScaleFromVfov(vfov); - } - - void Pair::setEquatorialAim(const glm::dvec2& aim) - { - _equatorialAim = aim; - _target->setEquatorialAim(aim); - _browser->setEquatorialAim(aim); - } - - void Pair::setBorderColor(const glm::ivec3& color) - { - _borderColor = color; - _target->setColor(color); - _browser->setBorderColor(color); - } - - void Pair::setScreenSpaceSize(const glm::vec2& dimensions) - { - _dimensions = dimensions; - _target->setDimensions(dimensions); - _browser->setScreenSpaceSize(dimensions); - } - - void Pair::setVerticalFovWithScroll(float scroll) - { - _browser->setVerticalFovWithScroll(scroll); - } - - void Pair::incrementallyAnimateToCoordinate(double deltaTime) - { - // Animate the target before the field of view starts to animate - if (_target->isAnimated()) { - _target->incrementallyAnimateToCoordinate(deltaTime); - } - else if (_browser->isAnimated()) { - _browser->incrementallyAnimateToFov(deltaTime); - } - } - - void Pair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, - bool shouldLockAfter) - { - _target->startAnimation(equatorialCoords, shouldLockAfter); - _browser->startFovAnimation(fovEnd); - } - - void Pair::centerTargetOnScreen() - { - // Animate the target to the center of the screen - unlock(); - // Get camera direction in celestial spherical coordinates - glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); - // Keep the current fov - float currentFov = verticalFov(); - startAnimation(viewDirection, currentFov, false); - } - - bool Pair::hasFinishedFading(float goalState) const - { - return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); - } - - bool Pair::isFacingCamera() const - { - return _browser->isFacingCamera() || _target->isFacingCamera(); - } - - bool Pair::isUsingRadiusAzimuthElevation() const - { - return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); - } - - ScreenSpaceSkyTarget* Pair::getTarget() { - return _target; - } - - ScreenSpaceSkyBrowser* Pair::getBrowser() { - return _browser; - } - - void Pair::incrementallyFade(float goalState, float fadeTime, float deltaTime) - { - float opacityDelta = static_cast(deltaTime / fadeTime); - if (_target->opacity() > goalState) { - opacityDelta *= -1.f; - } - - if (!isTargetFadeFinished(goalState)) { - _target->setOpacity(_target->opacity() + opacityDelta); - } - else { - _target->setOpacity(goalState); - } - - if (!isBrowserFadeFinished(goalState)) { - _browser->setOpacity(_browser->opacity() + opacityDelta); - } - else { - _browser->setOpacity(goalState); - } - } - - bool operator==(const Pair& lhs, const Pair& rhs) { - return lhs._target == rhs._target && lhs._browser == rhs._browser; - } - bool operator!=(const Pair& lhs, const Pair& rhs) { - return !(lhs == rhs); - } - - -} // namespace openspace From ffee7e6f5c8ec021a905e75c396102c793803824 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 10 Feb 2022 07:22:59 -0500 Subject: [PATCH 193/251] Don't highlight browser when using rae coords since dragging is not working in that mode currently --- modules/skybrowser/skybrowsermodule.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 2171158229..3d697b0d8f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -445,7 +445,8 @@ void SkyBrowserModule::setSelectedObject() // Find and save what mouse is currently hovering on auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), [&] (const std::unique_ptr &pair) { - return pair->checkMouseIntersection(_mousePosition); + return pair->checkMouseIntersection(_mousePosition) && + !pair->isUsingRadiusAzimuthElevation(); }); if (it == std::end(_targetsBrowsers)) { From 5a07842b9e3058c379833dc817e793ea6e8376f8 Mon Sep 17 00:00:00 2001 From: sylvass Date: Thu, 17 Feb 2022 08:55:03 -0500 Subject: [PATCH 194/251] Add lua function to translate screen space renderable. Add documentation for the lua functions. --- modules/skybrowser/skybrowsermodule.cpp | 175 ++++++++++---------- modules/skybrowser/skybrowsermodule_lua.inl | 16 +- 2 files changed, 105 insertions(+), 86 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 3d697b0d8f..e0901198af 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -81,199 +81,204 @@ namespace openspace { { "getListOfImages", &skybrowser::luascriptfunctions::getListOfImages, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "", + "Returns a list of all the loaded AAS WorldWide Telescope images that " + "has been loaded." }, { "setHoverCircle", &skybrowser::luascriptfunctions::setHoverCircle, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a screen space renderable and adds it to the " + "module." }, { "moveCircleToHoverImage", &skybrowser::luascriptfunctions::moveCircleToHoverImage, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "int", + "Moves the hover circle to the coordinate specified by the image index." }, { "disableHoverCircle", &skybrowser::luascriptfunctions::disableHoverCircle, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "", + "Disables the hover circle, if there is one added to the sky browser " + "module. " }, { "loadImagesToWWT", &skybrowser::luascriptfunctions::loadImagesToWWT, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser or target and loads the WWT image " + "collection to that browser." }, { "selectImage", &skybrowser::luascriptfunctions::selectImage, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "int", + "Takes an index to an image and selects that image in the currently " + "selected sky browser." }, { "removeSelectedImageInBrowser", &skybrowser::luascriptfunctions::removeSelectedImageInBrowser, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, int", + "Takes an identifier to a sky browser or target and an index to an " + "image. Removes that image from that sky browser." }, { "adjustCamera", & skybrowser::luascriptfunctions::adjustCamera, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser or sky target. Rotates the camera " + "so that the target is placed in the center of the view." }, { "setSelectedBrowser", & skybrowser::luascriptfunctions::setSelectedBrowser, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser or target. Sets that sky browser " + "currently selected." }, { "getTargetData", &skybrowser::luascriptfunctions::getTargetData, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "", + "Returns a table of data regarding the current view and the sky browsers " + "and targets." }, { "lockTarget", &skybrowser::luascriptfunctions::lockTarget, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser or target. Locks the target " + "to its current position." }, { "unlockTarget", &skybrowser::luascriptfunctions::unlockTarget, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser or target. Unlocks the target." }, { "createTargetBrowserPair", &skybrowser::luascriptfunctions::createTargetBrowserPair, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "", + "Creates a sky browser and a target." }, { "removeTargetBrowserPair", &skybrowser::luascriptfunctions::removeTargetBrowserPair, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes in identifier to a sky browser or target and removes them." }, { "place3dSkyBrowser", &skybrowser::luascriptfunctions::place3dSkyBrowser, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "int", + "Takes an index to an image and places the 3D sky browser in that place. " }, { "setOpacityOfImageLayer", &skybrowser::luascriptfunctions::setOpacityOfImageLayer, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, int, double", + "Takes an identifier to a sky browser or sky target, an index to an image" + "and a value for the opacity." }, { "sendOutIdsToBrowsers", &skybrowser::luascriptfunctions::sendOutIdsToBrowsers, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "", + "Sends all sky browsers' identifiers to their respective CEF browser. " }, { "initializeBrowser", &skybrowser::luascriptfunctions::initializeBrowser, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser and starts the initialization " + "for that browser. That means that the browser starts to try to connect " + "to the AAS WorldWide Telescope application by sending it messages. And " + "that the target matches its appearance to its corresponding browser." }, { "add3dBrowserToSkyBrowserModule", &skybrowser::luascriptfunctions::add3dBrowserToSkyBrowserModule, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes the identifier to the 3D sky browser and adds it to the sky " + "browser module." }, { "set3dSelectedImagesAs2dSelection", &skybrowser::luascriptfunctions::set3dSelectedImagesAs2dSelection, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser and adds the selected images in " + "that browser to the 3D sky browser." }, { "centerTargetOnScreen", &skybrowser::luascriptfunctions::centerTargetOnScreen, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string", + "Takes an identifier to a sky browser and animates its corresponding " + "target to the center of the current view." }, { "setImageLayerOrder", &skybrowser::luascriptfunctions::setImageLayerOrder, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, int, int", + "Takes an identifier to a sky browser or a sky target, an image index " + "and the order which it should have in the selected image list. The " + "image is then changed to have this order." }, { "addPairToSkyBrowserModule", &skybrowser::luascriptfunctions::addPairToSkyBrowserModule, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, string", + "Takes the identifier of the sky target and a sky browser and adds them " + "to the sky browser module." }, { "setEquatorialAim", &skybrowser::luascriptfunctions::setEquatorialAim, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, double, double", + "Takes the identifier of a sky browser or a sky target and equatorial " + "coordinates Right Ascension and Declination. The target will animate to " + "this coordinate and the browser will display the coordinate." }, { "setVerticalFov", &skybrowser::luascriptfunctions::setVerticalFov, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, float", + "Takes an identifier to a sky browser or a sky target and a vertical " + "field of view. Changes the field of view as specified by the input." }, { "setBorderColor", &skybrowser::luascriptfunctions::setBorderColor, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, int, int, int", + "Takes an identifier to a sky browser or a sky target and a rgb color " + "in the ranges [0, 255]." }, { "setScreenSpaceSize", &skybrowser::luascriptfunctions::setScreenSpaceSize, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "string, float, float", + "Sets the screen space size of the sky browser to the numbers specified " + "by the input [x, y]." }, { "startSetup", &skybrowser::luascriptfunctions::startSetup, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" + "", + "Starts the setup process of the sky browers. This function calls " + "the lua function 'sendOutIdsToBrowsers' in all nodes in the cluster." }, + { + "translateScreenSpaceRenderable", + &skybrowser::luascriptfunctions::translateScreenSpaceRenderable, + "string, float, float, float, float", + "Takes an identifier to a sky browser or sky target and the [x, y] " + "starting position and the [x, y] translation vector." + }, }; return res; @@ -479,7 +484,7 @@ void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const s global::renderEngine->screenSpaceRenderable(browserId) ); - // Assert pair to have both target and browser + // Ensure pair has both target and browser if (browser && target) { _targetsBrowsers.push_back(std::make_unique(browser, target)); } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 01908a5a5e..be6c38b802 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -594,6 +594,20 @@ int removeTargetBrowserPair(lua_State* L) { return 0; } +int translateScreenSpaceRenderable(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 5, "lua::translateScreenSpaceRenderable"); + const std::string id = ghoul::lua::value(L, 1); + float startX = ghoul::lua::value(L, 1); + float startY = ghoul::lua::value(L, 1); + float transX = ghoul::lua::value(L, 1); + float transY = ghoul::lua::value(L, 1); + + ScreenSpaceRenderable* renderable = global::renderEngine->screenSpaceRenderable(id); + renderable->translate(glm::vec2(transX, transY), glm::vec2(startX, startY)); + + return 0; +} + int place3dSkyBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::place3dSkyBrowser"); // Image index to place in 3D @@ -689,7 +703,7 @@ int setBorderColor(lua_State* L) { } int setScreenSpaceSize(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setBorderColor"); + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setScreenSpaceSize"); // Browser id const std::string id = ghoul::lua::value(L, 1); float sizeX = ghoul::lua::value(L, 1); From 863b5557476dc635e78e8b7caa8e1f022a5b9c4f Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 18 Feb 2022 11:28:09 -0500 Subject: [PATCH 195/251] Ensure all nodes in a cluset get the same border color for the browsers --- modules/skybrowser/skybrowsermodule.cpp | 93 +++++++++++-------- modules/skybrowser/skybrowsermodule.h | 1 + modules/skybrowser/skybrowsermodule_lua.inl | 21 ++++- .../skybrowser/src/screenspaceskybrowser.cpp | 21 ++++- 4 files changed, 89 insertions(+), 47 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index e0901198af..afea32d6af 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -322,52 +322,54 @@ SkyBrowserModule::SkyBrowserModule() } ); - global::callback::mousePosition->emplace_back( - [&](double x, double y) { - - if (!_isCameraInSolarSystem || !_allowMouseInteraction) { + if (global::windowDelegate->isMaster()) { + global::callback::mousePosition->emplace_back( + [&](double x, double y) { + + if (!_isCameraInSolarSystem || !_allowMouseInteraction) { + return false; + } + + glm::vec2 pixel{ static_cast(x), static_cast(y) }; + _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); + glm::vec2 translation = _mousePosition - _startMousePosition; + + switch (_interactionMode) { + case MouseInteraction::Hover: + setSelectedObject(); + + break; + + case MouseInteraction::Drag: + _mouseOnPair->translateSelected(_startDragPosition, translation); + break; + + case MouseInteraction::FineTune: + _mouseOnPair->fineTuneTarget(_startDragPosition, translation); + break; + + default: + setSelectedObject(); + break; + } return false; } + ); - glm::vec2 pixel{ static_cast(x), static_cast(y) }; - _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); - glm::vec2 translation = _mousePosition - _startMousePosition; + global::callback::mouseScrollWheel->emplace_back( + [&](double, double scroll) -> bool { - switch (_interactionMode) { - case MouseInteraction::Hover: - setSelectedObject(); - break; - - case MouseInteraction::Drag: - _mouseOnPair->translateSelected(_startDragPosition, translation); - break; - - case MouseInteraction::FineTune: - _mouseOnPair->fineTuneTarget(_startDragPosition, translation); - break; - - default: - setSelectedObject(); - break; + if (!_isCameraInSolarSystem || !_mouseOnPair || !_allowMouseInteraction) { + return false; + } + // If mouse is on browser or target, apply zoom + _mouseOnPair->setVerticalFovWithScroll( + static_cast(scroll) + ); + return true; } - return false; - } - ); - - global::callback::mouseScrollWheel->emplace_back( - [&](double, double scroll) -> bool { - - if (!_isCameraInSolarSystem || !_mouseOnPair || !_allowMouseInteraction) { - return false; - } - // If mouse is on browser or target, apply zoom - _mouseOnPair->setVerticalFovWithScroll( - static_cast(scroll) - ); - return true; - } - ); - + ); + } global::callback::preSync->emplace_back([this]() { @@ -650,6 +652,10 @@ SceneGraphNode* SkyBrowserModule::get3dBrowserNode() { RenderableSkyBrowser* SkyBrowserModule::get3dBrowser(const std::string& id) { + if (!_browser3dNode || !_browser3d) { + return nullptr; + } + if (_browser3dNode->identifier() == id || _browser3d->identifier() == id) { return _browser3d; } @@ -793,6 +799,11 @@ std::string SkyBrowserModule::selectedTargetId() } } +glm::ivec3 SkyBrowserModule::highlight() +{ + return _highlightAddition; +} + bool SkyBrowserModule::isCameraInSolarSystem() { return _isCameraInSolarSystem; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 7cba102ca4..405138eebf 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -75,6 +75,7 @@ public: const std::unique_ptr& getWwtDataHandler(); std::string selectedBrowserId(); std::string selectedTargetId(); + glm::ivec3 highlight(); // Setters void set3dBrowser(const std::string& id); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index be6c38b802..a34e237038 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -4,8 +4,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -152,6 +153,24 @@ int startSetup(lua_State* L) { // This is called when the sky_browser website is connected to OpenSpace ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::startSetup"); + // Set all border colors to the border color in the master node + if (global::windowDelegate->isMaster()) { + SkyBrowserModule* module = global::moduleEngine->module(); + std::vector>& pairs = module->getPairs(); + for (std::unique_ptr& pair : pairs) { + std::string id = pair->browserId(); + glm::ivec3 color = pair->borderColor(); + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.setBorderColor('" + id + "'," + + std::to_string(color.r) + "," + + std::to_string(color.g) + "," + + std::to_string(color.b) + "" + + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + } + // To ensure each node in a cluster calls its own instance of the wwt application // Do not send this script to the other nodes openspace::global::scriptEngine->queueScript( diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 8a41ddc13c..5b7d52a441 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -45,16 +45,23 @@ namespace { #include "ScreenSpaceSkyBrowser_codegen.cpp" } // namespace -glm::ivec3 randomBorderColor() { +glm::ivec3 randomBorderColor(glm::ivec3 highlight) { // Generate a random border color with sufficient lightness and a n std::random_device rd; // Hue is in the unit degrees [0, 360] std::uniform_real_distribution hue(0.f, 360.f); + // Value in saturation are in the unit percent [0,1] - float value = 0.95f; // Brightness + float value = 0.9f; // Brightness float saturation = 0.5f; - glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); - glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); + glm::ivec3 rgbColor; + glm::ivec3 highlighted; + do { + glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value); + rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f); + highlighted = rgbColor + highlight; + } while (highlighted.x < 255 && highlighted.y < 255 && highlighted.z < 255); + return rgbColor; } @@ -95,7 +102,11 @@ namespace openspace { glm::vec2 screenPosition = _cartesianPosition.value(); _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); - _borderColor = randomBorderColor(); + if (global::windowDelegate->isMaster()) { + SkyBrowserModule* module = global::moduleEngine->module(); + _borderColor = randomBorderColor(module->highlight()); + + } } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { From 8b71bbd0da478e29499465bfd17403cd52ed6b81 Mon Sep 17 00:00:00 2001 From: sylvass Date: Fri, 18 Feb 2022 12:21:12 -0500 Subject: [PATCH 196/251] Remove renderable sky browser (3D browser and related functionality) --- modules/skybrowser/CMakeLists.txt | 2 - .../skybrowser/include/renderableskybrowser.h | 62 ------- modules/skybrowser/include/wwtdatahandler.h | 8 +- modules/skybrowser/skybrowsermodule.cpp | 127 +------------- modules/skybrowser/skybrowsermodule.h | 15 +- modules/skybrowser/skybrowsermodule_lua.inl | 148 +--------------- .../skybrowser/src/renderableskybrowser.cpp | 165 ------------------ modules/skybrowser/src/wwtdatahandler.cpp | 44 +---- 8 files changed, 17 insertions(+), 554 deletions(-) delete mode 100644 modules/skybrowser/include/renderableskybrowser.h delete mode 100644 modules/skybrowser/src/renderableskybrowser.cpp diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 972e28bbfd..d5f3196a2b 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -34,7 +34,6 @@ set(HEADER_FILES include/wwtcommunicator.h include/browser.h include/screenspaceskybrowser.h - include/renderableskybrowser.h ext/tinyxml2/tinyxml2.h ) @@ -47,7 +46,6 @@ set(SOURCE_FILES src/screenspaceskytarget.cpp src/wwtdatahandler.cpp src/utility.cpp - src/renderableskybrowser.cpp src/targetbrowserpair.cpp src/wwtcommunicator.cpp src/browser.cpp diff --git a/modules/skybrowser/include/renderableskybrowser.h b/modules/skybrowser/include/renderableskybrowser.h deleted file mode 100644 index 3732da88db..0000000000 --- a/modules/skybrowser/include/renderableskybrowser.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ -#define __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ - -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable : 4100) -#endif // _MSC_VER - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-parameter" -#endif // __clang__ - -#include - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif // __clang__ - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - -namespace ghoul::opengl { class Texture; } - -namespace openspace::documentation { struct Documentation; } - -namespace openspace { - - class RenderableSkyBrowser : public RenderablePlane, public WwtCommunicator - { - public: - static constexpr const char* KeyIdentifier = "Identifier"; - - RenderableSkyBrowser(const ghoul::Dictionary& dictionary); - ~RenderableSkyBrowser(); - - // Inherited from RenderablePlane - void initializeGL() override; - void deinitializeGL() override; - void update(const UpdateData& data) override; - void render(const RenderData& data, RendererTasks& rendererTask) override; - - // Set up initialization with wwt - void setIdInBrowser(); - - // Place - void placeAt3dPosition(const glm::dvec3& positionSpeck, float verticalFov, - const std::string& sceneGraphNodeId); - - private: - void bindTexture() override; - void unbindTexture() override; - }; -} - -#endif // __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYBROWSER___H__ - diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 974ded0923..fb11d48dd4 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -36,11 +36,9 @@ namespace openspace { std::string creditsUrl{ wwt::Undefined }; std::string collection{ wwt::Undefined }; bool hasCelestialCoords{ false }; - bool has3dCoords{ false }; float fov{ 0.f }; glm::dvec2 equatorialSpherical{ 0.0 }; glm::dvec3 equatorialCartesian{ 0.0 }; - glm::dvec3 position3d{ 0.0 }; }; class WwtDataHandler { @@ -49,8 +47,7 @@ namespace openspace { WwtDataHandler() = default; ~WwtDataHandler(); - void loadImages(const std::string& root, const std::string& directory, - std::vector& speckFiles); + void loadImages(const std::string& root, const std::string& directory); int nLoadedImages() const; const ImageData& getImage(int i) const; @@ -61,10 +58,7 @@ namespace openspace { // Images std::vector _images; std::vector _xmls; - int _nMatched3dPositions = 0; - // 3D position data loaded from speck files - std::unordered_map _3dPositions; }; } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index afea32d6af..c4d2006b5c 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -25,7 +25,6 @@ #include -#include #include #include #include @@ -172,12 +171,6 @@ namespace openspace { "string", "Takes in identifier to a sky browser or target and removes them." }, - { - "place3dSkyBrowser", - &skybrowser::luascriptfunctions::place3dSkyBrowser, - "int", - "Takes an index to an image and places the 3D sky browser in that place. " - }, { "setOpacityOfImageLayer", &skybrowser::luascriptfunctions::setOpacityOfImageLayer, @@ -200,20 +193,6 @@ namespace openspace { "to the AAS WorldWide Telescope application by sending it messages. And " "that the target matches its appearance to its corresponding browser." }, - { - "add3dBrowserToSkyBrowserModule", - &skybrowser::luascriptfunctions::add3dBrowserToSkyBrowserModule, - "string", - "Takes the identifier to the 3D sky browser and adds it to the sky " - "browser module." - }, - { - "set3dSelectedImagesAs2dSelection", - &skybrowser::luascriptfunctions::set3dSelectedImagesAs2dSelection, - "string", - "Takes an identifier to a sky browser and adds the selected images in " - "that browser to the 3D sky browser." - }, { "centerTargetOnScreen", &skybrowser::luascriptfunctions::centerTargetOnScreen, @@ -385,10 +364,6 @@ SkyBrowserModule::SkyBrowserModule() // Camera moved into the solar system if (!_isCameraInSolarSystem) { _goal = Transparency::Transparent; - // Select the 3D browser when moving out of the solar system - if (_browser3dNode) { - _selectedBrowser = _browser3dNode->renderable()->identifier(); - } } else { _goal = Transparency::Opaque; @@ -422,20 +397,16 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); - // register ScreenSpaceBrowser + // Register ScreenSpaceRenderable auto fScreenSpaceRenderable = FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); - // register ScreenSpaceTarget + // Register ScreenSpaceSkyTarget fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); - // register ScreenSpaceTarget + // Register ScreenSpaceSkyBrowser fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); - // Register Renderable Skybrowser - auto fRenderable = FactoryManager::ref().factory(); - ghoul_assert(fRenderable, "Renderable factory was not created"); - fRenderable->registerClass("RenderableSkyBrowser"); // Create data handler dynamically to avoid the linking error that // came up when including the include file in the module header file _dataHandler = std::make_unique(); @@ -508,16 +479,6 @@ void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) { _mouseOnPair = nullptr; } -void SkyBrowserModule::set3dBrowser(const std::string& id) -{ - SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id); - if (node) { - // Add to module - _browser3dNode = node; - _browser3d = dynamic_cast(_browser3dNode->renderable()); - } -} - void SkyBrowserModule::lookAtTarget(std::string id) { TargetBrowserPair* pair = getPair(id); @@ -562,10 +523,9 @@ void SkyBrowserModule::disableHoverCircle() } } -void SkyBrowserModule::loadImages(const std::string& root, const std::string& directory, - std::vector& speckFiles) +void SkyBrowserModule::loadImages(const std::string& root, const std::string& directory) { - _dataHandler->loadImages(root, directory, speckFiles); + _dataHandler->loadImages(root, directory); } int SkyBrowserModule::nLoadedImages() @@ -573,21 +533,6 @@ int SkyBrowserModule::nLoadedImages() return _dataHandler->nLoadedImages(); } -void SkyBrowserModule::add2dSelectedImagesTo3d(const std::string& pairId) -{ - TargetBrowserPair* pair = getPair(pairId); - - if (pair && get3dBrowser()) { - - // Copy 2D selection of images to 3D browser - const std::deque images = pair->getSelectedImages(); - std::for_each(std::begin(images), std::end(images), [&](const int i) { - const ImageData& image = _dataHandler->getImage(i); - get3dBrowser()->displayImage(image.imageUrl, i); - }); - } -} - void SkyBrowserModule::handleMouseClick(const MouseButton& button) { setSelectedBrowser(_mouseOnPair->browserId()); @@ -646,66 +591,6 @@ TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) } } -SceneGraphNode* SkyBrowserModule::get3dBrowserNode() { - return _browser3dNode; -} - -RenderableSkyBrowser* SkyBrowserModule::get3dBrowser(const std::string& id) -{ - if (!_browser3dNode || !_browser3d) { - return nullptr; - } - - if (_browser3dNode->identifier() == id || _browser3d->identifier() == id) { - return _browser3d; - } - else { - return nullptr; - } - -} - -RenderableSkyBrowser* SkyBrowserModule::get3dBrowser() -{ - return _browser3d; -} - -void SkyBrowserModule::lookAt3dBrowser() { - if (!_browser3dNode) { - return; - } - std::string id = _browser3dNode->identifier(); - // Target camera on the 3D sky browser - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." - "RetargetAnchor\", nil)", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." - "Anchor\", '" + id + "')", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator." - "Aim\", '')", - scripting::ScriptEngine::RemoteScripting::Yes - ); -} - -void SkyBrowserModule::place3dBrowser(const ImageData& image, const int i) -{ - // If the image has a 3D position, add it to the scene graph - if (image.has3dCoords && _browser3d) { - _browser3d->displayImage(image.imageUrl, i); - _browser3d->placeAt3dPosition(image.position3d, image.fov, - _browser3dNode->identifier()); - } - else { - LINFO("Image has no 3D coordinate!"); - } -} - void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates _endAnimation = endAnimation; @@ -780,7 +665,7 @@ void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) } void SkyBrowserModule::setSelectedBrowser(const std::string& id) { - if (getPair(id) || (_browser3dNode && _browser3dNode->identifier() == id)) { + if (getPair(id)) { _selectedBrowser = id; } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 405138eebf..874a81d779 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -34,7 +34,6 @@ namespace openspace { -class RenderableSkyBrowser; class ScreenSpaceImageLocal; class WwtDataHandler; class TargetBrowserPair; @@ -69,16 +68,12 @@ public: std::vector>& getPairs(); int nPairs(); TargetBrowserPair* getPair(const std::string& id); - SceneGraphNode* get3dBrowserNode(); - RenderableSkyBrowser* get3dBrowser(); - RenderableSkyBrowser* get3dBrowser(const std::string& id); const std::unique_ptr& getWwtDataHandler(); std::string selectedBrowserId(); std::string selectedTargetId(); glm::ivec3 highlight(); // Setters - void set3dBrowser(const std::string& id); void setSelectedBrowser(const std::string& id); void setSelectedObject(); // Manage mouse interactions void setHoverCircle(ScreenSpaceImageLocal* circle); @@ -89,8 +84,6 @@ public: void incrementallyRotateCamera(double deltaTime); void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); void incrementallyAnimateTargets(double deltaTime); - void lookAt3dBrowser(); - void place3dBrowser(const ImageData& image, const int i); // Boolean functions bool isCameraInSolarSystem(); @@ -106,10 +99,8 @@ public: void disableHoverCircle(); // Image collection handling - void loadImages(const std::string& root, const std::string& directory, - std::vector& speckFiles); + void loadImages(const std::string& root, const std::string& directory); int nLoadedImages(); - void add2dSelectedImagesTo3d(const std::string& pairId); // Mouse interaction void handleMouseClick(const MouseButton& button); @@ -130,9 +121,7 @@ private: std::vector> _targetsBrowsers; TargetBrowserPair* _mouseOnPair{ nullptr }; ScreenSpaceImageLocal* _hoverCircle{ nullptr }; - SceneGraphNode* _browser3dNode{ nullptr }; // Scene graph node is used for positioning - RenderableSkyBrowser* _browser3d{ nullptr }; - std::string _selectedBrowser{ "" }; // Currently selected browser (2D or 3D) + std::string _selectedBrowser{ "" }; // Currently selected browser // Fading Transparency _goal; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index a34e237038..493536910a 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -40,12 +40,6 @@ int selectImage(lua_State* L) { } } } - else if (module->get3dBrowser()) { - const ImageData& image = module->getWwtDataHandler()->getImage(i); - module->get3dBrowser()->displayImage(image.imageUrl, i); - module->get3dBrowser()->setEquatorialAim(image.equatorialCartesian); - module->get3dBrowser()->setVerticalFov(image.fov); - } return 0; } @@ -110,10 +104,6 @@ int setImageLayerOrder(lua_State* L) { if (module->getPair(id)) { module->getPair(id)->setImageOrder(i, order); } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->setImageOrder(i, order); - } - return 0; } @@ -134,16 +124,6 @@ int loadImagesToWWT(lua_State* L) { if (module->getPair(id)) { //module->getPair(id)->hideChromeInterface(true); module->getPair(id)->loadImageCollection(root); - } - else if (module->get3dBrowser(id)) { - - // Load Image collections - module->get3dBrowser(id)->hideChromeInterface(true); - module->get3dBrowser(id)->setIsSyncedWithWwt(false); - LINFO("Load images to " + module->get3dBrowser(id)->identifier()); - module->get3dBrowser(id)->loadImageCollection(root); - LINFO("Image collection loaded in " + module->get3dBrowser(id)->identifier()); - } return 0; @@ -191,10 +171,7 @@ int sendOutIdsToBrowsers(lua_State* L) { for (std::unique_ptr& pair : pairs) { pair->sendIdToBrowser(); } - if(module->get3dBrowser()) { - - module->get3dBrowser()->setIdInBrowser(); - } + return 0; } @@ -209,26 +186,10 @@ int initializeBrowser(lua_State* L) { module->getPair(id)->setIsSyncedWithWwt(true); module->getPair(id)->initialize(); } - else if(module->get3dBrowser(id)) { - // Initialize - LINFO("Initializing 3D sky browsers"); - module->get3dBrowser()->setIsSyncedWithWwt(true); - } return 0; } -int add3dBrowserToSkyBrowserModule(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::add3dBrowserToSkyBrowserModule"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - - LINFO("Add to sky browser module id " + id); - module->set3dBrowser(id); - - return 0; -} - int addPairToSkyBrowserModule(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); const std::string targetId = ghoul::lua::value(L, 1); @@ -253,23 +214,10 @@ int getListOfImages(lua_State* L) { if (module->nLoadedImages() == 0) { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" "wwt-web-client/master/assets/webclient-explore-root.wtml"; - //std::string hubble = "http://www.worldwidetelescope.org/wwtweb/" - //"catalog.aspx?W=hubble"; + std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/").string(); - // 3D images - std::string http = "${SYNC}/http/"; - std::string globular = "digitaluniverse_globularclusters_speck/2/gc.speck"; - std::string open = "digitaluniverse_openclusters_speck/2/oc.speck"; - // Load speck files for 3D positions - std::filesystem::path globularClusters = absPath(http + globular); - std::filesystem::path openClusters = absPath(http + open); - std::vector specks = { - openClusters, - globularClusters - }; - - module->loadImages(root, directory, specks); + module->loadImages(root, directory); } // Create Lua table to send to the GUI @@ -278,11 +226,9 @@ int getListOfImages(lua_State* L) { for (int i = 0; i < module->nLoadedImages(); i++) { const ImageData& img = module->getWwtDataHandler()->getImage(i); glm::dvec3 coords = img.equatorialCartesian; - glm::dvec3 position = img.position3d; // Conversions for ghoul std::vector cartCoordsVec = { coords.x, coords.y, coords.z }; - std::vector position3d = { position.x, position.y, position.z }; // Index for current ImageData ghoul::lua::push(L, i + 1); @@ -306,10 +252,7 @@ int getListOfImages(lua_State* L) { lua_settable(L, -3); ghoul::lua::push(L, "identifier", std::to_string(i)); lua_settable(L, -3); - ghoul::lua::push(L, "has3dCoords", img.has3dCoords); - lua_settable(L, -3); - ghoul::lua::push(L, "position3d", position3d); - lua_settable(L, -3); + // Set table for the current ImageData lua_settable(L, -3); } @@ -421,49 +364,6 @@ int getTargetData(lua_State* L) { } } - else if(module->get3dBrowser()){ - // Convert deque to vector so ghoul can read it - std::vector selectedImagesVector; - std::deque selectedImages = module->get3dBrowser()->getSelectedImages(); - std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) { - selectedImagesVector.push_back(index); - }); - glm::dvec3 position3dBrowser = module->get3dBrowserNode()->position(); - glm::dvec3 cartesian = skybrowser::galacticToEquatorial(position3dBrowser); - glm::dvec2 spherical = skybrowser::cartesianToSpherical(cartesian); - std::vector celestialCartVec = { - cartesian.x, - cartesian.y, - cartesian.z - }; - // Convert color to vector so ghoul can read it - glm::ivec3 color = module->get3dBrowser()->borderColor(); - std::vector colorVec = { color.x, color.y, color.z }; - - ghoul::lua::push(L, module->get3dBrowser()->identifier()); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "id", module->get3dBrowser()->identifier()); - lua_settable(L, -3); - ghoul::lua::push(L, "name", module->get3dBrowserNode()->guiName()); - lua_settable(L, -3); - ghoul::lua::push(L, "FOV", module->get3dBrowser()->verticalFov()); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedImages", selectedImagesVector); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", celestialCartVec); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", spherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", spherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "color", colorVec); - lua_settable(L, -3); - - // Set table for the current target - lua_settable(L, -3); - } - return 1; } @@ -475,22 +375,10 @@ int adjustCamera(lua_State* L) { if(module->isCameraInSolarSystem()) { module->lookAtTarget(id); } - else { - module->lookAt3dBrowser(); - } return 0; } -int set3dSelectedImagesAs2dSelection(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::set3dSelectedImagesAs2dSelection"); - const std::string pairId = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - module->add2dSelectedImagesTo3d(pairId); - - return 0; -} - int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); const std::string id = ghoul::lua::value(L, 1); @@ -502,9 +390,6 @@ int setOpacityOfImageLayer(lua_State* L) { module->getPair(id)->setImageOpacity(i, opacity); } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->setImageOpacity(i, opacity); - } return 0; } @@ -627,18 +512,6 @@ int translateScreenSpaceRenderable(lua_State* L) { return 0; } -int place3dSkyBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::place3dSkyBrowser"); - // Image index to place in 3D - const int i = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - const ImageData image = module->getWwtDataHandler()->getImage(i); - - module->place3dBrowser(image, i); - - return 0; -} - int removeSelectedImageInBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); const std::string id = ghoul::lua::value(L, 1); @@ -652,9 +525,7 @@ int removeSelectedImageInBrowser(lua_State* L) { if (pair) { pair->removeSelectedImage(i); } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->removeSelectedImage(i); - } + return 0; } @@ -672,9 +543,6 @@ int setEquatorialAim(lua_State* L) { if (pair) { pair->setEquatorialAim(glm::dvec2(ra, dec)); } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->setEquatorialAim(glm::dvec2(ra, dec)); - } return 0; } @@ -692,9 +560,6 @@ int setVerticalFov(lua_State* L) { if (pair) { pair->setVerticalFov(vfov); } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->setVerticalFov(vfov); - } return 0; } @@ -714,9 +579,6 @@ int setBorderColor(lua_State* L) { if (pair) { pair->setBorderColor(color); } - else if (module->get3dBrowser(id)) { - module->get3dBrowser(id)->setBorderColor(color); - } return 0; } diff --git a/modules/skybrowser/src/renderableskybrowser.cpp b/modules/skybrowser/src/renderableskybrowser.cpp deleted file mode 100644 index 662f4305b9..0000000000 --- a/modules/skybrowser/src/renderableskybrowser.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include // formatJson -#include - - -namespace { - - constexpr const char* _loggerCat = "RenderableSkyBrowser"; - - const openspace::properties::Property::PropertyInfo DimensionsInfo = { - "Dimensions", - "Browser Dimensions", - "Set the dimensions of the web browser windows." - }; - const openspace::properties::Property::PropertyInfo UrlInfo = { - "Url", - "URL", - "The URL to load" - }; - - const openspace::properties::Property::PropertyInfo ReloadInfo = { - "Reload", - "Reload", - "Reload the web browser" - }; - - - struct [[codegen::Dictionary(RenderableSkyBrowser)]] Parameters { - - // [[codegen::verbatim(DimensionsInfo.description)]] - std::optional browserDimensions; - - // [[codegen::verbatim(UrlInfo.description)]] - std::optional url; - }; - -#include "renderableskybrowser_codegen.cpp" -} // namespace - -namespace openspace { - - - RenderableSkyBrowser::RenderableSkyBrowser(const ghoul::Dictionary& dictionary) - : RenderablePlane(dictionary), - WwtCommunicator(dictionary) - { - std::string identifier; - if (dictionary.hasValue(KeyIdentifier)) { - identifier = dictionary.value(KeyIdentifier); - } - else { - identifier = "RenderableSkyBrowser"; - } - setIdentifier(identifier); - - const Parameters p = codegen::bake(dictionary); - _url = p.url.value_or(_url); - - // Ensure the texture is a square for now - // Maybe change later - glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); - float maxDimension = std::max(windowDimensions.x, windowDimensions.y); - _browserPixeldimensions = { maxDimension, maxDimension }; - - addProperty(_url); - addProperty(_browserPixeldimensions); - addProperty(_reload); - } - - RenderableSkyBrowser::~RenderableSkyBrowser() { - - } - - void RenderableSkyBrowser::initializeGL() { - WwtCommunicator::initializeGL(); - RenderablePlane::initializeGL(); - } - - void RenderableSkyBrowser::deinitializeGL() { - - RenderablePlane::deinitializeGL(); - WwtCommunicator::deinitializeGL(); - } - - void RenderableSkyBrowser::update(const UpdateData& data) { - WwtCommunicator::update(); - RenderablePlane::update(data); - } - - void RenderableSkyBrowser::render(const RenderData& data, RendererTasks& rendererTask) - { - glDisable(GL_CULL_FACE); - WwtCommunicator::render(); - RenderablePlane::render(data, rendererTask); - } - - void RenderableSkyBrowser::setIdInBrowser() - { - WwtCommunicator::setIdInBrowser(identifier()); - } - - void RenderableSkyBrowser::placeAt3dPosition( - const glm::dvec3& positionSpeck, float verticalFov, - const std::string& sceneGraphNodeId) - { - // Uris for properties - std::string sizeUri = "Scene." + sceneGraphNodeId + "." + _identifier + ".Size"; - std::string positionUri = "Scene." + sceneGraphNodeId + ".Translation.Position"; - std::string rotationUri = "Scene." + sceneGraphNodeId + ".Rotation.Rotation"; - std::string cameraAim = "NavigationHandler.OrbitalNavigator.Aim"; - glm::dvec3 position = positionSpeck * distanceconstants::Parsec; - // Calculate the size of the plane with trigonometry - // Calculate in equatorial coordinate system since the FOV is from Earth - // /| - // /_| Adjacent is the horizontal line, opposite the vertical - // \ | Calculate for half the triangle first, then multiply with 2 - // \| - double adjacent = glm::length(position); - double opposite = 2 * adjacent * glm::tan(glm::radians(verticalFov * 0.5)); - - // Calculate rotation to make the plane face the solar system barycenter - glm::dvec3 normal = glm::normalize(-position); - glm::dvec3 newRight = glm::normalize( - glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) - ); - glm::dvec3 newUp = glm::cross(normal, newRight); - // Face the Solar System Barycenter as an approximation of Earth - glm::dmat3 rotation = glm::dmat3(1.0); - rotation[0] = newRight; - rotation[1] = newUp; - rotation[2] = normal; - - std::string setValue = "openspace.setPropertyValueSingle('"; - - openspace::global::scriptEngine->queueScript( - setValue + sizeUri + "', " + std::to_string(opposite) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - setValue + positionUri + "', " + ghoul::to_string(position) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - openspace::global::scriptEngine->queueScript( - setValue + rotationUri + "', " + ghoul::to_string(rotation) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - } - void RenderableSkyBrowser::bindTexture() - { - _texture->bind(); - } - void RenderableSkyBrowser::unbindTexture() - { - - } -} // namespace diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index a2d615c43e..074463b74e 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -77,20 +77,6 @@ namespace openspace { return str; } - std::unordered_map - loadSpeckData(const speck::Dataset& dataset) { - // Create map - std::unordered_map positions3d; - - for (speck::Dataset::Entry entry : dataset.entries) { - if (entry.comment.has_value()) { - std::string name = createSearchableString(entry.comment.value()); - positions3d[name] = std::move(entry.position); - } - } - return positions3d; - } - tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, const std::string& name) { while (node && node->Name() != name) { @@ -228,16 +214,8 @@ namespace openspace { _xmls.clear(); } - void WwtDataHandler::loadImages(const std::string& root, const std::string& directory, - std::vector& speckFiles) { - - // Load 3D data from speck files - for (std::filesystem::path& path : speckFiles) { - speck::Dataset speck = speck::data::loadFileWithCache(path); - _3dPositions = loadSpeckData(speck); - LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + - " entries!"); - } + void WwtDataHandler::loadImages(const std::string& root, + const std::string& directory) { // Collect the wtml files, either by reading from disc or from a url if (directoryExists(directory)) { @@ -271,9 +249,6 @@ namespace openspace { LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope " "images."); - - LINFO(std::to_string(_nMatched3dPositions) + " 3D positions were matched in " - "the speck files!"); } int WwtDataHandler::nLoadedImages() const @@ -325,7 +300,7 @@ namespace openspace { // Collect equatorial coordinates. All-sky surveys do not have this kind of // coordinate - const bool hasCelestialCoords = hasAttribute(node, wwt::RA) && + bool hasCelestialCoords = hasAttribute(node, wwt::RA) && hasAttribute(node, wwt::Dec); glm::dvec2 equatorialSpherical{ 0.0 }; glm::dvec3 equatorialCartesian{ 0.0 }; @@ -347,17 +322,6 @@ namespace openspace { fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0; } - // Find 3D position by matching with speck file - bool has3dCoords{ false }; - glm::dvec3 position3d{ 0.0 }; - auto it = _3dPositions.find(createSearchableString(name)); - if (it != _3dPositions.end()) { - position3d = it->second; - has3dCoords = true; - _nMatched3dPositions++; - LINFO("3d position was found for " + name); - } - ImageData image = { name, thumbnailUrl, @@ -366,11 +330,9 @@ namespace openspace { creditsUrl, collection, hasCelestialCoords, - has3dCoords, fov, equatorialSpherical, equatorialCartesian, - position3d }; _images.push_back(image); From 96149a797873f8fd630ae4c41c833e6b8567598e Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 09:50:26 -0500 Subject: [PATCH 197/251] Tidy up shader code --- modules/skybrowser/shaders/target_fs.glsl | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index ee7d042cd6..d1b3a605a7 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -46,14 +46,6 @@ float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { return crosshair_horizontal + crosshair_vertical; } -float createFilledRectangle(in float size, in float ratio, in vec2 coord) { - float center = 0.5f; - float horizontal = createLine(center, size, coord.y); - float vertical = createLine(center, size, coord.x); - - return horizontal * vertical; -} - #include "fragment.glsl" Fragment getFragment() { @@ -63,17 +55,14 @@ Fragment getFragment() { if(showCrosshair) { crosshair = createCrosshair(lineWidth, ratio, vs_st); + float border = 1.0f - createRectangle(lineWidth * 5.0f, ratio, vs_st); + crosshair *= border; } if(showRectangle) { rectangle = createRectangle(lineWidth, ratio, vs_st); } - // If both rectangle and crosshair are displayed, draw crosshair a bit smaller - if(showCrosshair && showRectangle) { - crosshair *= createFilledRectangle(lineWidth * 7.0f, ratio, vs_st); - } - float result = clamp(crosshair + rectangle, 0.0, 1.0); Fragment frag; From 4af95311b9436450e21e65ca02b6a97712849290 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 09:50:55 -0500 Subject: [PATCH 198/251] Add linewidth property to sky target --- .../skybrowser/include/screenspaceskytarget.h | 1 + .../skybrowser/src/screenspaceskytarget.cpp | 20 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 7a475ea0db..e5e677718a 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -63,6 +63,7 @@ namespace openspace { // Properties properties::FloatProperty _showCrosshairThreshold; properties::FloatProperty _showRectangleThreshold; + properties::FloatProperty _lineWidth; properties::DoubleProperty _stopAnimationThreshold; properties::DoubleProperty _animationSpeed; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 3c884b52bb..523449fe21 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -40,7 +40,7 @@ namespace { constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { "AnimationSpeed", - "TrAnimation Speed", + "Animation Speed", "The factor which is multiplied with the animation speed of the target." }; @@ -53,6 +53,13 @@ namespace { "equatorial Cartesian coordinate system." }; + constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = + { + "LineWidth", + "Line Width", + "The thickness of the line of the target. The larger number, the thicker line." + }; + struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { // [[codegen::verbatim(CrosshairThresholdInfo.description)]] @@ -67,6 +74,9 @@ namespace { // [[codegen::verbatim(AnimationThresholdInfo.description)]] std::optional animationThreshold; + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + }; #include "screenspaceskytarget_codegen.cpp" @@ -76,10 +86,11 @@ namespace { namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f) - , _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f) + , _showCrosshairThreshold(CrosshairThresholdInfo, 4.f, 0.1f, 70.f) + , _showRectangleThreshold(RectangleThresholdInfo, 2.f, 0.1f, 70.f) , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) + , _lineWidth(LineWidthInfo, 25.f, 1.f, 100.f) , _borderColor(220, 220, 220) { // Handle target dimension property @@ -93,6 +104,7 @@ namespace openspace { addProperty(_showRectangleThreshold); addProperty(_stopAnimationThreshold); addProperty(_animationSpeed); + addProperty(_lineWidth); // Set a unique identifier std::string identifier; @@ -188,7 +200,7 @@ namespace openspace { glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * localRotationMatrix() * scaleMatrix(); - float lineWidth = 0.0016f/_scale.value(); + float lineWidth = (_lineWidth * 0.0001f) / _scale.value(); glDisable(GL_CULL_FACE); From ea174f544e7f063b07d944abbbc970d310b7258a Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 09:51:06 -0500 Subject: [PATCH 199/251] Remove unneccessary time variables --- modules/skybrowser/include/screenspaceskytarget.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index e5e677718a..2fb25ea79d 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -95,13 +95,6 @@ namespace openspace { // Animation glm::dvec3 _animationEnd; // Cartesian equatorial coordinates glm::dvec3 _animationStart; // Cartesian equatorial coordinates - - // Time variables - // For capping sending of equatorial coordinates to sky browser - const std::chrono::microseconds interval = std::chrono::microseconds(10000); - std::chrono::time_point latestCall; - constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; - std::chrono::system_clock::time_point _lastUpdateTime; }; } From ee26ab4e0828c2d9e9cef9c1ee7038d043a39898 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 09:51:53 -0500 Subject: [PATCH 200/251] Remove comments with other urls for the sky browser --- modules/skybrowser/skybrowsermodule_lua.inl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 493536910a..45b04cdeb2 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -427,9 +427,7 @@ int createTargetBrowserPair(lua_State* L) { std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; - //std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - std::string url = "http://localhost:8000"; // check webgl version - //std::string url = "https://get.webgl.org"; + std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; const std::string browser = "{" "Identifier = '" + idBrowser + "'," From 46dc827180557310b5b32e4206dee6f29f6fc498 Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 15:35:07 -0500 Subject: [PATCH 201/251] Merge resolve from updating submodules --- modules/skybrowser/src/browser.cpp | 5 +++-- modules/skybrowser/src/wwtdatahandler.cpp | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index e235fe0845..88c51f7c0f 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -103,9 +103,10 @@ namespace openspace { bool Browser::initializeGL() { _texture = std::make_unique( - glm::uvec3(_browserPixeldimensions.value(), 1.0f) + glm::uvec3(glm::ivec2(_browserPixeldimensions.value()), 1), + GL_TEXTURE_2D ); - + _renderHandler->setTexture(*_texture); _browserInstance->initialize(); diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 074463b74e..3409d37bb7 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -32,11 +32,10 @@ namespace openspace { // Parsing and downloading of wtml files bool downloadFile(const std::string& url, const std::string& fileDestination) { // Get the web page and save to file - HttpRequest::RequestOptions opt{ 5 }; - SyncHttpFileDownload wtml_root( + HttpFileDownload wtml_root( url, fileDestination, HttpFileDownload::Overwrite::Yes ); - wtml_root.download(opt); + wtml_root.start(std::chrono::milliseconds(5)); return wtml_root.hasSucceeded(); } From d96ea9189d0e70262b5ad43e8ba0aa603a79aebd Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 16:05:15 -0500 Subject: [PATCH 202/251] Reset files that shouldn't be changed for pull request --- data/assets/customization/gui.asset | 2 +- data/assets/renderableBrowser.asset | 49 ----------------------- data/assets/util/webgui.asset | 2 +- modules/skybrowser/data/skyBrowser.asset | 11 ----- modules/skybrowser/data/skyTarget.asset | 10 ----- modules/skybrowser/src/wwtdatahandler.cpp | 38 ------------------ modules/space/speckloader.cpp | 2 +- 7 files changed, 3 insertions(+), 111 deletions(-) delete mode 100644 data/assets/renderableBrowser.asset delete mode 100644 modules/skybrowser/data/skyBrowser.asset delete mode 100644 modules/skybrowser/data/skyTarget.asset diff --git a/data/assets/customization/gui.asset b/data/assets/customization/gui.asset index e89fa7b955..6e7d14003f 100644 --- a/data/assets/customization/gui.asset +++ b/data/assets/customization/gui.asset @@ -1,4 +1,4 @@ -asset.export("webguiDevelopmentMode", true) +asset.export("webguiDevelopmentMode", false) -- To make changes to the webgui: diff --git a/data/assets/renderableBrowser.asset b/data/assets/renderableBrowser.asset deleted file mode 100644 index c81c82af08..0000000000 --- a/data/assets/renderableBrowser.asset +++ /dev/null @@ -1,49 +0,0 @@ -local assetHelper = asset.require("util/asset_helper") -local transforms = asset.require("scene/solarsystem/sun/transforms") - -local PARSEC_CONSTANT = 3.0856776E16; -local browserId = "SkyBrowser3D"; -local url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - -local browser = { - Identifier = browserId, - Parent = transforms.SolarSystemBarycenter.Identifier, - Transform = { - Translation = { - Type = "StaticTranslation", - Position = { - -3.915 * PARSEC_CONSTANT, - -150.153 * PARSEC_CONSTANT, - -120.706 * PARSEC_CONSTANT - }, - }, - Rotation = { - Type = "StaticRotation", - Rotation = {0.0, 0.0, 0.0} - } - }, - Renderable = { - Identifier = "SkyBrowser3DRenderable", - Type = "RenderableSkyBrowser", - Size = 10.0E11, - Origin = "Center", - Billboard = false, - Url = url, - Opacity = 0.99 - }, - GUI = { - Name = "Sky Browser 3D", - Path = "/SkyBrowser", - } -} - -asset.onInitialize(function () - openspace.addSceneGraphNode(browser) - openspace.skybrowser.add3dBrowserToSkyBrowserModule(browserId) -end) - -asset.onDeinitialize(function () - openspace.removeSceneGraphNode(browserId) -end) - -asset.export("browser", {browser}) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 0f8e350871..c1e0871036 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "60e1399472a86464e963a39ab6fc13de6a5f3bf4" +local frontendHash = "7f2b2b84ef526d7e67ed50462853a0d9a09b4f71" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ diff --git a/modules/skybrowser/data/skyBrowser.asset b/modules/skybrowser/data/skyBrowser.asset deleted file mode 100644 index b672166a03..0000000000 --- a/modules/skybrowser/data/skyBrowser.asset +++ /dev/null @@ -1,11 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - - local spec = { - Type = "ScreenSpaceSkyBrowser", - Identifier = "SkyBrowser1", - Name = "SkyBrowser", - Url = "http://localhost:8000/", - FaceCamera = false - }; - -assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/data/skyTarget.asset b/modules/skybrowser/data/skyTarget.asset deleted file mode 100644 index 547b43ad15..0000000000 --- a/modules/skybrowser/data/skyTarget.asset +++ /dev/null @@ -1,10 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - - local spec = { - Type = "ScreenSpaceSkyTarget", - Identifier = "SkyTarget1", - Name = "Target", - FaceCamera = false - }; - -assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 3409d37bb7..40aeabf4d1 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -364,41 +364,3 @@ namespace openspace { } } - -// Loading of speck files -namespace { - constexpr bool startsWith(std::string_view lhs, std::string_view rhs) noexcept { - return (rhs.size() <= lhs.size()) && (lhs.substr(0, rhs.size()) == rhs); - } - - void strip(std::string& line) noexcept { - // 1. Remove all spaces from the beginning - // 2. Remove # - // 3. Remove all spaces from the new beginning - // 4. Remove all spaces from the end - - while (!line.empty() && line[0] == ' ') { - line = line.substr(1); - } - - if (!line.empty() && line[0] == '#') { - line = line.substr(1); - } - - while (!line.empty() && line[0] == ' ') { - line = line.substr(1); - } - - while (!line.empty() && line.back() == ' ') { - line = line.substr(0, line.size() - 2); - } - } - - template - void checkSize(U value, std::string_view message) { - if (value > std::numeric_limits::max()) { - throw ghoul::RuntimeError(fmt::format("Error saving file: {}", message)); - } - } -} // namespace - diff --git a/modules/space/speckloader.cpp b/modules/space/speckloader.cpp index 9ededd31da..4d5f03d9d3 100644 --- a/modules/space/speckloader.cpp +++ b/modules/space/speckloader.cpp @@ -130,7 +130,6 @@ namespace { } } // namespace -#pragma optimize("", off) namespace openspace::speck { namespace data { @@ -333,6 +332,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) strip(rest); entry.comment = rest; } + int i = 0; i += 1; res.entries.push_back(std::move(entry)); From 380e317f3423af2dd31507a48625c0901719497a Mon Sep 17 00:00:00 2001 From: sylvass Date: Tue, 22 Feb 2022 16:25:46 -0500 Subject: [PATCH 203/251] More cleanup before pull request --- data/assets/skyBrowserTargetPair.asset | 37 -------------------------- modules/space/speckloader.cpp | 2 -- 2 files changed, 39 deletions(-) delete mode 100644 data/assets/skyBrowserTargetPair.asset diff --git a/data/assets/skyBrowserTargetPair.asset b/data/assets/skyBrowserTargetPair.asset deleted file mode 100644 index 4facf93371..0000000000 --- a/data/assets/skyBrowserTargetPair.asset +++ /dev/null @@ -1,37 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - -local targetId= "SkyTarget0" -local browserId = "SkyBrowser0" -local serverUrl = "https://data.openspaceproject.com/dist/skybrowser/page/" ---local localHostUrl = "http://localhost:8000" - -local browser = { - Type = "ScreenSpaceSkyBrowser", - Identifier = browserId, - Name = "Sky Browser", - Url = serverUrl, - FaceCamera = false, - CartesianPosition = {-1.0, -0.5, -2.1}, - Dimensions = { 1000, 1000 }, -}; - -local target = { - Type = "ScreenSpaceSkyTarget", - Identifier = targetId, - Name = "Sky Target", - FaceCamera = false, -}; - -asset.onInitialize(function () - openspace.addScreenSpaceRenderable(browser) - openspace.addScreenSpaceRenderable(target) - openspace.skybrowser.addPairToSkyBrowserModule(targetId,browserId) - openspace.skybrowser.setSelectedBrowser(browserId) -end) - -asset.onDeinitialize(function () - openspace.removeScreenSpaceRenderable(browserId) - openspace.removeScreenSpaceRenderable(targetId) -end) - -asset.export("browser", {browser, target}) diff --git a/modules/space/speckloader.cpp b/modules/space/speckloader.cpp index 4d5f03d9d3..8327ada08f 100644 --- a/modules/space/speckloader.cpp +++ b/modules/space/speckloader.cpp @@ -333,8 +333,6 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) entry.comment = rest; } - int i = 0; - i += 1; res.entries.push_back(std::move(entry)); } From 02c9ef4a7abadc1a45ad34fc7b9dc02f6898a0d3 Mon Sep 17 00:00:00 2001 From: sylvass Date: Mon, 28 Feb 2022 17:19:41 -0500 Subject: [PATCH 204/251] Add missing files --- .../skybrowser/include/targetbrowserpair.h | 144 ++++++ modules/skybrowser/src/targetbrowserpair.cpp | 425 ++++++++++++++++++ 2 files changed, 569 insertions(+) create mode 100644 modules/skybrowser/include/targetbrowserpair.h create mode 100644 modules/skybrowser/src/targetbrowserpair.cpp diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h new file mode 100644 index 0000000000..a074a5b09f --- /dev/null +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -0,0 +1,144 @@ +/***************************************************************************************** + * * + * 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_SKYBROWSER___TARGETBROWSERPAIR___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___TARGETBROWSERPAIR___H__ + +#include +#include + +namespace openspace { + +class ScreenSpaceSkyBrowser; +class ScreenSpaceSkyTarget; +class ScreenSpaceRenderable; +class ImageData; + +class TargetBrowserPair { +public: + + constexpr static const float FadeThreshold = 0.01f; + constexpr static const double AnimationThreshold = 0.0001f; + + TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); + TargetBrowserPair(TargetBrowserPair const&) = default; + // user-defined copy assignment (copy-and-swap idiom) + TargetBrowserPair& operator=(TargetBrowserPair other); + + // Target & Browser + void initialize(); + // Highlighting + void removeHighlight(glm::ivec3 color); + void highlight(glm::ivec3 color); + // Animation + void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); + void incrementallyAnimateToCoordinate(double deltaTime); + void incrementallyFade(float goalState, float fadeTime, float deltaTime); + // Mouse interaction + bool checkMouseIntersection(glm::vec2 mousePosition); + glm::vec2 selectedScreenSpacePosition(); + bool isBrowserSelected(); + bool isTargetSelected(); + void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); + void translateSelected(const glm::vec2& start, const glm::vec2& translation); + void synchronizeAim(); + + // Browser + void sendIdToBrowser(); + void updateBrowserSize(); + + // Target + void centerTargetOnScreen(); + void lock(); + void unlock(); + + // Boolean functions + bool hasFinishedFading(float goalState) const; + bool isFacingCamera() const; + bool isUsingRadiusAzimuthElevation() const; + bool isEnabled() const; + bool isLocked() const; + + // Setters + void setEnabled(bool enable); + void setIsSyncedWithWwt(bool isSynced); + void setVerticalFov(float vfov); + void setEquatorialAim(const glm::dvec2& aim); + void setBorderColor(const glm::ivec3& color); + void setScreenSpaceSize(const glm::vec2& dimensions); + void setVerticalFovWithScroll(float scroll); + void setSelectedWithId(const std::string& id); + + // Getters by value + float verticalFov() const; + glm::ivec3 borderColor() const; + glm::dvec2 targetDirectionEquatorial() const; + glm::dvec3 targetDirectionGalactic() const; + std::string browserGuiName() const; + std::string browserId() const; + std::string targetId() const; + std::string selectedId(); + glm::vec2 size() const; + + // Getters by reference + ScreenSpaceSkyTarget* getTarget(); + ScreenSpaceSkyBrowser* getBrowser(); + const std::deque& getSelectedImages() const; + + // WorldWide Telescope image handling + void setImageOrder(int i, int order); + void selectImage(const ImageData& image, int i); + void removeSelectedImage(int i); + void loadImageCollection(const std::string& collection); + void setImageOpacity(int i, float opacity); + void hideChromeInterface(bool shouldHide); + + // Comparision operators + friend bool operator==(const TargetBrowserPair& lhs, + const TargetBrowserPair& rhs); + friend bool operator!=(const TargetBrowserPair& lhs, + const TargetBrowserPair& rhs); + +private: + bool isTargetFadeFinished(float goalState) const; + bool isBrowserFadeFinished(float goalState) const; + + // Selection + ScreenSpaceRenderable* _selected{ nullptr }; + bool _isSelectedBrowser{ false }; + + // Target and browser + ScreenSpaceSkyTarget* _target{ nullptr }; + ScreenSpaceSkyBrowser* _browser{ nullptr }; + + // Shared properties between the target and the browser + float _verticalFov{ 70.0f }; + glm::dvec2 _equatorialAim{ 0.0 }; + glm::ivec3 _borderColor{ 255 }; + glm::vec2 _dimensions{ 0.5f, 0.5f }; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SKYBROWSER___TARGETBROWSERPAIR___H__ diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp new file mode 100644 index 0000000000..613b39c7e3 --- /dev/null +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -0,0 +1,425 @@ +/***************************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include + +namespace openspace { + + TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) + : _target(target), _browser(browser) + { + ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); + ghoul_assert(target != nullptr, "Sky target is null pointer!"); + } + + TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) + { + std::swap(_target, other._target); + std::swap(_browser, other._browser); + return *this; + + } + + void TargetBrowserPair::lock() { + _target->setLock(true); + } + + void TargetBrowserPair::unlock() { + _target->setLock(false); + } + + void TargetBrowserPair::setImageOrder(int i, int order) { + _browser->setImageOrder(i, order); + } + + void TargetBrowserPair::removeHighlight(glm::ivec3 color) + { + _target->removeHighlight(color); + _browser->removeHighlight(color); + } + + void TargetBrowserPair::highlight(glm::ivec3 color) + { + _browser->highlight(color); + _target->highlight(color); + } + + bool TargetBrowserPair::isTargetFadeFinished(float goalState) const + { + // Is fading finished? + float targetDiff = abs(_target->opacity() - goalState); + + return targetDiff < FadeThreshold; + } + + bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const + { + float browserDiff = abs(_browser->opacity() - goalState); + return browserDiff < FadeThreshold; + } + + bool TargetBrowserPair::checkMouseIntersection(glm::vec2 mousePosition) + { + bool onBrowser = _browser->intersection(mousePosition); + bool onTarget = _target->intersection(mousePosition); + if (onBrowser) { + _selected = _browser; + _isSelectedBrowser = true; + } + else if (onTarget) { + _selected = _target; + _isSelectedBrowser = false; + } + else { + _selected = nullptr; + _isSelectedBrowser = false; + } + return onBrowser || onTarget; + } + + glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() + { + return _selected->screenSpacePosition(); + } + + bool TargetBrowserPair::isBrowserSelected() + { + return _isSelectedBrowser; + } + + bool TargetBrowserPair::isTargetSelected() + { + return _selected && !_isSelectedBrowser; + } + + void TargetBrowserPair::fineTuneTarget(const glm::vec2& start, + const glm::vec2& translation) + { + glm::vec2 fineTune = -_browser->fineTuneVector(translation); + + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.translateScreenSpaceRenderable(\"" + targetId() + "\"," + + std::to_string(start.x) + "," + std::to_string(start.y) + "," + + std::to_string(translation.x) + "," + std::to_string(translation.y) + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + + void TargetBrowserPair::translateSelected(const glm::vec2& start, + const glm::vec2& translation) + { + if (this && _selected) { + std::string id = _selected->identifier(); + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.translateScreenSpaceRenderable(\"" + id + "\"," + + std::to_string(start.x) + "," + std::to_string(start.y) + "," + + std::to_string(translation.x) + "," + std::to_string(translation.y) + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + } + + void TargetBrowserPair::synchronizeAim() + { + if (!_target->isAnimated()) { + glm::dvec2 aim; + // To remove the lag effect when moving the camera while having a locked + // target, send the locked coordinates to wwt + if (_target->isLocked()) { + aim = _target->lockedCoordinates(); + } + else { + aim = _target->equatorialAim(); + } + + _browser->setEquatorialAim(aim); + _target->setScaleFromVfov(_browser->verticalFov()); + } + } + + void TargetBrowserPair::setEnabled(bool enable) + { + _browser->setEnabled(enable); + _target->setEnabled(enable); + } + + bool TargetBrowserPair::isEnabled() const + { + return _target->isEnabled() && _browser->isEnabled(); + } + + bool TargetBrowserPair::isLocked() const + { + return _target->isLocked(); + } + + void TargetBrowserPair::initialize() + { + _target->setColor(_browser->borderColor()); + _target->setDimensions(_browser->browserPixelDimensions()); + _target->setScaleFromVfov(_browser->verticalFov()); + _browser->updateBorderColor(); + } + + glm::ivec3 TargetBrowserPair::borderColor() const + { + return _browser->borderColor(); + } + + glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const + { + return _target->equatorialAim(); + } + + glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const + { + return _target->directionGalactic(); + } + + std::string TargetBrowserPair::browserGuiName() const + { + return _browser->guiName(); + } + + std::string TargetBrowserPair::browserId() const + { + return _browser->identifier(); + } + + std::string TargetBrowserPair::targetId() const + { + return _target->identifier(); + } + + std::string TargetBrowserPair::selectedId() + { + return _selected->identifier(); + } + + glm::vec2 TargetBrowserPair::size() const + { + return _browser->size(); + } + + float TargetBrowserPair::verticalFov() const + { + return _browser->verticalFov(); + } + + const std::deque& TargetBrowserPair::getSelectedImages() const + { + return _browser->getSelectedImages(); + } + + void TargetBrowserPair::selectImage(const ImageData& image, int i) + { + // Load image into browser + _browser->displayImage(image.imageUrl, i); + + // If the image has coordinates, move the target + if (image.hasCelestialCoords) { + + // Animate the target to the image coordinate position + unlock(); + startAnimation(image.equatorialCartesian, image.fov, true); + } + } + + void TargetBrowserPair::removeSelectedImage(int i) + { + _browser->removeSelectedImage(i); + } + + void TargetBrowserPair::loadImageCollection(const std::string& collection) + { + _browser->loadImageCollection(collection); + } + + void TargetBrowserPair::setImageOpacity(int i, float opacity) + { + _browser->setImageOpacity(i, opacity); + } + + void TargetBrowserPair::hideChromeInterface(bool shouldHide) + { + _browser->hideChromeInterface(shouldHide); + } + + void TargetBrowserPair::sendIdToBrowser() + { + _browser->setIdInBrowser(); + } + + void TargetBrowserPair::updateBrowserSize() { + _browser->updateBrowserSize(); + } + + void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) + { + _browser->setIsSyncedWithWwt(isSynced); + } + + void TargetBrowserPair::setVerticalFov(float vfov) + { + _verticalFov = vfov; + _browser->setVerticalFov(vfov); + _target->setScaleFromVfov(vfov); + } + + void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) + { + _equatorialAim = aim; + _target->setEquatorialAim(aim); + _browser->setEquatorialAim(aim); + } + + void TargetBrowserPair::setBorderColor(const glm::ivec3& color) + { + _borderColor = color; + _target->setColor(color); + _browser->setBorderColor(color); + } + + void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) + { + _dimensions = dimensions; + _target->setDimensions(dimensions); + _browser->setScreenSpaceSize(dimensions); + } + + void TargetBrowserPair::setVerticalFovWithScroll(float scroll) + { + _browser->setVerticalFovWithScroll(scroll); + } + + void TargetBrowserPair::setSelectedWithId(const std::string& id) + { + if (browserId() == id) { + _isSelectedBrowser = true; + _selected = _browser; + } + else if (targetId() == id) { + _isSelectedBrowser = false; + _selected = _target; + } + else { + _isSelectedBrowser = false; + _selected = nullptr; + } + } + + void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) + { + // Animate the target before the field of view starts to animate + if (_target->isAnimated()) { + _target->incrementallyAnimateToCoordinate(static_cast(deltaTime)); + } + else if (_browser->isAnimated()) { + _browser->incrementallyAnimateToFov(static_cast(deltaTime)); + } + } + + void TargetBrowserPair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, + bool shouldLockAfter) + { + _target->startAnimation(equatorialCoords, shouldLockAfter); + _browser->startFovAnimation(fovEnd); + } + + void TargetBrowserPair::centerTargetOnScreen() + { + // Animate the target to the center of the screen + unlock(); + // Get camera direction in celestial spherical coordinates + glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); + // Keep the current fov + float currentFov = verticalFov(); + startAnimation(viewDirection, currentFov, false); + } + + bool TargetBrowserPair::hasFinishedFading(float goalState) const + { + return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); + } + + bool TargetBrowserPair::isFacingCamera() const + { + return _browser->isFacingCamera() || _target->isFacingCamera(); + } + + bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const + { + return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); + } + + ScreenSpaceSkyTarget* TargetBrowserPair::getTarget() { + return _target; + } + + ScreenSpaceSkyBrowser* TargetBrowserPair::getBrowser() { + return _browser; + } + + void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, float deltaTime) + { + float opacityDelta = static_cast(deltaTime / fadeTime); + if (_target->opacity() > goalState) { + opacityDelta *= -1.f; + } + + if (!isTargetFadeFinished(goalState)) { + _target->setOpacity(_target->opacity() + opacityDelta); + } + else { + _target->setOpacity(goalState); + } + + if (!isBrowserFadeFinished(goalState)) { + _browser->setOpacity(_browser->opacity() + opacityDelta); + } + else { + _browser->setOpacity(goalState); + } + } + + bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { + return lhs._target == rhs._target && lhs._browser == rhs._browser; + } + bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { + return !(lhs == rhs); + } + + +} // namespace openspace From 21e572149e328140121ca7bc2d1de53ddee67b61 Mon Sep 17 00:00:00 2001 From: sylvass Date: Wed, 2 Mar 2022 16:39:44 -0500 Subject: [PATCH 205/251] Fix comments from pull request --- data/assets/hoverCircle.asset | 26 +- data/assets/util/webgui.asset | 22 +- .../rendering/screenspacerenderable.h | 2 - modules/skybrowser/CMakeLists.txt | 53 +- modules/skybrowser/include/browser.h | 9 +- .../include/screenspaceskybrowser.h | 113 +-- .../skybrowser/include/screenspaceskytarget.h | 158 ++-- .../skybrowser/include/targetbrowserpair.h | 12 +- modules/skybrowser/include/utility.h | 114 +-- modules/skybrowser/include/wwtcommunicator.h | 73 +- modules/skybrowser/include/wwtdatahandler.h | 82 ++- modules/skybrowser/shaders/target_fs.glsl | 78 +- modules/skybrowser/shaders/target_vs.glsl | 29 +- modules/skybrowser/skybrowsermodule.cpp | 185 ++--- modules/skybrowser/skybrowsermodule.h | 41 +- modules/skybrowser/skybrowsermodule_lua.inl | 227 +++--- modules/skybrowser/src/browser.cpp | 282 ++++---- .../skybrowser/src/screenspaceskybrowser.cpp | 407 +++++------ .../skybrowser/src/screenspaceskytarget.cpp | 89 +-- modules/skybrowser/src/targetbrowserpair.cpp | 145 ++-- modules/skybrowser/src/utility.cpp | 372 +++++----- modules/skybrowser/src/wwtcommunicator.cpp | 532 +++++++------- modules/skybrowser/src/wwtdatahandler.cpp | 677 +++++++++--------- 23 files changed, 1867 insertions(+), 1861 deletions(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index 4110a238ed..54fc5fd2ce 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -1,18 +1,16 @@ -local assetHelper = asset.require('util/asset_helper') - local id = "HoverCircle" local circle = { - Identifier = id, - Type = "ScreenSpaceImageLocal", - Name = "HoverCircle", - FaceCamera = false, - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome - Scale= 0.025, - Enabled = false, - TexturePath = "${ASSETS}/circle.png", - CartesianPosition = { 0, 0, -2.1 }, + Identifier = id, + Type = "ScreenSpaceImageLocal", + Name = "HoverCircle", + FaceCamera = false, + UseRadiusAzimuthElevation = false, + RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome + Scale = 0.025, + Enabled = false, + TexturePath = "${ASSETS}/circle.png", + CartesianPosition = { 0, 0, -2.1 }, }; asset.onInitialize(function () @@ -21,7 +19,7 @@ asset.onInitialize(function () end) asset.onDeinitialize(function () - openspace.removeScreenSpaceRenderable(circle) + openspace.removeScreenSpaceRenderable(circle) end) -asset.export("circle", {circle}) +asset.export("circle", circle) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index c1e0871036..3be431b3ef 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -1,9 +1,9 @@ -asset.require('./static_server') +asset.require("./static_server") -local guiCustomization = asset.require('customization/gui') +local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "7f2b2b84ef526d7e67ed50462853a0d9a09b4f71" +local frontendHash = "aa9aa521ace55cc25f447d287d34624f2cb56832" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ @@ -15,9 +15,9 @@ local frontend = asset.syncedResource({ asset.onInitialize(function () -- Unzip the frontend bundle - local dest = frontend .. "/frontend" + local dest = frontend .. "frontend" if not openspace.directoryExists(dest) then - openspace.unzipFile(frontend .. "/frontend.zip", dest, true) + openspace.unzipFile(frontend .. "frontend.zip", dest, true) end -- Disable the server, add production gui endpoint, and restart server. @@ -31,7 +31,7 @@ asset.onInitialize(function () local directories = openspace.getPropertyValue("Modules.WebGui.Directories") directories[#directories + 1] = "frontend" - directories[#directories + 1] = frontend .. '/frontend' + directories[#directories + 1] = frontend .. "frontend" openspace.setPropertyValueSingle("Modules.WebGui.Directories", directories) openspace.setPropertyValueSingle("Modules.WebGui.DefaultEndpoint", "frontend") @@ -39,12 +39,12 @@ asset.onInitialize(function () -- The GUI contains date and simulation increment, -- so let's remove these from the dashboard. - if openspace.getPropertyValue('Modules.CefWebGui.Visible') then - if openspace.hasProperty('Dashboard.Date.Enabled') then - openspace.setPropertyValueSingle('Dashboard.Date.Enabled', false) + if openspace.getPropertyValue("Modules.CefWebGui.Visible") then + if openspace.hasProperty("Dashboard.Date.Enabled") then + openspace.setPropertyValueSingle("Dashboard.Date.Enabled", false) end - if openspace.hasProperty('Dashboard.SimulationIncrement.Enabled') then - openspace.setPropertyValueSingle('Dashboard.SimulationIncrement.Enabled', false) + if openspace.hasProperty("Dashboard.SimulationIncrement.Enabled") then + openspace.setPropertyValueSingle("Dashboard.SimulationIncrement.Enabled", false) end end end) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 815cd55a70..8fb13795f8 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -75,7 +75,6 @@ public: void setEnabled(bool isEnabled); float depth(); - // Added by skybrowser team // Screen space functionality in these coords: [-1,1][-ratio,ratio] glm::vec2 screenSpacePosition(); glm::vec2 screenSpaceDimensions(); @@ -86,7 +85,6 @@ public: void setCartesianPosition(const glm::vec3& position); void setRaeFromCartesianPosition(const glm::vec3& position); glm::vec3 raePosition() const; - // End of addition by skybrowser team static documentation::Documentation Documentation(); diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index d5f3196a2b..60387683c1 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -2,7 +2,7 @@ # # # OpenSpace # # # -# Copyright (c) 2014-2021 # +# Copyright (c) 2014-2022 # # # # 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 # @@ -25,40 +25,35 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES - - skybrowsermodule.h - include/screenspaceskytarget.h - include/wwtdatahandler.h - include/utility.h - include/targetbrowserpair.h - include/wwtcommunicator.h - include/browser.h - include/screenspaceskybrowser.h - ext/tinyxml2/tinyxml2.h - + skybrowsermodule.h + include/screenspaceskytarget.h + include/wwtdatahandler.h + include/utility.h + include/targetbrowserpair.h + include/wwtcommunicator.h + include/browser.h + include/screenspaceskybrowser.h + ext/tinyxml2/tinyxml2.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES - - skybrowsermodule.cpp - skybrowsermodule_lua.inl - src/screenspaceskytarget.cpp - src/wwtdatahandler.cpp - src/utility.cpp - src/targetbrowserpair.cpp - src/wwtcommunicator.cpp - src/browser.cpp - src/screenspaceskybrowser.cpp - ext/tinyxml2/tinyxml2.cpp - + skybrowsermodule.cpp + skybrowsermodule_lua.inl + src/screenspaceskytarget.cpp + src/wwtdatahandler.cpp + src/utility.cpp + src/targetbrowserpair.cpp + src/wwtcommunicator.cpp + src/browser.cpp + src/screenspaceskybrowser.cpp + ext/tinyxml2/tinyxml2.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) - create_new_module( - "SkyBrowser" - skybrowser_module - STATIC - ${HEADER_FILES} ${SOURCE_FILES} + "SkyBrowser" + skybrowser_module + STATIC + ${HEADER_FILES} ${SOURCE_FILES} ) diff --git a/modules/skybrowser/include/browser.h b/modules/skybrowser/include/browser.h index 192258d23d..f33d1e6be2 100644 --- a/modules/skybrowser/include/browser.h +++ b/modules/skybrowser/include/browser.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -25,8 +25,8 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___BROWSER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___BROWSER___H__ -#include #include +#include #include #include #include @@ -61,9 +61,8 @@ class WebKeyboardHandler; class Browser { public: - Browser(const ghoul::Dictionary& dictionary); - Browser(Browser const&) = default; - ~Browser(); + explicit Browser(const ghoul::Dictionary& dictionary); + virtual ~Browser(); bool initializeGL(); bool deinitializeGL(); diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index e79bc50265..b9ba42efeb 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -1,8 +1,33 @@ -#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ -#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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_SKYBROWSER___SCREENSPACESKYBROWSER___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ #include #include + #include #include #include @@ -10,58 +35,56 @@ namespace openspace { - class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator - { - public: - constexpr static const double FovThreshold = 0.001f; +class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator +{ +public: + constexpr static const double FovThreshold = 0.001; - // Constructor and destructor - ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); - ~ScreenSpaceSkyBrowser(); + explicit ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); + ~ScreenSpaceSkyBrowser(); - // Inherited functions - bool initializeGL() override; - bool deinitializeGL() override; - glm::mat4 scaleMatrix() override; - void render() override; - void update() override; + bool initializeGL() override; + bool deinitializeGL() override; + glm::mat4 scaleMatrix() override; + void render() override; + void update() override; - // Animation - bool isAnimated(); - void startFovAnimation(float fov); - void incrementallyAnimateToFov(float deltaTime); + // Animation + bool isAnimated() const; + void startFovAnimation(float fov); + void incrementallyAnimateToFov(float deltaTime); - // Getters - float opacity() const; - glm::vec2 size() const; + // Getters + float opacity() const; + glm::vec2 size() const; - // Setters - void setVerticalFovWithScroll(float scroll); - void setOpacity(float opacity); - void setScreenSpaceSize(const glm::vec2& newSize); - void updateScreenSpaceSize(); + // Setters + void setVerticalFovWithScroll(float scroll); + void setOpacity(float opacity); + void setScreenSpaceSize(const glm::vec2& newSize); + void updateScreenSpaceSize(); - glm::dvec2 fineTuneVector(glm::dvec2 drag); - void setIdInBrowser(); + glm::dvec2 fineTuneVector(glm::dvec2 drag); + void setIdInBrowser(); - void updateTextureResolution(); + void updateTextureResolution(); - private: - properties::DoubleProperty _animationSpeed; - properties::FloatProperty _textureQuality; +private: + properties::DoubleProperty _animationSpeed; + properties::FloatProperty _textureQuality; - void bindTexture() override; + void bindTexture() override; - // Flags - bool _isSyncedWithWwt{ false }; - bool _isFovAnimated{ false }; - bool _textureDimensionsIsDirty{ false }; - bool _sizeIsDirty{ false }; + // Flags + bool _isSyncedWithWwt = false; + bool _isFovAnimated = false; + bool _textureDimensionsIsDirty = false; + bool _sizeIsDirty = false; - // Animation of fieldOfView - float _endVfov{ 0.f }; - glm::vec2 _size{ 0.5f }; - }; -} + // Animation of fieldOfView + float _endVfov = 0.f; + glm::vec2 _size = glm::vec2(0.5f); +}; +} // namespace openspace -#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__ +#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__ diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 2fb25ea79d..866a4d9869 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -1,7 +1,32 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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_SKYBROWSER___SCREENSPACESKYTARGET___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ #include + #include #include #include @@ -10,92 +35,83 @@ namespace openspace::documentation { struct Documentation; } namespace openspace { - class ScreenSpaceSkyBrowser; +class ScreenSpaceSkyBrowser; - class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { +class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { - public: - constexpr static const float DeltaTimeThreshold = 0.03f; +public: + constexpr static const float DeltaTimeThreshold = 0.03f; - // Constructor & destructor - ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); - virtual ~ScreenSpaceSkyTarget(); + explicit ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); + virtual ~ScreenSpaceSkyTarget(); - // ScreenSpaceRenderable inherited functions - bool initializeGL() override; - bool deinitializeGL() override; - bool isReady() const override; - void render() override; - void update() override; - glm::mat4 scaleMatrix() override; - void bindTexture() override; // Empty function but has to be defined - void createShaders(); + bool initializeGL() override; + bool deinitializeGL() override; + bool isReady() const override; + void render() override; + void update() override; + glm::mat4 scaleMatrix() override; + void bindTexture() override; // Empty function but has to be defined + void createShaders(); - glm::ivec3 borderColor() const; - float opacity() const; - glm::dvec2 lockedCoordinates() const; + glm::ivec3 borderColor() const; + float opacity() const; + glm::dvec2 lockedCoordinates() const; - // Setters - void setScaleFromVfov(float verticalFov); - void setFovFromScale(); - void setDimensions(glm::vec2 dimensions); - void setColor(glm::ivec3 color); - void setOpacity(float opacity); - void setLock(bool isLocked); - void setEquatorialAim(const glm::dvec2& aim); + void setScaleFromVfov(float verticalFov); + void setFovFromScale(); + void setDimensions(glm::vec2 dimensions); + void setColor(glm::ivec3 color); + void setOpacity(float opacity); + void setLock(bool isLocked); + void setEquatorialAim(const glm::dvec2& aim); - // Target directions - glm::dvec3 directionGalactic() const; - glm::dvec2 equatorialAim() const; + // Target directions + glm::dvec3 directionGalactic() const; + glm::dvec2 equatorialAim() const; - // Locking functionality - bool isLocked() const; + // Locking functionality + bool isLocked() const; - // Animation - bool isAnimated(); - void startAnimation(glm::dvec3 end, bool shouldLockAfter = true); - void incrementallyAnimateToCoordinate(float deltaTime); - // Display - void highlight(glm::ivec3 addition); - void removeHighlight(glm::ivec3 removal); + // Animation + bool isAnimated(); + void startAnimation(glm::dvec3 end, bool shouldLockAfter = true); + void incrementallyAnimateToCoordinate(float deltaTime); + // Display + void highlight(glm::ivec3 addition); + void removeHighlight(glm::ivec3 removal); - private: - // Properties - properties::FloatProperty _showCrosshairThreshold; - properties::FloatProperty _showRectangleThreshold; - properties::FloatProperty _lineWidth; - properties::DoubleProperty _stopAnimationThreshold; - properties::DoubleProperty _animationSpeed; +private: + // Properties + properties::FloatProperty _showCrosshairThreshold; + properties::FloatProperty _showRectangleThreshold; + properties::FloatProperty _lineWidth; + properties::DoubleProperty _stopAnimationThreshold; + properties::DoubleProperty _animationSpeed; - // Flags - bool _isLocked{ false }; - bool _isAnimated{ false }; - bool _shouldLockAfterAnimation{ false }; + // Flags + bool _isLocked = false; + bool _isAnimated = false; + bool _shouldLockAfterAnimation = false; - // Shader - UniformCache( - modelTransform, - viewProj, - showCrosshair, - showRectangle, - lineWidth, - dimensions, - lineColor) _uniformCache; - GLuint _vertexArray = 0; - GLuint _vertexBuffer = 0; + // Shader + UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, + dimensions, lineColor) _uniformCache; + GLuint _vertexArray = 0; + GLuint _vertexBuffer = 0; - // Sky browser - float _verticalFov{ 70.0f }; - glm::dvec2 _equatorialAim{ 0.0 }; - glm::ivec3 _borderColor{ 255 }; + // Sky browser + float _verticalFov = 70.0f; + glm::dvec2 _equatorialAim = glm::dvec2(0.0); + glm::ivec3 _borderColor = glm::ivec3(255); - // Lock target to a coordinate on the sky - glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates + // Lock target to a coordinate on the sky + glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates - // Animation - glm::dvec3 _animationEnd; // Cartesian equatorial coordinates - glm::dvec3 _animationStart; // Cartesian equatorial coordinates - }; + // Animation + glm::dvec3 _animationEnd; // Cartesian equatorial coordinates + glm::dvec3 _animationStart; // Cartesian equatorial coordinates +}; } #endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index a074a5b09f..5fe396cfa8 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -37,13 +37,10 @@ class ImageData; class TargetBrowserPair { public: - constexpr static const float FadeThreshold = 0.01f; constexpr static const double AnimationThreshold = 0.0001f; TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); - TargetBrowserPair(TargetBrowserPair const&) = default; - // user-defined copy assignment (copy-and-swap idiom) TargetBrowserPair& operator=(TargetBrowserPair other); // Target & Browser @@ -73,14 +70,12 @@ public: void lock(); void unlock(); - // Boolean functions bool hasFinishedFading(float goalState) const; bool isFacingCamera() const; bool isUsingRadiusAzimuthElevation() const; bool isEnabled() const; bool isLocked() const; - // Setters void setEnabled(bool enable); void setIsSyncedWithWwt(bool isSynced); void setVerticalFov(float vfov); @@ -90,7 +85,6 @@ public: void setVerticalFovWithScroll(float scroll); void setSelectedWithId(const std::string& id); - // Getters by value float verticalFov() const; glm::ivec3 borderColor() const; glm::dvec2 targetDirectionEquatorial() const; @@ -100,8 +94,7 @@ public: std::string targetId() const; std::string selectedId(); glm::vec2 size() const; - - // Getters by reference + ScreenSpaceSkyTarget* getTarget(); ScreenSpaceSkyBrowser* getBrowser(); const std::deque& getSelectedImages() const; @@ -114,7 +107,6 @@ public: void setImageOpacity(int i, float opacity); void hideChromeInterface(bool shouldHide); - // Comparision operators friend bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs); friend bool operator!=(const TargetBrowserPair& lhs, diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index c8c394a411..37756b13f9 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -1,63 +1,81 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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_SKYBROWSER___UTILITY___H__ #define __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ #include -namespace openspace { - namespace skybrowser { - // Constants - constexpr const double ScreenSpaceZ = -2.1; - constexpr const glm::dvec3 NorthPole = { 0.0 , 0.0 , 1.0 }; - constexpr const double CelestialSphereRadius = std::numeric_limits::max(); +namespace openspace::skybrowser { +// Constants +constexpr const double ScreenSpaceZ = -2.1; +constexpr const glm::dvec3 NorthPole = { 0.0 , 0.0 , 1.0 }; +constexpr const double CelestialSphereRadius = std::numeric_limits::max(); - // Conversion matrix - J2000 equatorial <-> galactic - // https://arxiv.org/abs/1010.3773v1 - const glm::dmat3 conversionMatrix = glm::dmat3({ - -0.054875539390, 0.494109453633, -0.867666135681, // col 0 - -0.873437104725, -0.444829594298, -0.198076389622, // col 1 - -0.483834991775, 0.746982248696, 0.455983794523 // col 2 - }); +// Conversion matrix - J2000 equatorial <-> galactic +// https://arxiv.org/abs/1010.3773v1 +const glm::dmat3 conversionMatrix = glm::dmat3({ + -0.054875539390, 0.494109453633, -0.867666135681, // col 0 + -0.873437104725, -0.444829594298, -0.198076389622, // col 1 + -0.483834991775, 0.746982248696, 0.455983794523 // col 2 + }); - // Galactic coordinates are projected onto the celestial sphere - // Equatorial coordinates are unit length - // Conversion spherical <-> Cartesian - glm::dvec2 cartesianToSpherical(const glm::dvec3& coords); - glm::dvec3 sphericalToCartesian(const glm::dvec2& coords); +// Galactic coordinates are projected onto the celestial sphere +// Equatorial coordinates are unit length +// Conversion spherical <-> Cartesian +glm::dvec2 cartesianToSpherical(const glm::dvec3& coords); +glm::dvec3 sphericalToCartesian(const glm::dvec2& coords); - // Conversion J2000 equatorial <-> galactic - glm::dvec3 galacticToEquatorial(const glm::dvec3& coords); - glm::dvec3 equatorialToGalactic(const glm::dvec3& coords); +// Conversion J2000 equatorial <-> galactic +glm::dvec3 galacticToEquatorial(const glm::dvec3& coords); +glm::dvec3 equatorialToGalactic(const glm::dvec3& coords); - // Conversion to screen space from local camera / pixels - glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords); - glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate); +// Conversion to screen space from local camera / pixels +glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords); +glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate); - // Conversion local camera space <-> galactic / equatorial - glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords); - glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords); - glm::dvec3 localCameraToGalactic(const glm::dvec3& coords); - glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); +// Conversion local camera space <-> galactic / equatorial +glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords); +glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords); +glm::dvec3 localCameraToGalactic(const glm::dvec3& coords); +glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); - // Camera roll and direction - double cameraRoll(); // Camera roll is with respect to the equatorial North Pole - glm::dvec3 cameraDirectionGalactic(); - glm::dvec3 cameraDirectionEquatorial(); +// Camera roll and direction +double cameraRoll(); // Camera roll is with respect to the equatorial North Pole +glm::dvec3 cameraDirectionGalactic(); +glm::dvec3 cameraDirectionEquatorial(); - // Window and field of view - float windowRatio(); - glm::dvec2 fovWindow(); - bool isCoordinateInView(const glm::dvec3& equatorial); +// Window and field of view +float windowRatio(); +glm::dvec2 fovWindow(); +bool isCoordinateInView(const glm::dvec3& equatorial); - // Animation for target and camera - double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); - glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, - const glm::dvec3& end, - double deltaTime, - double speedFactor = 1.0); - } -} +// Animation for target and camera +double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); +glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, + double deltaTime, double speedFactor = 1.0); + +} // namespace openspace::skybrowser #endif // __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ - - - diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 1cc582e293..7ef1c1adf8 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_SKYBROWSER___WWTCOMMUNICATOR___H__ #include + #include #include #include @@ -35,11 +36,10 @@ namespace openspace { class WwtCommunicator : public Browser { - public: - WwtCommunicator(const ghoul::Dictionary& dictionary); - WwtCommunicator(WwtCommunicator const&) = default; - virtual ~WwtCommunicator(); + explicit WwtCommunicator(const ghoul::Dictionary& dictionary); + WwtCommunicator(const WwtCommunicator&) = default; + ~WwtCommunicator(); void update(); void render(); @@ -48,74 +48,65 @@ public: // WorldWide Telescope communication void displayImage(const std::string& url, int i); - void removeSelectedImage(const int i); + void removeSelectedImage(int i); void setImageOrder(int i, int order); void loadImageCollection(const std::string& collection); void setImageOpacity(int i, float opacity); void hideChromeInterface(bool shouldHide); - // Getters - const std::deque& getSelectedImages(); - glm::ivec3 borderColor() const; - float verticalFov() const; - glm::dvec2 fieldsOfView(); bool hasLoadedImages() const; + float verticalFov() const; + glm::ivec3 borderColor() const; glm::dvec2 equatorialAim() const; + glm::dvec2 fieldsOfView() const; + const std::deque& getSelectedImages() const; - // Setters void setHasLoadedImages(bool isLoaded); void setVerticalFov(float vfov); void setIsSyncedWithWwt(bool isSynced); - void setEquatorialAim(const glm::dvec2& equatorial); - void setBorderColor(const glm::ivec3& color); + void setEquatorialAim(glm::dvec2 equatorial); + void setBorderColor(glm::ivec3 color); - // Display void highlight(glm::ivec3 addition); + // The removal parameter decides what will be removed from the border color void removeHighlight(glm::ivec3 removal); void updateBorderColor(); void updateAim(); - protected: - // Web page communication void setIdInBrowser(const std::string& id); - glm::dvec2 _equatorialAim; - float _verticalFov{ 10.f }; - glm::ivec3 _borderColor; - + float _verticalFov = 10.f; + glm::ivec3 _borderColor = glm::ivec3(70); + glm::dvec2 _equatorialAim = glm::dvec2(0.0); + bool _hasLoadedImages = false; std::deque _selectedImages; - bool _hasLoadedImages{ false }; private: - bool _isSyncedWithWwt{ false }; - - bool _borderColorIsDirty{ false }; - bool _equatorialAimIsDirty{ false }; - void setWebpageBorderColor(glm::ivec3 color); void sendMessageToWwt(const ghoul::Dictionary& msg); - int messageCounter{ 0 }; - - ghoul::Dictionary moveCamera(const glm::dvec2& celestCoords, double fov, + // WorldWide Telescope messages + ghoul::Dictionary moveCameraMessage(const glm::dvec2& celestCoords, double fov, double roll, bool shouldMoveInstantly = true); - ghoul::Dictionary loadCollection(const std::string& url); - ghoul::Dictionary setForeground(const std::string& name); - ghoul::Dictionary addImage(const std::string& id, const std::string& url); - ghoul::Dictionary removeImage(const std::string& id); - ghoul::Dictionary setImageOpacity(const std::string& id, double opacity); - ghoul::Dictionary setForegroundOpacity(double val); - ghoul::Dictionary setLayerOrder(const std::string& id, int version); - ghoul::Dictionary hideChromeGui(bool isHidden); + ghoul::Dictionary loadCollectionMessage(const std::string& url); + ghoul::Dictionary setForegroundMessage(const std::string& name); + ghoul::Dictionary addImageMessage(const std::string& id, const std::string& url); + ghoul::Dictionary removeImageMessage(const std::string& id); + ghoul::Dictionary setImageOpacityMessage(const std::string& id, double opacity); + ghoul::Dictionary setLayerOrderMessage(const std::string& id, int version); + ghoul::Dictionary hideChromeGuiMessage(bool isHidden); // Requires a newer CEF version + + bool _isSyncedWithWwt = false; + bool _borderColorIsDirty = false; + bool _equatorialAimIsDirty = false; + int messageCounter{ 0 }; // Time variables // For capping the message passing to WWT - constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 }; + constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; std::chrono::system_clock::time_point _lastUpdateTime; - }; - } // namespace openspace #endif // __OPENSPACE_MODULE_SKYBROWSER___WWTCOMMUNICATOR___H__ diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index fb11d48dd4..eaf32819b8 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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_SKYBROWSER___WWTDATAHANDLER___H__ #define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ @@ -24,45 +48,41 @@ namespace openspace::wwt { const std::string ZoomLevel = "ZoomLevel"; const std::string DataSetType = "DataSetType"; const std::string Sky = "Sky"; -} // namespace openspace::wwt\ +} // namespace openspace::wwt namespace openspace { - struct ImageData { - std::string name{ wwt::Undefined }; - std::string thumbnailUrl{ wwt::Undefined }; - std::string imageUrl{ wwt::Undefined }; - std::string credits{ wwt::Undefined }; - std::string creditsUrl{ wwt::Undefined }; - std::string collection{ wwt::Undefined }; - bool hasCelestialCoords{ false }; - float fov{ 0.f }; - glm::dvec2 equatorialSpherical{ 0.0 }; - glm::dvec3 equatorialCartesian{ 0.0 }; - }; +struct ImageData { + std::string name{ wwt::Undefined }; + std::string thumbnailUrl{ wwt::Undefined }; + std::string imageUrl{ wwt::Undefined }; + std::string credits{ wwt::Undefined }; + std::string creditsUrl{ wwt::Undefined }; + std::string collection{ wwt::Undefined }; + bool hasCelestialCoords = false; + float fov = 0.f; + glm::dvec2 equatorialSpherical = glm::dvec2(0.0); + glm::dvec3 equatorialCartesian = glm::dvec3(0.0); +}; - class WwtDataHandler { - - public: - WwtDataHandler() = default; - ~WwtDataHandler(); +class WwtDataHandler { +public: + WwtDataHandler() = default; + ~WwtDataHandler(); - void loadImages(const std::string& root, const std::string& directory); - int nLoadedImages() const; - const ImageData& getImage(int i) const; + void loadImages(const std::string& root, const std::filesystem::path& directory); + int nLoadedImages() const; + const ImageData& getImage(int i) const; - private: - void saveImageFromNode(tinyxml2::XMLElement* node, std::string collection); - void saveImagesFromXml(tinyxml2::XMLElement* root, std::string collection); +private: + void saveImageFromNode(tinyxml2::XMLElement* node, std::string collection); + void saveImagesFromXml(tinyxml2::XMLElement* root, std::string collection); - // Images - std::vector _images; - std::vector _xmls; - - }; + // Images + std::vector _images; + std::vector _xmls; +}; } - - #endif // __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index d1b3a605a7..4d70cad072 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -1,65 +1,85 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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. * + ****************************************************************************************/ + +in vec2 vs_st; +in vec4 vs_position; + uniform float lineWidth; uniform vec2 dimensions; uniform bool showCrosshair; uniform bool showRectangle; uniform vec4 lineColor; -in vec2 vs_st; -in vec4 vs_position; - // A factor which states how much thicker vertical lines are rendered than horizontal // This compensates for the optical illusion that vertical lines appear thinner -#define VERTICAL_THICKNESS 1.15f +const float VerticalThickness = 1.15; -float createLine(in float lineCenter, in float lineWidth, in float coord) { +float createLine(float lineCenter, float lineWidth, float coord) { // Calculate edges of line - float start_edge = lineCenter - (lineWidth * 0.5f); - float end_edge = lineCenter + (lineWidth * 0.5f); + float startEdge = lineCenter - (lineWidth * 0.5); + float endEdge = lineCenter + (lineWidth * 0.5); - // Create line - float line = step(start_edge, coord) - step(end_edge, coord); - - return line; + return step(startEdge, coord) - step(endEdge, coord); } -float createRectangle(in float linewidth_y, in float ratio, in vec2 coord) { +float createRectangle(float linewidthY, float ratio, vec2 coord) { // Calculate the widths and centers for the lines - float linewidth_x = linewidth_y * ratio * VERTICAL_THICKNESS; - float linecenter_x = linewidth_x * 0.5f; - float linecenter_y = linewidth_y * 0.5f; + float linewidthX = linewidthY * ratio * VerticalThickness; + float linecenterX = linewidthX * 0.5; + float linecenterY = linewidthY * 0.5; // Create the four lines for the rectangle - float l = createLine(linecenter_x, linewidth_x, coord.x); - float r = createLine(1.0f - linecenter_x, linewidth_x, coord.x); - float b = createLine(linecenter_y, linewidth_y, coord.y); - float t = createLine(1.0f - linecenter_y, linewidth_y, coord.y); + float l = createLine(linecenterX, linewidthX, coord.x); + float r = createLine(1.0 - linecenterX, linewidthX, coord.x); + float b = createLine(linecenterY, linewidthY, coord.y); + float t = createLine(1.0 - linecenterY, linewidthY, coord.y); - // Add all lines together return l + r + b + t; } float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { - float center = 0.5f; - float crosshair_vertical = createLine(center, linewidth * ratio * VERTICAL_THICKNESS, coord.x); - float crosshair_horizontal = createLine(center, linewidth, coord.y); + const float Center = 0.5; + float crosshairVertical = createLine(Center, linewidth * ratio * VerticalThickness, coord.x); + float crosshairHorizontal = createLine(Center, linewidth, coord.y); - return crosshair_horizontal + crosshair_vertical; + return crosshairHorizontal + crosshairVertical; } #include "fragment.glsl" Fragment getFragment() { float ratio = dimensions.y / dimensions.x; - float crosshair = 0.0f; - float rectangle = 0.0f; + float crosshair = 0.0; + float rectangle = 0.0; - if(showCrosshair) { + if (showCrosshair) { crosshair = createCrosshair(lineWidth, ratio, vs_st); - float border = 1.0f - createRectangle(lineWidth * 5.0f, ratio, vs_st); + float border = 1.0 - createRectangle(lineWidth * 5.0, ratio, vs_st); crosshair *= border; } - if(showRectangle) { + if (showRectangle) { rectangle = createRectangle(lineWidth, ratio, vs_st); } diff --git a/modules/skybrowser/shaders/target_vs.glsl b/modules/skybrowser/shaders/target_vs.glsl index c1d2e7c618..9d91c1e636 100644 --- a/modules/skybrowser/shaders/target_vs.glsl +++ b/modules/skybrowser/shaders/target_vs.glsl @@ -1,14 +1,37 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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. * + ****************************************************************************************/ #version __CONTEXT__ +out vec2 vs_st; +out vec4 vs_position; + uniform mat4 modelTransform; uniform mat4 viewProj; layout(location = 0) in vec4 in_position; layout(location = 1) in vec2 in_st; -out vec2 vs_st; -out vec4 vs_position; - void main(){ vs_st = in_st; vs_position = viewProj * modelTransform * in_position; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index c4d2006b5c..5ed31a0836 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -22,7 +22,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - #include #include @@ -30,7 +29,6 @@ #include #include #include -#include "skybrowsermodule_lua.inl" #include #include #include @@ -39,9 +37,9 @@ #include #include +#include "skybrowsermodule_lua.inl" namespace { - constexpr const openspace::properties::Property::PropertyInfo AllowInteractionInfo = { "AllowMouseInteraction", @@ -69,11 +67,8 @@ namespace { #include "skybrowsermodule_codegen.cpp" } // namespace - namespace openspace { - scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { - scripting::LuaLibrary res; res.name = "skybrowser"; res.functions = { @@ -263,8 +258,6 @@ namespace openspace { return res; } - - SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _allowMouseInteraction(AllowInteractionInfo, true) @@ -276,7 +269,6 @@ SkyBrowserModule::SkyBrowserModule() // Set callback functions global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { - if (!_isCameraInSolarSystem || !_allowMouseInteraction) { return false; } @@ -304,7 +296,6 @@ SkyBrowserModule::SkyBrowserModule() if (global::windowDelegate->isMaster()) { global::callback::mousePosition->emplace_back( [&](double x, double y) { - if (!_isCameraInSolarSystem || !_allowMouseInteraction) { return false; } @@ -314,30 +305,25 @@ SkyBrowserModule::SkyBrowserModule() glm::vec2 translation = _mousePosition - _startMousePosition; switch (_interactionMode) { - case MouseInteraction::Hover: - setSelectedObject(); - - break; - - case MouseInteraction::Drag: - _mouseOnPair->translateSelected(_startDragPosition, translation); - break; - - case MouseInteraction::FineTune: - _mouseOnPair->fineTuneTarget(_startDragPosition, translation); - break; - - default: - setSelectedObject(); - break; - } + case MouseInteraction::Hover: + setSelectedObject(); + break; + case MouseInteraction::Drag: + _mouseOnPair->translateSelected(_startDragPosition, translation); + break; + case MouseInteraction::FineTune: + _mouseOnPair->fineTuneTarget(_startDragPosition, translation); + break; + default: + setSelectedObject(); + break; + } return false; } ); global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { - if (!_isCameraInSolarSystem || !_mouseOnPair || !_allowMouseInteraction) { return false; } @@ -351,7 +337,6 @@ SkyBrowserModule::SkyBrowserModule() } global::callback::preSync->emplace_back([this]() { - // Disable browser and targets when camera is outside of solar system bool camWasInSolarSystem = _isCameraInSolarSystem; glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); @@ -375,10 +360,13 @@ SkyBrowserModule::SkyBrowserModule() incrementallyFadeBrowserTargets(_goal, deltaTime); } if (_isCameraInSolarSystem) { - std::for_each(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + std::for_each( + _targetsBrowsers.begin(), + _targetsBrowsers.end(), [&](const std::unique_ptr& pair) { pair->synchronizeAim(); - }); + } + ); incrementallyAnimateTargets(deltaTime); } if (_isCameraRotating && _allowCameraRotation) { @@ -387,18 +375,12 @@ SkyBrowserModule::SkyBrowserModule() }); } -SkyBrowserModule::~SkyBrowserModule() { -} - -void SkyBrowserModule::internalDeinitialize() { -} - void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { - const Parameters p = codegen::bake(dict); // Register ScreenSpaceRenderable - auto fScreenSpaceRenderable = FactoryManager::ref().factory(); + ghoul::TemplateFactory* fScreenSpaceRenderable = + FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); // Register ScreenSpaceSkyTarget @@ -412,8 +394,7 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { _dataHandler = std::make_unique(); } -void SkyBrowserModule::setSelectedObject() -{ +void SkyBrowserModule::setSelectedObject() { if (_interactionMode != MouseInteraction::Hover) { return; } @@ -421,13 +402,15 @@ void SkyBrowserModule::setSelectedObject() TargetBrowserPair* previousPair = _mouseOnPair; // Find and save what mouse is currently hovering on - auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + auto it = std::find_if( + _targetsBrowsers.begin(), + _targetsBrowsers.end(), [&] (const std::unique_ptr &pair) { return pair->checkMouseIntersection(_mousePosition) && !pair->isUsingRadiusAzimuthElevation(); }); - if (it == std::end(_targetsBrowsers)) { + if (it == _targetsBrowsers.end()) { _mouseOnPair = nullptr; } else { @@ -436,7 +419,6 @@ void SkyBrowserModule::setSelectedObject() // Selection has changed if (previousPair != _mouseOnPair) { - // Remove highlight if (previousPair) { previousPair->removeHighlight(_highlightAddition); @@ -449,13 +431,12 @@ void SkyBrowserModule::setSelectedObject() } void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const std::string& browserId) { - ScreenSpaceSkyTarget* target = dynamic_cast( global::renderEngine->screenSpaceRenderable(targetId) - ); + ); ScreenSpaceSkyBrowser* browser = dynamic_cast( global::renderEngine->screenSpaceRenderable(browserId) - ); + ); // Ensure pair has both target and browser if (browser && target) { @@ -464,36 +445,35 @@ void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const s } void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) { - TargetBrowserPair* found = getPair(id); if (!found) { return; } - auto it = std::remove_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), + auto it = std::remove_if( + _targetsBrowsers.begin(), + _targetsBrowsers.end(), [&](const std::unique_ptr& pair) { return *found == *(pair.get()); - }); + } + ); - _targetsBrowsers.erase(it, std::end(_targetsBrowsers)); + _targetsBrowsers.erase(it, _targetsBrowsers.end()); _mouseOnPair = nullptr; } -void SkyBrowserModule::lookAtTarget(std::string id) -{ +void SkyBrowserModule::lookAtTarget(const std::string& id) { TargetBrowserPair* pair = getPair(id); if (pair) { startRotatingCamera(pair->targetDirectionGalactic()); } } -void SkyBrowserModule::setHoverCircle(ScreenSpaceImageLocal* circle) -{ +void SkyBrowserModule::setHoverCircle(ScreenSpaceImageLocal* circle) { _hoverCircle = circle; } -void SkyBrowserModule::moveHoverCircle(int i) -{ +void SkyBrowserModule::moveHoverCircle(int i) { const ImageData& image = _dataHandler->getImage(i); // Only move and show circle if the image has coordinates @@ -516,25 +496,22 @@ void SkyBrowserModule::moveHoverCircle(int i) } } -void SkyBrowserModule::disableHoverCircle() -{ +void SkyBrowserModule::disableHoverCircle() { if (_hoverCircle && _hoverCircle->isEnabled()) { _hoverCircle->setEnabled(false); } } -void SkyBrowserModule::loadImages(const std::string& root, const std::string& directory) -{ +void SkyBrowserModule::loadImages(const std::string& root, + const std::filesystem::path& directory) { _dataHandler->loadImages(root, directory); } -int SkyBrowserModule::nLoadedImages() -{ +int SkyBrowserModule::nLoadedImages() { return _dataHandler->nLoadedImages(); } -void SkyBrowserModule::handleMouseClick(const MouseButton& button) -{ +void SkyBrowserModule::handleMouseClick(const MouseButton& button) { setSelectedBrowser(_mouseOnPair->browserId()); if (button == MouseButton::Left) { @@ -561,28 +538,28 @@ void SkyBrowserModule::handleMouseClick(const MouseButton& button) } } -const std::unique_ptr& SkyBrowserModule::getWwtDataHandler() { +const std::unique_ptr& SkyBrowserModule::getWwtDataHandler() const { return _dataHandler; } -std::vector>& SkyBrowserModule::getPairs() -{ +std::vector>& SkyBrowserModule::getPairs() { return _targetsBrowsers; } -int SkyBrowserModule::nPairs() -{ +int SkyBrowserModule::nPairs() { return static_cast(_targetsBrowsers.size()); } -TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) -{ - auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers), +TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) { + auto it = std::find_if( + _targetsBrowsers.begin(), + _targetsBrowsers.end(), [&](const std::unique_ptr& pair) { bool foundBrowser = pair->browserId() == id; bool foundTarget = pair->targetId() == id; return foundBrowser || foundTarget; - }); + } + ); if (it == std::end(_targetsBrowsers)) { return nullptr; } @@ -623,16 +600,17 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { } } -void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float deltaTime) +void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, + float deltaTime) { float transparency = [](Transparency goal) { switch (goal) { - case Transparency::Transparent: - return 0.f; + case Transparency::Transparent: + return 0.f; - case Transparency::Opaque: - return 1.f; - } + case Transparency::Opaque: + return 1.f; + } }(goal); bool isAllFinished{ false }; @@ -655,8 +633,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float } } -void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) -{ +void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) { for (std::unique_ptr& pair : _targetsBrowsers) { if (pair->isEnabled()) { pair->incrementallyAnimateToCoordinate(deltaTime); @@ -665,59 +642,51 @@ void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) } void SkyBrowserModule::setSelectedBrowser(const std::string& id) { - if (getPair(id)) { + TargetBrowserPair* found = getPair(id); + if (found) { _selectedBrowser = id; } } -std::string SkyBrowserModule::selectedBrowserId() { +std::string SkyBrowserModule::selectedBrowserId() const { return _selectedBrowser; } -std::string SkyBrowserModule::selectedTargetId() -{ - if (getPair(_selectedBrowser)) { - return getPair(_selectedBrowser)->targetId(); +std::string SkyBrowserModule::selectedTargetId() { + TargetBrowserPair* found = getPair(_selectedBrowser); + if (found) { + return found->targetId(); } else { return ""; } } -glm::ivec3 SkyBrowserModule::highlight() -{ +glm::ivec3 SkyBrowserModule::highlight() const { return _highlightAddition; } -bool SkyBrowserModule::isCameraInSolarSystem() { +bool SkyBrowserModule::isCameraInSolarSystem() const { return _isCameraInSolarSystem; } -bool SkyBrowserModule::isSelectedPairUsingRae() -{ - if (getPair(_selectedBrowser)) { - return getPair(_selectedBrowser)->isUsingRadiusAzimuthElevation(); +bool SkyBrowserModule::isSelectedPairUsingRae() { + TargetBrowserPair* found = getPair(_selectedBrowser); + if (found) { + return found->isUsingRadiusAzimuthElevation(); } else { return false; } } -bool SkyBrowserModule::isSelectedPairFacingCamera() -{ - if (getPair(_selectedBrowser)) { - return getPair(_selectedBrowser)->isFacingCamera(); +bool SkyBrowserModule::isSelectedPairFacingCamera() { + TargetBrowserPair* found = getPair(_selectedBrowser); + if (found) { + return found->isFacingCamera(); } else { return false; } } - -//std::vector SkyBrowserModule::documentations() const { -// return { -// ExoplanetsDataPreparationTask::documentation(), -// RenderableOrbitDisc::Documentation() -// }; -//} - } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 874a81d779..6c81635737 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -25,8 +25,9 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ -#include #include + +#include #include #include #include @@ -53,40 +54,34 @@ enum class MouseInteraction { class SkyBrowserModule : public OpenSpaceModule { public: - constexpr static const char* Name = "SkyBrowser"; - constexpr static const double StopAnimationThreshold{ 0.0005 }; - constexpr static const double FadingTime = { 2.0 }; - constexpr static const double AnimationSpeed = { 1.0 }; + constexpr static const double StopAnimationThreshold = 0.0005; + constexpr static const double FadingTime = 2.0; + constexpr static const double AnimationSpeed = 1.0; const double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; - // Constructor & destructor SkyBrowserModule(); - virtual ~SkyBrowserModule(); - // Getters std::vector>& getPairs(); int nPairs(); TargetBrowserPair* getPair(const std::string& id); - const std::unique_ptr& getWwtDataHandler(); - std::string selectedBrowserId(); + const std::unique_ptr& getWwtDataHandler() const; + std::string selectedBrowserId() const; std::string selectedTargetId(); - glm::ivec3 highlight(); + glm::ivec3 highlight() const; - // Setters void setSelectedBrowser(const std::string& id); void setSelectedObject(); // Manage mouse interactions void setHoverCircle(ScreenSpaceImageLocal* circle); // Rotation, animation, placement - void lookAtTarget(std::string id); + void lookAtTarget(const std::string& id); void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate void incrementallyRotateCamera(double deltaTime); void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); void incrementallyAnimateTargets(double deltaTime); - // Boolean functions - bool isCameraInSolarSystem(); + bool isCameraInSolarSystem() const; bool isSelectedPairFacingCamera(); bool isSelectedPairUsingRae(); @@ -99,7 +94,7 @@ public: void disableHoverCircle(); // Image collection handling - void loadImages(const std::string& root, const std::string& directory); + void loadImages(const std::string& root, const std::filesystem::path& directory); int nLoadedImages(); // Mouse interaction @@ -110,21 +105,20 @@ public: protected: void internalInitialize(const ghoul::Dictionary& dict) override; - void internalDeinitialize() override; private: properties::BoolProperty _allowMouseInteraction; properties::BoolProperty _allowCameraRotation; - glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers + glm::ivec3 _highlightAddition = glm::ivec3(35); // Highlight object when mouse hovers // The browsers and targets std::vector> _targetsBrowsers; - TargetBrowserPair* _mouseOnPair{ nullptr }; - ScreenSpaceImageLocal* _hoverCircle{ nullptr }; - std::string _selectedBrowser{ "" }; // Currently selected browser + TargetBrowserPair* _mouseOnPair = nullptr; + ScreenSpaceImageLocal* _hoverCircle = nullptr; + std::string _selectedBrowser = ""; // Currently selected browser // Fading - Transparency _goal; + Transparency _goal = Transparency::Opaque; // Flags bool _isCameraInSolarSystem{ true }; // Visualization modes @@ -144,7 +138,6 @@ private: // Data handler for the image collections std::unique_ptr _dataHandler; }; - } // namespace openspace #endif // __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 45b04cdeb2..08e062ec9b 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -1,3 +1,26 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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 @@ -11,37 +34,36 @@ #include namespace { - constexpr const char _loggerCat[] = "SkyBrowserModule"; + constexpr const char _loggerCat[] = "SkyBrowserModule"; } // namespace namespace openspace::skybrowser::luascriptfunctions { int selectImage(lua_State* L) { - // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); - const int i = ghoul::lua::value(L, 1); + // Load image + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); + const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->isCameraInSolarSystem()) { TargetBrowserPair* selected = module->getPair(module->selectedBrowserId()); if (selected) { - const ImageData& image = module->getWwtDataHandler()->getImage(i); // Load image into browser LINFO("Loading image " + image.name); selected->selectImage(image, i); - bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); + bool isInView = isCoordinateInView(image.equatorialCartesian); // If the coordinate is not in view, rotate camera if (image.hasCelestialCoords && !isInView) { module->startRotatingCamera( - skybrowser::equatorialToGalactic(image.equatorialCartesian) + equatorialToGalactic(image.equatorialCartesian) ); } } } - return 0; + return 0; } int setHoverCircle(lua_State* L) { @@ -96,9 +118,8 @@ int unlockTarget(lua_State* L) { int setImageLayerOrder(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); - const std::string id = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 1); - int order = ghoul::lua::value(L, 1); + auto [id, i, order] = ghoul::lua::values(L); + SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { @@ -106,10 +127,10 @@ int setImageLayerOrder(lua_State* L) { } return 0; } - + int loadImagesToWWT(lua_State* L) { - // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT"); + // Load images from url + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT"); const std::string id = ghoul::lua::value(L, 1); LINFO("Connection established to WorldWide Telescope application in " + id); LINFO("Loading image collections to " + id); @@ -122,11 +143,11 @@ int loadImagesToWWT(lua_State* L) { SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { - //module->getPair(id)->hideChromeInterface(true); + module->getPair(id)->hideChromeInterface(true); module->getPair(id)->loadImageCollection(root); } - return 0; + return 0; } int startSetup(lua_State* L) { @@ -140,12 +161,15 @@ int startSetup(lua_State* L) { for (std::unique_ptr& pair : pairs) { std::string id = pair->browserId(); glm::ivec3 color = pair->borderColor(); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.setBorderColor('" + id + "'," + - std::to_string(color.r) + "," + - std::to_string(color.g) + "," + - std::to_string(color.b) + "" + - ");", + std::string script = fmt::format( + "openspace.skybrowser.setBorderColor('{}', {}, {}, {})", + id, + color.r, + color.g, + color.b + ); + global::scriptEngine->queueScript( + script, scripting::ScriptEngine::RemoteScripting::Yes ); } @@ -153,7 +177,7 @@ int startSetup(lua_State* L) { // To ensure each node in a cluster calls its own instance of the wwt application // Do not send this script to the other nodes - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.skybrowser.sendOutIdsToBrowsers();", scripting::ScriptEngine::RemoteScripting::No ); @@ -165,7 +189,7 @@ int sendOutIdsToBrowsers(lua_State* L) { // This is called when the sky_browser website is connected to OpenSpace ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers"); - // Send out ID's to the browsers + // Send out identifiers to the browsers SkyBrowserModule* module = global::moduleEngine->module(); std::vector>& pairs = module->getPairs(); for (std::unique_ptr& pair : pairs) { @@ -182,9 +206,10 @@ int initializeBrowser(lua_State* L) { LINFO("Initializing sky browser " + id); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->setIsSyncedWithWwt(true); - module->getPair(id)->initialize(); + TargetBrowserPair* found = module->getPair(id); + if (found) { + found->setIsSyncedWithWwt(true); + found->initialize(); } return 0; @@ -192,12 +217,11 @@ int initializeBrowser(lua_State* L) { int addPairToSkyBrowserModule(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); - const std::string targetId = ghoul::lua::value(L, 1); - const std::string browserId = ghoul::lua::value(L, 1); + auto [targetId, browserId] = ghoul::lua::values(L); SkyBrowserModule* module = global::moduleEngine->module(); - LINFO("Add browser " + browserId + " to sky browser module."); - LINFO("Add target " + targetId + " to sky browser module."); + LINFO("Add browser " + browserId + " to sky browser module"); + LINFO("Add target " + targetId + " to sky browser module"); module->addTargetBrowserPair(targetId, browserId); @@ -205,30 +229,26 @@ int addPairToSkyBrowserModule(lua_State* L) { } int getListOfImages(lua_State* L) { - // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); - SkyBrowserModule* module = global::moduleEngine->module(); + // Send image list to GUI + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); + SkyBrowserModule* module = global::moduleEngine->module(); - // If no data has been loaded yet, download the data from the web! + // If no data has been loaded yet, download the data from the web! - if (module->nLoadedImages() == 0) { + if (module->nLoadedImages() == 0) { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" "wwt-web-client/master/assets/webclient-explore-root.wtml"; - std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/").string(); + std::filesystem::path directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); module->loadImages(root, directory); - } - + } + // Create Lua table to send to the GUI lua_newtable(L); - for (int i = 0; i < module->nLoadedImages(); i++) { + for (int i = 0; i < module->nLoadedImages(); i++) { const ImageData& img = module->getWwtDataHandler()->getImage(i); - glm::dvec3 coords = img.equatorialCartesian; - - // Conversions for ghoul - std::vector cartCoordsVec = { coords.x, coords.y, coords.z }; // Index for current ImageData ghoul::lua::push(L, i + 1); @@ -242,7 +262,7 @@ int getListOfImages(lua_State* L) { lua_settable(L, -3); ghoul::lua::push(L, "dec", img.equatorialSpherical.y); lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); + ghoul::lua::push(L, "cartesianDirection", img.equatorialCartesian); lua_settable(L, -3); ghoul::lua::push(L, "hasCelestialCoords", img.hasCelestialCoords); lua_settable(L, -3); @@ -255,9 +275,9 @@ int getListOfImages(lua_State* L) { // Set table for the current ImageData lua_settable(L, -3); - } + } - return 1; + return 1; } int getTargetData(lua_State* L) { @@ -273,20 +293,14 @@ int getTargetData(lua_State* L) { lua_newtable(L); glm::dvec3 cartesianCam = skybrowser::cameraDirectionEquatorial(); glm::dvec2 sphericalCam = skybrowser::cartesianToSpherical(cartesianCam); - // Convert to vector so ghoul can read it - std::vector viewDirCelestVec = { - cartesianCam.x, - cartesianCam.y, - cartesianCam.z - }; - + // Calculate the smallest FOV of vertical and horizontal glm::dvec2 fovs = skybrowser::fovWindow(); double FOV = std::min(fovs.x, fovs.y); // Push window data ghoul::lua::push(L, "windowHFOV", FOV); lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); + ghoul::lua::push(L, "cartesianDirection", cartesianCam); lua_settable(L, -3); ghoul::lua::push(L, "ra", sphericalCam.x); lua_settable(L, -3); @@ -314,26 +328,16 @@ int getTargetData(lua_State* L) { // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; const std::deque selectedImages = pair->getSelectedImages(); - std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) { - selectedImagesVector.push_back(i); - }); + std::for_each( + selectedImages.begin(), + selectedImages.end(), + [&](int i) { + selectedImagesVector.push_back(i); + } + ); glm::dvec2 spherical = pair->targetDirectionEquatorial(); glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical); - - - std::vector cartesianVec = { - cartesian.x, - cartesian.y, - cartesian.z - }; - // Convert color to vector so ghoul can read it - glm::ivec3 color = pair->borderColor(); - std::vector colorVec = { color.r, color.g, color.b }; - - // Convert color to vector so ghoul can read it - glm::vec2 size = pair->size(); - std::vector sizeVec = { size.x, size.y }; ghoul::lua::push(L, id); lua_newtable(L); @@ -346,49 +350,47 @@ int getTargetData(lua_State* L) { lua_settable(L, -3); ghoul::lua::push(L, "selectedImages", selectedImagesVector); lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", cartesianVec); + ghoul::lua::push(L, "cartesianDirection", cartesian); lua_settable(L, -3); ghoul::lua::push(L, "ra", spherical.x); lua_settable(L, -3); ghoul::lua::push(L, "dec", spherical.y); lua_settable(L, -3); - ghoul::lua::push(L, "color", colorVec); + ghoul::lua::push(L, "color", pair->borderColor()); lua_settable(L, -3); ghoul::lua::push(L, "isLocked", pair->isLocked()); lua_settable(L, -3); - ghoul::lua::push(L, "size", sizeVec); + ghoul::lua::push(L, "size", pair->size()); lua_settable(L, -3); // Set table for the current target lua_settable(L, -3); - } } return 1; } + int adjustCamera(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const std::string id = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); - if(module->isCameraInSolarSystem()) { + if (module->isCameraInSolarSystem()) { module->lookAtTarget(id); } - return 0; + return 0; } int setOpacityOfImageLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); - const std::string id = ghoul::lua::value(L, 1); - const int i = ghoul::lua::value(L, 1); - double opacity = ghoul::lua::value(L, 1); + auto [id, i, opacity] = ghoul::lua::values(L); SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->setImageOpacity(i, opacity); - + TargetBrowserPair* found = module->getPair(id); + if (found) { + found->setImageOpacity(i, opacity); } return 0; @@ -444,23 +446,23 @@ int createTargetBrowserPair(lua_State* L) { "FaceCamera = false," "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + browser + ");", scripting::ScriptEngine::RemoteScripting::No ); - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + target + ");", scripting::ScriptEngine::RemoteScripting::No ); - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::No ); - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::No ); @@ -476,45 +478,42 @@ int removeTargetBrowserPair(lua_State* L) { if (found) { std::string browser = found->browserId(); std::string target = found->targetId(); - found = nullptr; module->removeTargetBrowserPair(id); // Remove from engine - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.removeScreenSpaceRenderable('" + browser + "');", scripting::ScriptEngine::RemoteScripting::Yes ); - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.removeScreenSpaceRenderable('" + target + "');", scripting::ScriptEngine::RemoteScripting::Yes ); } - return 0; } int translateScreenSpaceRenderable(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 5, "lua::translateScreenSpaceRenderable"); - const std::string id = ghoul::lua::value(L, 1); - float startX = ghoul::lua::value(L, 1); - float startY = ghoul::lua::value(L, 1); - float transX = ghoul::lua::value(L, 1); - float transY = ghoul::lua::value(L, 1); + auto [id, startX, startY, transX, transY] = + ghoul::lua::values(L); ScreenSpaceRenderable* renderable = global::renderEngine->screenSpaceRenderable(id); - renderable->translate(glm::vec2(transX, transY), glm::vec2(startX, startY)); + + if (renderable) { + renderable->translate(glm::vec2(transX, transY), glm::vec2(startX, startY)); + } return 0; } int removeSelectedImageInBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); - const std::string id = ghoul::lua::value(L, 1); - // Image index - const int i = ghoul::lua::value(L, 1); + auto [id, i] = ghoul::lua::values(L); + // Get browser SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& image = module->getWwtDataHandler()->getImage(i); @@ -529,10 +528,7 @@ int removeSelectedImageInBrowser(lua_State* L) { int setEquatorialAim(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setEquatorialAim"); - // Browser id - const std::string id = ghoul::lua::value(L, 1); - double ra = ghoul::lua::value(L, 1); - double dec = ghoul::lua::value(L, 1); + auto [id, ra, dec] = ghoul::lua::values(L); // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -547,9 +543,7 @@ int setEquatorialAim(lua_State* L) { int setVerticalFov(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setVerticalFov"); - // Browser id - const std::string id = ghoul::lua::value(L, 1); - float vfov = ghoul::lua::value(L, 1); + auto [id, vfov] = ghoul::lua::values(L); // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -564,11 +558,8 @@ int setVerticalFov(lua_State* L) { int setBorderColor(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::setBorderColor"); - // Browser id - const std::string id = ghoul::lua::value(L, 1); - int r = ghoul::lua::value(L, 1); - int g = ghoul::lua::value(L, 1); - int b = ghoul::lua::value(L, 1); + auto [id, r, g, b] = ghoul::lua::values(L); + glm::ivec3 color{ r, g, b }; // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -583,10 +574,7 @@ int setBorderColor(lua_State* L) { int setScreenSpaceSize(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setScreenSpaceSize"); - // Browser id - const std::string id = ghoul::lua::value(L, 1); - float sizeX = ghoul::lua::value(L, 1); - float sizeY = ghoul::lua::value(L, 1); + auto [id, sizeX, sizeY] = ghoul::lua::values(L); // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -597,6 +585,5 @@ int setScreenSpaceSize(lua_State* L) { } return 0; } - -} +} // namespace openspace::skybrowser::luafunctions diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index 88c51f7c0f..e35c31ab0d 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -32,7 +32,6 @@ #include #include #include -#include namespace { constexpr const char* _loggerCat = "Browser"; @@ -42,6 +41,7 @@ namespace { "Browser Dimensions", "Set the dimensions of the web browser window." }; + const openspace::properties::Property::PropertyInfo UrlInfo = { "Url", "URL", @@ -54,158 +54,166 @@ namespace { "Reload the web browser" }; + struct [[codegen::Dictionary(Browser)]] Parameters { + // [[codegen::verbatim(DimensionsInfo.description)]] + std::optional dimensions; + + // [[codegen::verbatim(UrlInfo.description)]] + std::optional url; + + // [[codegen::verbatim(ReloadInfo.description)]] + std::optional reload; + }; + +#include "browser_codegen.cpp" + } // namespace namespace openspace { - void Browser::RenderHandler::draw() {} +void Browser::RenderHandler::draw() {} - void Browser::RenderHandler::render() {} +void Browser::RenderHandler::render() {} - void Browser::RenderHandler::setTexture(GLuint t) { - _texture = t; +void Browser::RenderHandler::setTexture(GLuint t) { + _texture = t; +} + +Browser::Browser(const ghoul::Dictionary& dictionary) + : _url(UrlInfo) + , _browserPixeldimensions(DimensionsInfo, glm::vec2(500.f), glm::vec2(10.f), glm::vec2(3000.f)) + , _reload(ReloadInfo) +{ + if (dictionary.hasValue(UrlInfo.identifier)) { + _url = dictionary.value(UrlInfo.identifier); } + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _url = p.url.value_or(_url); + _browserPixeldimensions = p.dimensions.value_or(_browserPixeldimensions); + glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); + _browserPixeldimensions = windowDimensions; - Browser::Browser(const ghoul::Dictionary& dictionary) - : _url(UrlInfo) - , _browserPixeldimensions(DimensionsInfo, glm::vec2(500.f), glm::vec2(10.f), glm::vec2(3000.f)) - , _reload(ReloadInfo) - { - if (dictionary.hasValue(UrlInfo.identifier)) { - _url = dictionary.value(UrlInfo.identifier); - } + _url.onChange([this]() { _isUrlDirty = true; }); + _browserPixeldimensions.onChange([this]() { _isDimensionsDirty = true; }); + _reload.onChange([this]() { _shouldReload = true; }); - glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize(); - _browserPixeldimensions = windowDimensions; + // Create browser and render handler + _renderHandler = new RenderHandler(); + _keyboardHandler = new WebKeyboardHandler(); + _browserInstance = std::make_unique( + _renderHandler, + _keyboardHandler + ); - _url.onChange([this]() { _isUrlDirty = true; }); - _browserPixeldimensions.onChange([this]() { _isDimensionsDirty = true; }); - _reload.onChange([this]() { _shouldReload = true; }); + WebBrowserModule* webBrowser = global::moduleEngine->module(); + if (webBrowser) { + webBrowser->addBrowser(_browserInstance.get()); + } +} - // Create browser and render handler - _renderHandler = new RenderHandler(); - _keyboardHandler = new WebKeyboardHandler(); - _browserInstance = std::make_unique( - _renderHandler, - _keyboardHandler - ); +Browser::~Browser() {} - WebBrowserModule* webBrowser = global::moduleEngine->module(); - if (webBrowser) { - webBrowser->addBrowser(_browserInstance.get()); - } - } - - Browser::~Browser() { - - } - - bool Browser::initializeGL() { - _texture = std::make_unique( - glm::uvec3(glm::ivec2(_browserPixeldimensions.value()), 1), - GL_TEXTURE_2D - ); +bool Browser::initializeGL() { + _texture = std::make_unique( + glm::uvec3(glm::ivec2(_browserPixeldimensions.value()), 1), + GL_TEXTURE_2D + ); - _renderHandler->setTexture(*_texture); + _renderHandler->setTexture(*_texture); - _browserInstance->initialize(); + _browserInstance->initialize(); + _browserInstance->loadUrl(_url); + return isReady(); +} + +bool Browser::deinitializeGL() { + _renderHandler->setTexture(0); + + _texture = nullptr; + + LDEBUG(fmt::format("Deinitializing browser: {}", _url.value())); + + _browserInstance->close(true); + + WebBrowserModule* webBrowser = global::moduleEngine->module(); + if (webBrowser) { + webBrowser->removeBrowser(_browserInstance.get()); + _browserInstance.reset(); + } + else { + LWARNING("Could not find WebBrowserModule"); + } + + return true; +} + +void Browser::render() { + if (!_renderHandler->isTextureReady()) { + return; + } + _renderHandler->updateTexture(); +} + +void Browser::update() { + if (_isUrlDirty) { _browserInstance->loadUrl(_url); - return isReady(); + _isUrlDirty = false; } - - - bool Browser::deinitializeGL() { - _renderHandler->setTexture(0); - - _texture = nullptr; - - std::string urlString; - _url.getStringValue(urlString); - LDEBUG(fmt::format("Deinitializing browser: {}", urlString)); - - _browserInstance->close(true); - - WebBrowserModule* webBrowser = global::moduleEngine->module(); - if (webBrowser) { - webBrowser->removeBrowser(_browserInstance.get()); - _browserInstance.reset(); - } - else { - LWARNING("Could not find WebBrowserModule"); - } - - return true; - } - - void Browser::render() { - if (!_renderHandler->isTextureReady()) { - return; - } - _renderHandler->updateTexture(); - - } - - void Browser::update() { - - if (_isUrlDirty) { - _browserInstance->loadUrl(_url); - _isUrlDirty = false; - } - if (_isDimensionsDirty) { - if (_browserPixeldimensions.value().x > 0 && - _browserPixeldimensions.value().y > 0) { - _browserInstance->reshape(_browserPixeldimensions.value()); - _isDimensionsDirty = false; - } - } - - if (_shouldReload) { - _browserInstance->reloadBrowser(); - _shouldReload = false; - } - } - - bool Browser::isReady() const { - return _texture.get(); - } - - glm::vec2 Browser::browserPixelDimensions() const { - return _browserPixeldimensions.value(); - } - - // Updates the browser size to match the size of the texture - void Browser::updateBrowserSize() { - _browserPixeldimensions = _texture->dimensions(); - } - - float Browser::browserRatio() const - { - return static_cast(_texture->dimensions().x) / - static_cast(_texture->dimensions().y); - } - - void Browser::setCallbackDimensions( - const std::function& function) - { - _browserPixeldimensions.onChange([&]() { - function(_browserPixeldimensions.value()); - }); - } - - void Browser::executeJavascript(const std::string& script) const { - - // Make sure that the browser has a main frame - const bool browserExists = _browserInstance && _browserInstance->getBrowser(); - const bool frameIsLoaded = browserExists && - _browserInstance->getBrowser()->GetMainFrame(); - - if (frameIsLoaded) { - _browserInstance->getBrowser()->GetMainFrame()->ExecuteJavaScript( - script, - _browserInstance->getBrowser()->GetMainFrame()->GetURL(), - 0 - ); + if (_isDimensionsDirty) { + if (_browserPixeldimensions.value().x > 0 && + _browserPixeldimensions.value().y > 0) + { + _browserInstance->reshape(_browserPixeldimensions.value()); + _isDimensionsDirty = false; } } + + if (_shouldReload) { + _browserInstance->reloadBrowser(); + _shouldReload = false; + } +} + +bool Browser::isReady() const { + return _texture.get(); +} + +glm::vec2 Browser::browserPixelDimensions() const { + return _browserPixeldimensions.value(); +} + +// Updates the browser size to match the size of the texture +void Browser::updateBrowserSize() { + _browserPixeldimensions = _texture->dimensions(); +} + +float Browser::browserRatio() const { + return static_cast(_texture->dimensions().x) / + static_cast(_texture->dimensions().y); +} + +void Browser::setCallbackDimensions( + const std::function& function) +{ + _browserPixeldimensions.onChange([&]() { + function(_browserPixeldimensions.value()); + }); +} + +void Browser::executeJavascript(const std::string& script) const { + // Make sure that the browser has a main frame + const bool browserExists = _browserInstance && _browserInstance->getBrowser(); + const bool frameIsLoaded = browserExists && + _browserInstance->getBrowser()->GetMainFrame(); + + if (frameIsLoaded) { + _browserInstance->getBrowser()->GetMainFrame()->ExecuteJavaScript( + script, + _browserInstance->getBrowser()->GetMainFrame()->GetURL(), + 0 + ); + } +} } // namespace openspace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 5b7d52a441..fb9b142015 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -1,3 +1,26 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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 @@ -7,14 +30,12 @@ #include #include #include -#include // formatJson +#include #include #include -#include // For hsv color -#include // For random color +#include +#include -#include -#pragma optimize("", off) namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; @@ -34,7 +55,6 @@ namespace { }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - // [[codegen::verbatim(AnimationSpeedInfo.description)]] std::optional animationSpeed; @@ -42,7 +62,7 @@ namespace { std::optional textureQuality; }; -#include "ScreenSpaceSkyBrowser_codegen.cpp" +#include "screenspaceskybrowser_codegen.cpp" } // namespace glm::ivec3 randomBorderColor(glm::ivec3 highlight) { @@ -67,209 +87,190 @@ glm::ivec3 randomBorderColor(glm::ivec3 highlight) { namespace openspace { - ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) - : ScreenSpaceRenderable(dictionary) - , WwtCommunicator(dictionary) - , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) - , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) - { - // Set a unique identifier - std::string identifier; - if (dictionary.hasValue(KeyIdentifier)) { - identifier = dictionary.value(KeyIdentifier); - } - else { - identifier = "ScreenSpaceSkyBrowser"; - } - identifier = makeUniqueIdentifier(identifier); - setIdentifier(identifier); +ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) + : ScreenSpaceRenderable(dictionary) + , WwtCommunicator(dictionary) + , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) + , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) +{ + _identifier = makeUniqueIdentifier(_identifier); - // Handle target dimension property - const Parameters p = codegen::bake(dictionary); - _textureQuality = p.textureQuality.value_or(_textureQuality); - _animationSpeed = p.animationSpeed.value_or(_animationSpeed); + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _textureQuality = p.textureQuality.value_or(_textureQuality); + _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - addProperty(_url); - addProperty(_browserPixeldimensions); - addProperty(_reload); - addProperty(_textureQuality); + addProperty(_url); + addProperty(_browserPixeldimensions); + addProperty(_reload); + addProperty(_textureQuality); - _textureQuality.onChange([this]() { - _textureDimensionsIsDirty = true; - }); + _textureQuality.onChange([this]() { + _textureDimensionsIsDirty = true; + }); - // Ensure that the browser is placed at the z-coordinate of the screen space plane - glm::vec2 screenPosition = _cartesianPosition.value(); - _cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ)); + // Ensure that the browser is placed at the z-coordinate of the screen space plane + glm::vec2 screenPosition = _cartesianPosition.value(); + _cartesianPosition = glm::vec3(screenPosition, skybrowser::ScreenSpaceZ); - if (global::windowDelegate->isMaster()) { - SkyBrowserModule* module = global::moduleEngine->module(); - _borderColor = randomBorderColor(module->highlight()); - - } - } - - ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { + if (global::windowDelegate->isMaster()) { SkyBrowserModule* module = global::moduleEngine->module(); + _borderColor = randomBorderColor(module->highlight()); + } +} - if (module && module->getPair(identifier())) { - module->removeTargetBrowserPair(identifier()); - } - } +ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { + SkyBrowserModule* module = global::moduleEngine->module(); - bool ScreenSpaceSkyBrowser::initializeGL() { - - WwtCommunicator::initializeGL(); - ScreenSpaceRenderable::initializeGL(); - updateTextureResolution(); - return true; - } - - glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) { - // Fine tuning of target - glm::dvec2 wwtFov = fieldsOfView(); - glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); - - glm::dvec2 browserDim = screenSpaceDimensions(); - glm::dvec2 angleResult = wwtFov * (drag / browserDim); - glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; - - // Convert to screen space coordinate system - glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; - glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; - return result; - } - - void ScreenSpaceSkyBrowser::setIdInBrowser() { - WwtCommunicator::setIdInBrowser(identifier()); - } - - void ScreenSpaceSkyBrowser::updateTextureResolution() - { - // Scale texture depending on the height of the window - // Set texture size to the actual pixel size it covers - glm::vec2 pixels = glm::vec2(global::windowDelegate->currentSubwindowSize()); - - // If the scale is 1, it covers half the window. Hence multiplication with 2 - float newResY = pixels.y * 2.f * _scale; - float ratio = _size.x / _size.y; - float newResX = newResY * ratio; - glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value(); - - _browserPixeldimensions = glm::ivec2(newSize); - _texture->setDimensions(glm::ivec3(newSize, 1)); - _objectSize = glm::ivec3(_texture->dimensions()); - } - - bool ScreenSpaceSkyBrowser::deinitializeGL() { - ScreenSpaceRenderable::deinitializeGL(); - WwtCommunicator::deinitializeGL(); - - return true; - } - - bool ScreenSpaceSkyBrowser::isAnimated() - { - return _isFovAnimated; - } - - void ScreenSpaceSkyBrowser::startFovAnimation(float fov) - { - _isFovAnimated = true; - _endVfov = fov; - } - - void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) - { - // If distance too large, keep animating. Else, stop animation - float diff = _endVfov - verticalFov(); - bool shouldAnimate = abs(diff) > FovThreshold; - - if (shouldAnimate) { - float delta = _animationSpeed * (diff * deltaTime); - _verticalFov = std::clamp(_verticalFov + delta, 0.0001f, 70.0f); - } - else { - _isFovAnimated = false; - } - } - - void ScreenSpaceSkyBrowser::render() { - WwtCommunicator::render(); - - draw( - globalRotationMatrix() * - translationMatrix() * - localRotationMatrix() * - scaleMatrix() - ); - } - - void ScreenSpaceSkyBrowser::update() { - // Texture of window is 1x1 when minimized - bool isWindow = global::windowDelegate->currentSubwindowSize() != glm::ivec2(1); - bool isWindowResized = global::windowDelegate->windowHasResized(); - if ((isWindowResized && isWindow) || _textureDimensionsIsDirty) { - updateTextureResolution(); - _textureDimensionsIsDirty = false; - } - if (_sizeIsDirty) { - updateScreenSpaceSize(); - _sizeIsDirty = false; - } - - WwtCommunicator::update(); - ScreenSpaceRenderable::update(); - } - - void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { - // Make scroll more sensitive the smaller the FOV - float x = _verticalFov; - float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999; - float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; - _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); - } - - void ScreenSpaceSkyBrowser::bindTexture() - { - _texture->bind(); - } - - glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { - // To ensure the plane has the right ratio - // The _scale tells us how much of the windows height the - // browser covers: e.g. a browser that covers 0.25 of the - // height of the window will have scale = 0.25 - - glm::mat4 scale = glm::scale( - glm::mat4(1.f), - glm::vec3(browserRatio() * _scale, _scale, 1.f) - ); - return scale; - } - - void ScreenSpaceSkyBrowser::setOpacity(float opacity) - { - _opacity = opacity; - } - - void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) - { - _size = newSize; - _sizeIsDirty = true; - } - - void ScreenSpaceSkyBrowser::updateScreenSpaceSize() - { - _scale = abs(_size.y) * 0.5f; - updateTextureResolution(); - } - - float ScreenSpaceSkyBrowser::opacity() const { - return _opacity; - } - glm::vec2 ScreenSpaceSkyBrowser::size() const - { - return _size; + if (module && module->getPair(identifier())) { + module->removeTargetBrowserPair(identifier()); } } + +bool ScreenSpaceSkyBrowser::initializeGL() { + WwtCommunicator::initializeGL(); + ScreenSpaceRenderable::initializeGL(); + updateTextureResolution(); + return true; +} + +glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) { + // Fine tuning of target + glm::dvec2 wwtFov = fieldsOfView(); + glm::dvec2 openSpaceFOV = skybrowser::fovWindow(); + + glm::dvec2 browserDim = screenSpaceDimensions(); + glm::dvec2 angleResult = wwtFov * (drag / browserDim); + glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; + + // Convert to screen space coordinate system + glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; + glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; + return result; +} + +void ScreenSpaceSkyBrowser::setIdInBrowser() { + WwtCommunicator::setIdInBrowser(identifier()); +} + +void ScreenSpaceSkyBrowser::updateTextureResolution() { + // Scale texture depending on the height of the window + // Set texture size to the actual pixel size it covers + glm::vec2 pixels = glm::vec2(global::windowDelegate->currentSubwindowSize()); + + // If the scale is 1, it covers half the window. Hence multiplication with 2 + float newResY = pixels.y * 2.f * _scale; + float ratio = _size.x / _size.y; + float newResX = newResY * ratio; + glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value(); + + _browserPixeldimensions = glm::ivec2(newSize); + _texture->setDimensions(glm::ivec3(newSize, 1)); + _objectSize = glm::ivec3(_texture->dimensions()); +} + +bool ScreenSpaceSkyBrowser::deinitializeGL() { + ScreenSpaceRenderable::deinitializeGL(); + WwtCommunicator::deinitializeGL(); + + return true; +} + +bool ScreenSpaceSkyBrowser::isAnimated() const{ + return _isFovAnimated; +} + +void ScreenSpaceSkyBrowser::startFovAnimation(float fov) { + _isFovAnimated = true; + _endVfov = fov; +} + +void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { + // If distance too large, keep animating. Else, stop animation + float diff = _endVfov - verticalFov(); + bool shouldAnimate = abs(diff) > FovThreshold; + + if (shouldAnimate) { + float delta = _animationSpeed * (diff * deltaTime); + _verticalFov = std::clamp(_verticalFov + delta, 0.0001f, 70.0f); + } + else { + _isFovAnimated = false; + } +} + +void ScreenSpaceSkyBrowser::render() { + WwtCommunicator::render(); + + draw( + globalRotationMatrix() * + translationMatrix() * + localRotationMatrix() * + scaleMatrix() + ); +} + +void ScreenSpaceSkyBrowser::update() { + // Texture of window is 1x1 when minimized + bool isWindow = global::windowDelegate->currentSubwindowSize() != glm::ivec2(1); + bool isWindowResized = global::windowDelegate->windowHasResized(); + if ((isWindowResized && isWindow) || _textureDimensionsIsDirty) { + updateTextureResolution(); + _textureDimensionsIsDirty = false; + } + if (_sizeIsDirty) { + updateScreenSpaceSize(); + _sizeIsDirty = false; + } + + WwtCommunicator::update(); + ScreenSpaceRenderable::update(); +} + +void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { + // Make scroll more sensitive the smaller the FOV + float x = _verticalFov; + float zoomFactor = atan(x / 50.f) + exp(x / 40.f) - 0.999999f; + float zoom = scroll > 0.f ? -zoomFactor : zoomFactor; + _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); +} + +void ScreenSpaceSkyBrowser::bindTexture() { + _texture->bind(); +} + +glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() { + // To ensure the plane has the right ratio + // The _scale tells us how much of the windows height the + // browser covers: e.g. a browser that covers 0.25 of the + // height of the window will have scale = 0.25 + + glm::mat4 scale = glm::scale( + glm::mat4(1.f), + glm::vec3(browserRatio() * _scale, _scale, 1.f) + ); + return scale; +} + +void ScreenSpaceSkyBrowser::setOpacity(float opacity) { + _opacity = opacity; +} + +void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) { + _size = newSize; + _sizeIsDirty = true; +} + +void ScreenSpaceSkyBrowser::updateScreenSpaceSize() { + _scale = abs(_size.y) * 0.5f; + updateTextureResolution(); +} + +float ScreenSpaceSkyBrowser::opacity() const { + return _opacity; +} + +glm::vec2 ScreenSpaceSkyBrowser::size() const { + return _size; +} +} // namespace openspace diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 523449fe21..a07ea8bd6a 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -1,3 +1,26 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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 @@ -61,7 +84,6 @@ namespace { }; struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { - // [[codegen::verbatim(CrosshairThresholdInfo.description)]] std::optional crosshairThreshold; @@ -76,7 +98,6 @@ namespace { // [[codegen::verbatim(LineWidthInfo.description)]] std::optional lineWidth; - }; #include "screenspaceskytarget_codegen.cpp" @@ -118,10 +139,11 @@ namespace openspace { setIdentifier(identifier); // Set the position to screen space z - glm::dvec3 startPos{ _cartesianPosition.value().x, _cartesianPosition.value().y, - skybrowser::ScreenSpaceZ }; - - _cartesianPosition.setValue(startPos); + _cartesianPosition = glm::dvec3( + _cartesianPosition.value().x, + _cartesianPosition.value().y, + skybrowser::ScreenSpaceZ + ); } @@ -134,16 +156,13 @@ namespace openspace { } // Pure virtual in the screen space renderable class and hence must be defined - void ScreenSpaceSkyTarget::bindTexture() { - - } + void ScreenSpaceSkyTarget::bindTexture() {} bool ScreenSpaceSkyTarget::isReady() const { return _shader != nullptr; } bool ScreenSpaceSkyTarget::initializeGL() { - glGenVertexArrays(1, &_vertexArray); glGenBuffers(1, &_vertexBuffer); createShaders(); @@ -151,8 +170,7 @@ namespace openspace { return isReady(); } - bool ScreenSpaceSkyTarget::deinitializeGL() - { + bool ScreenSpaceSkyTarget::deinitializeGL() { return ScreenSpaceRenderable::deinitializeGL(); } @@ -173,7 +191,6 @@ namespace openspace { void ScreenSpaceSkyTarget::createShaders() { - _shader = global::renderEngine->buildRenderProgram( "ScreenSpaceProgram", absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), @@ -185,7 +202,7 @@ namespace openspace { } void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) { - _borderColor = color; + _borderColor = std::move(color); } glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { @@ -193,7 +210,6 @@ namespace openspace { } void ScreenSpaceSkyTarget::render() { - bool showCrosshair = _verticalFov < _showCrosshairThreshold; bool showRectangle = _verticalFov > _showRectangleThreshold; @@ -224,8 +240,7 @@ namespace openspace { _shader->deactivate(); } - void ScreenSpaceSkyTarget::update() - { + void ScreenSpaceSkyTarget::update() { if (_isLocked) { glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera( _lockedCoordinates @@ -252,11 +267,9 @@ namespace openspace { } glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { - glm::vec3 localCamera = _cartesianPosition.value(); if (_useRadiusAzimuthElevation) { - localCamera = raeToCartesian(_raePosition.value()); } @@ -281,8 +294,7 @@ namespace openspace { _scale = std::max(heightRatio, smallestHeightRatio); } - void ScreenSpaceSkyTarget::setFovFromScale() - { + void ScreenSpaceSkyTarget::setFovFromScale() { glm::dvec2 fovs = skybrowser::fovWindow(); _verticalFov = _scale * fovs.y; } @@ -291,14 +303,12 @@ namespace openspace { return _isLocked; } - bool ScreenSpaceSkyTarget::isAnimated() - { + bool ScreenSpaceSkyTarget::isAnimated() { return _isAnimated; } void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, - bool shouldLockAfter) - { + bool shouldLockAfter) { _animationStart = glm::normalize( skybrowser::sphericalToCartesian(equatorialAim()) ); @@ -308,8 +318,7 @@ namespace openspace { _isLocked = false; } - void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) - { + void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { // At fps that are too low, the animation stops working. Just place target instead bool fpsTooLow = deltaTime > DeltaTimeThreshold; // Find smallest angle between the two vectors @@ -362,52 +371,48 @@ namespace openspace { } glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const { - + glm::dvec3 cartesian; // Get the local camera coordinates of the target if (_useRadiusAzimuthElevation) { - glm::vec3 cartesian = raeToCartesian(_raePosition.value()); + cartesian = raeToCartesian(_raePosition.value()); glm::dvec3 equatorial = skybrowser::localCameraToEquatorial(cartesian); return skybrowser::cartesianToSpherical(equatorial); } else { - glm::dvec3 cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value()); + cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value()); return skybrowser::cartesianToSpherical(cartesian); } } - - void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) - { + void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) { _borderColor += addition; } - void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal) - { + void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal) { _borderColor -= removal; } float ScreenSpaceSkyTarget::opacity() const { - return _opacity.value(); + return _opacity; } - glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const - { + glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const { return skybrowser::cartesianToSpherical(_lockedCoordinates); } void ScreenSpaceSkyTarget::setOpacity(float opacity) { _opacity = opacity; } - void ScreenSpaceSkyTarget::setLock(bool isLocked) - { + + void ScreenSpaceSkyTarget::setLock(bool isLocked) { _isLocked = isLocked; if (_isLocked) { _lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim()); } } - void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) - { + + void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) { _isAnimated = false; _isLocked = false; diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 613b39c7e3..965091c62b 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -37,15 +37,15 @@ namespace openspace { - TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target) + TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, + ScreenSpaceSkyTarget* target) : _target(target), _browser(browser) { ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); ghoul_assert(target != nullptr, "Sky target is null pointer!"); } - TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) - { + TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) { std::swap(_target, other._target); std::swap(_browser, other._browser); return *this; @@ -64,34 +64,29 @@ namespace openspace { _browser->setImageOrder(i, order); } - void TargetBrowserPair::removeHighlight(glm::ivec3 color) - { + void TargetBrowserPair::removeHighlight(glm::ivec3 color) { _target->removeHighlight(color); _browser->removeHighlight(color); } - void TargetBrowserPair::highlight(glm::ivec3 color) - { + void TargetBrowserPair::highlight(glm::ivec3 color) { _browser->highlight(color); _target->highlight(color); } - bool TargetBrowserPair::isTargetFadeFinished(float goalState) const - { + bool TargetBrowserPair::isTargetFadeFinished(float goalState) const { // Is fading finished? float targetDiff = abs(_target->opacity() - goalState); return targetDiff < FadeThreshold; } - bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const - { + bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const { float browserDiff = abs(_browser->opacity() - goalState); return browserDiff < FadeThreshold; } - bool TargetBrowserPair::checkMouseIntersection(glm::vec2 mousePosition) - { + bool TargetBrowserPair::checkMouseIntersection(glm::vec2 mousePosition) { bool onBrowser = _browser->intersection(mousePosition); bool onTarget = _target->intersection(mousePosition); if (onBrowser) { @@ -109,50 +104,46 @@ namespace openspace { return onBrowser || onTarget; } - glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() - { + glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() { return _selected->screenSpacePosition(); } - bool TargetBrowserPair::isBrowserSelected() - { + bool TargetBrowserPair::isBrowserSelected() { return _isSelectedBrowser; } - bool TargetBrowserPair::isTargetSelected() - { + bool TargetBrowserPair::isTargetSelected() { return _selected && !_isSelectedBrowser; } void TargetBrowserPair::fineTuneTarget(const glm::vec2& start, const glm::vec2& translation) { - glm::vec2 fineTune = -_browser->fineTuneVector(translation); + glm::vec2 fineTune = _browser->fineTuneVector(translation); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.translateScreenSpaceRenderable(\"" + targetId() + "\"," + std::to_string(start.x) + "," + std::to_string(start.y) + "," - + std::to_string(translation.x) + "," + std::to_string(translation.y) + ")", + + std::to_string(fineTune.x) + "," + std::to_string(fineTune.y) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); } void TargetBrowserPair::translateSelected(const glm::vec2& start, - const glm::vec2& translation) + const glm::vec2& trans) { if (this && _selected) { std::string id = _selected->identifier(); openspace::global::scriptEngine->queueScript( "openspace.skybrowser.translateScreenSpaceRenderable(\"" + id + "\"," + std::to_string(start.x) + "," + std::to_string(start.y) + "," - + std::to_string(translation.x) + "," + std::to_string(translation.y) + ")", + + std::to_string(trans.x) + "," + std::to_string(trans.y) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); } } - void TargetBrowserPair::synchronizeAim() - { + void TargetBrowserPair::synchronizeAim() { if (!_target->isAnimated()) { glm::dvec2 aim; // To remove the lag effect when moving the camera while having a locked @@ -169,82 +160,67 @@ namespace openspace { } } - void TargetBrowserPair::setEnabled(bool enable) - { + void TargetBrowserPair::setEnabled(bool enable) { _browser->setEnabled(enable); _target->setEnabled(enable); } - bool TargetBrowserPair::isEnabled() const - { + bool TargetBrowserPair::isEnabled() const { return _target->isEnabled() && _browser->isEnabled(); } - bool TargetBrowserPair::isLocked() const - { + bool TargetBrowserPair::isLocked() const { return _target->isLocked(); } - void TargetBrowserPair::initialize() - { + void TargetBrowserPair::initialize() { _target->setColor(_browser->borderColor()); _target->setDimensions(_browser->browserPixelDimensions()); _target->setScaleFromVfov(_browser->verticalFov()); _browser->updateBorderColor(); } - glm::ivec3 TargetBrowserPair::borderColor() const - { + glm::ivec3 TargetBrowserPair::borderColor() const { return _browser->borderColor(); } - glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const - { + glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const { return _target->equatorialAim(); } - glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const - { + glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const { return _target->directionGalactic(); } - std::string TargetBrowserPair::browserGuiName() const - { + std::string TargetBrowserPair::browserGuiName() const { return _browser->guiName(); } - std::string TargetBrowserPair::browserId() const - { + std::string TargetBrowserPair::browserId() const { return _browser->identifier(); } - std::string TargetBrowserPair::targetId() const - { + std::string TargetBrowserPair::targetId() const { return _target->identifier(); } - std::string TargetBrowserPair::selectedId() - { + std::string TargetBrowserPair::selectedId() { return _selected->identifier(); } - glm::vec2 TargetBrowserPair::size() const - { + glm::vec2 TargetBrowserPair::size() const { return _browser->size(); } - float TargetBrowserPair::verticalFov() const - { + float TargetBrowserPair::verticalFov() const { return _browser->verticalFov(); } - const std::deque& TargetBrowserPair::getSelectedImages() const - { + const std::deque& TargetBrowserPair::getSelectedImages() const { return _browser->getSelectedImages(); } - void TargetBrowserPair::selectImage(const ImageData& image, int i) - { + void TargetBrowserPair::selectImage(const ImageData& image, int i) { // Load image into browser _browser->displayImage(image.imageUrl, i); @@ -257,28 +233,23 @@ namespace openspace { } } - void TargetBrowserPair::removeSelectedImage(int i) - { + void TargetBrowserPair::removeSelectedImage(int i) { _browser->removeSelectedImage(i); } - void TargetBrowserPair::loadImageCollection(const std::string& collection) - { + void TargetBrowserPair::loadImageCollection(const std::string& collection) { _browser->loadImageCollection(collection); } - void TargetBrowserPair::setImageOpacity(int i, float opacity) - { + void TargetBrowserPair::setImageOpacity(int i, float opacity) { _browser->setImageOpacity(i, opacity); } - void TargetBrowserPair::hideChromeInterface(bool shouldHide) - { + void TargetBrowserPair::hideChromeInterface(bool shouldHide) { _browser->hideChromeInterface(shouldHide); } - void TargetBrowserPair::sendIdToBrowser() - { + void TargetBrowserPair::sendIdToBrowser() { _browser->setIdInBrowser(); } @@ -286,46 +257,39 @@ namespace openspace { _browser->updateBrowserSize(); } - void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) - { + void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { _browser->setIsSyncedWithWwt(isSynced); } - void TargetBrowserPair::setVerticalFov(float vfov) - { + void TargetBrowserPair::setVerticalFov(float vfov) { _verticalFov = vfov; _browser->setVerticalFov(vfov); _target->setScaleFromVfov(vfov); } - void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) - { + void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) { _equatorialAim = aim; _target->setEquatorialAim(aim); _browser->setEquatorialAim(aim); } - void TargetBrowserPair::setBorderColor(const glm::ivec3& color) - { + void TargetBrowserPair::setBorderColor(const glm::ivec3& color) { _borderColor = color; _target->setColor(color); _browser->setBorderColor(color); } - void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) - { + void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) { _dimensions = dimensions; _target->setDimensions(dimensions); _browser->setScreenSpaceSize(dimensions); } - void TargetBrowserPair::setVerticalFovWithScroll(float scroll) - { + void TargetBrowserPair::setVerticalFovWithScroll(float scroll) { _browser->setVerticalFovWithScroll(scroll); } - void TargetBrowserPair::setSelectedWithId(const std::string& id) - { + void TargetBrowserPair::setSelectedWithId(const std::string& id) { if (browserId() == id) { _isSelectedBrowser = true; _selected = _browser; @@ -340,8 +304,7 @@ namespace openspace { } } - void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) - { + void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { // Animate the target before the field of view starts to animate if (_target->isAnimated()) { _target->incrementallyAnimateToCoordinate(static_cast(deltaTime)); @@ -358,8 +321,7 @@ namespace openspace { _browser->startFovAnimation(fovEnd); } - void TargetBrowserPair::centerTargetOnScreen() - { + void TargetBrowserPair::centerTargetOnScreen() { // Animate the target to the center of the screen unlock(); // Get camera direction in celestial spherical coordinates @@ -369,18 +331,15 @@ namespace openspace { startAnimation(viewDirection, currentFov, false); } - bool TargetBrowserPair::hasFinishedFading(float goalState) const - { + bool TargetBrowserPair::hasFinishedFading(float goalState) const { return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); } - bool TargetBrowserPair::isFacingCamera() const - { + bool TargetBrowserPair::isFacingCamera() const { return _browser->isFacingCamera() || _target->isFacingCamera(); } - bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const - { + bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const { return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); } @@ -392,7 +351,8 @@ namespace openspace { return _browser; } - void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, float deltaTime) + void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, + float deltaTime) { float opacityDelta = static_cast(deltaTime / fadeTime); if (_target->opacity() > goalState) { @@ -417,9 +377,8 @@ namespace openspace { bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { return lhs._target == rhs._target && lhs._browser == rhs._browser; } + bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { return !(lhs == rhs); } - - } // namespace openspace diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 2003724fb0..c98260cdf1 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -1,3 +1,26 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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 @@ -5,191 +28,186 @@ #include #include #include -#include // For atan2 -#define _USE_MATH_DEFINES -#include // For M_PI - +#include namespace openspace::skybrowser { - // Converts from spherical coordinates in the unit of degrees to cartesian coordianates - glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) { +// Converts from spherical coordinates in the unit of degrees to cartesian coordianates +glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) { - glm::dvec2 coordsRadians = glm::radians(coords); + glm::dvec2 coordsRadians = glm::radians(coords); - glm::dvec3 cartesian = glm::dvec3( - cos(coordsRadians.x) * cos(coordsRadians.y), - sin(coordsRadians.x) * cos(coordsRadians.y), - sin(coordsRadians.y) - ); - - return cartesian; - } - - // Converts from cartesian coordianates to spherical in the unit of degrees - glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) { - // Equatorial coordinates RA = right ascension, Dec = declination - double ra = atan2(coord.y, coord.x); - double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y))); - - ra = ra > 0 ? ra : ra + (2 * M_PI); - - glm::dvec2 celestialCoords{ ra, dec }; - - return glm::degrees(celestialCoords); - } - - glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) { - return glm::transpose(conversionMatrix) * glm::normalize(coords); - } - - glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) { - // On the unit sphere - glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); - return rGalactic * CelestialSphereRadius; - } - - glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) { - - // Ensure that if the coord is behind the camera, - // the converted coordinate will be there too - double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ; - - // Calculate screen space coords x and y - double tan_x = coords.x / coords.z; - double tan_y = coords.y / coords.z; - - glm::dvec3 screenSpace = glm::dvec3(zCoord * tan_x, zCoord * tan_y, zCoord); - - return screenSpace; - } - - glm::dvec3 localCameraToGalactic(const glm::dvec3& coords) { - glm::dmat4 rotation = glm::inverse( - global::navigationHandler->camera()->viewRotationMatrix()); - glm::dvec4 position = glm::dvec4(coords, 1.0); - - return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius; - } - - glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) { - // Calculate the galactic coordinate of the target direction - // projected onto the celestial sphere - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 galactic = camPos + skybrowser::localCameraToGalactic(coords); - - return skybrowser::galacticToEquatorial(galactic); - } - - glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) - { - // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 galactic = equatorialToGalactic(coords); - glm::dvec3 localCamera = galacticToLocalCamera(galactic); - return localCamera; - } - - glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) { - // Transform vector to camera's local coordinate system - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos); - glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0); - - return glm::normalize(viewDirectionLocal); - } - - double cameraRoll() { - openspace::Camera* camera = global::navigationHandler->camera(); - glm::dvec3 upWorld = camera->lookUpVectorWorldSpace(); - glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace(); - - glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld); - glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld); - - glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole); - double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000); - double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000); - - return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); - } - - glm::dvec3 cameraDirectionEquatorial() { - // Get the view direction of the screen in cartesian J2000 coordinates - return galacticToEquatorial(cameraDirectionGalactic()); - } - - glm::dvec3 cameraDirectionGalactic() { - // Get the view direction of the screen in galactic coordinates - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace(); - glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view); - - return galCoord; - } - - float windowRatio() { - glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); - return windowRatio.x / windowRatio.y; - } - - bool isCoordinateInView(const glm::dvec3& equatorial) { - // Check if image coordinate is within current FOV - glm::dvec3 localCamera = equatorialToLocalCamera(equatorial); - glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera); - double r = static_cast(windowRatio()); - - bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f && - coordsScreen.z < 0; - - // If the coordinate is not in view, rotate camera - return isCoordInView; - } - - // Transforms a pixel coordinate to a screen space coordinate - glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) { - glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); - // Change origin to middle of the window - glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f); - // Ensure the upper right corner is positive on the y axis - screenSpacePos *= glm::vec2(1.0f, -1.0f); - // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] - screenSpacePos /= (0.5f * size.y); - return screenSpacePos; - } - - // The horizontal and vertical fov of the OpenSpace window - glm::dvec2 fovWindow() { - // OpenSpace FOV - glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize()); - double windowRatio = windowDim.y / windowDim.x; - double hFov = global::windowDelegate->getHorizFieldOfView(); - glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio); - return OpenSpaceFOV; - } - - double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { - - // Find smallest angle between the two vectors - double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); - return std::acos(cos); - } - - glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, - const glm::dvec3& end, double deltaTime, - double speedFactor) { - - double smallestAngle = angleBetweenVectors(start, end); - // Calculate rotation this frame - double rotationAngle = smallestAngle * deltaTime * speedFactor; - - // Create the rotation matrix for local camera space - glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end)); - return glm::rotate(rotationAngle, rotationAxis); - } + glm::dvec3 cartesian = glm::dvec3( + cos(coordsRadians.x) * cos(coordsRadians.y), + sin(coordsRadians.x) * cos(coordsRadians.y), + sin(coordsRadians.y) + ); + return cartesian; } +// Converts from cartesian coordianates to spherical in the unit of degrees +glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) { + // Equatorial coordinates RA = right ascension, Dec = declination + double ra = atan2(coord.y, coord.x); + double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y))); + + ra = ra > 0 ? ra : ra + (2.0 * glm::pi()); + + glm::dvec2 celestialCoords{ ra, dec }; + + return glm::degrees(celestialCoords); +} + +glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) { + return glm::transpose(conversionMatrix) * glm::normalize(coords); +} + +glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) { + // On the unit sphere + glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); + return rGalactic * CelestialSphereRadius; +} + +glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) { + // Ensure that if the coord is behind the camera, + // the converted coordinate will be there too + double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ; + + // Calculate screen space coords x and y + double tanX = coords.x / coords.z; + double tanY = coords.y / coords.z; + + glm::dvec3 screenSpace = glm::dvec3(zCoord * tanX, zCoord * tanY, zCoord); + + return screenSpace; +} + +glm::dvec3 localCameraToGalactic(const glm::dvec3& coords) { + glm::dmat4 rotation = glm::inverse( + global::navigationHandler->camera()->viewRotationMatrix()); + glm::dvec4 position = glm::dvec4(coords, 1.0); + + return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius; +} + +glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) { + // Calculate the galactic coordinate of the target direction + // projected onto the celestial sphere + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 galactic = camPos + skybrowser::localCameraToGalactic(coords); + + return skybrowser::galacticToEquatorial(galactic); +} + +glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) +{ + // Transform equatorial J2000 to galactic coord with infinite radius + glm::dvec3 galactic = equatorialToGalactic(coords); + glm::dvec3 localCamera = galacticToLocalCamera(galactic); + return localCamera; +} + +glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) { + // Transform vector to camera's local coordinate system + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); + glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0); + + return glm::normalize(viewDirectionLocal); +} + +double cameraRoll() { + openspace::Camera* camera = global::navigationHandler->camera(); + glm::dvec3 upWorld = camera->lookUpVectorWorldSpace(); + glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace(); + + glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld); + glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld); + + glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole); + double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000); + double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000); + + return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); +} + +glm::dvec3 cameraDirectionEquatorial() { + // Get the view direction of the screen in cartesian J2000 coordinates + return galacticToEquatorial(cameraDirectionGalactic()); +} + +glm::dvec3 cameraDirectionGalactic() { + // Get the view direction of the screen in galactic coordinates + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace(); + glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view); + + return galCoord; +} + +float windowRatio() { + glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); + return windowRatio.x / windowRatio.y; +} + +bool isCoordinateInView(const glm::dvec3& equatorial) { + // Check if image coordinate is within current FOV + glm::dvec3 localCamera = equatorialToLocalCamera(equatorial); + glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera); + double r = static_cast(windowRatio()); + + bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f && + coordsScreen.z < 0; + + // If the coordinate is not in view, rotate camera + return isCoordInView; +} + +// Transforms a pixel coordinate to a screen space coordinate +glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) { + glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize()); + // Change origin to middle of the window + glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f); + // Ensure the upper right corner is positive on the y axis + screenSpacePos *= glm::vec2(1.0f, -1.0f); + // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] + screenSpacePos /= (0.5f * size.y); + return screenSpacePos; +} + +// The horizontal and vertical fov of the OpenSpace window +glm::dvec2 fovWindow() { + // OpenSpace FOV + glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize()); + double windowRatio = windowDim.y / windowDim.x; + double hFov = global::windowDelegate->getHorizFieldOfView(); + glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio); + return OpenSpaceFOV; +} + +double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { + + // Find smallest angle between the two vectors + double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); + return std::acos(cos); +} + +glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, + const glm::dvec3& end, double deltaTime, + double speedFactor) { + + double smallestAngle = angleBetweenVectors(start, end); + // Calculate rotation this frame + double rotationAngle = smallestAngle * deltaTime * speedFactor; + + // Create the rotation matrix for local camera space + glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end)); + return glm::rotate(rotationAngle, rotationAxis); +} +} // namespace openspace + diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 227a96f6e8..4336074f47 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2021 * + * Copyright (c) 2014-2022 * * * * 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 * @@ -27,327 +27,291 @@ #include #include #include -#include // formatJson +#include #include -#include -#include // For atan2 -#define _USE_MATH_DEFINES -#include // For M_PI namespace { constexpr const char* _loggerCat = "WwtCommunicator"; - - } // namespace namespace openspace { - WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary) - : Browser(dictionary) {} +WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary) + : Browser(dictionary) {} - WwtCommunicator::~WwtCommunicator() { +WwtCommunicator::~WwtCommunicator() {} +void WwtCommunicator::displayImage(const std::string& url, int i) { + // Ensure there are no duplicates + auto it = std::find(_selectedImages.begin(), _selectedImages.end(), i); + if (it == _selectedImages.end()) { + // Push newly selected image to front + _selectedImages.push_front(i); + // Index of image is used as layer ID as it is unique in the image data set + sendMessageToWwt(addImageMessage(std::to_string(i), url)); + sendMessageToWwt(setImageOpacityMessage(std::to_string(i), 1.0)); + } +} + +void WwtCommunicator::removeSelectedImage(int i) { + // Remove from selected list + auto it = std::find(_selectedImages.begin(), _selectedImages.end(), i); + + if (it != std::end(_selectedImages)) { + _selectedImages.erase(it); + sendMessageToWwt(removeImageMessage(std::to_string(i))); + } +} + +void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) { + std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; + executeJavascript(script); +} + +const std::deque& WwtCommunicator::getSelectedImages() const { + return _selectedImages; +} + +void WwtCommunicator::setVerticalFov(float vfov) { + _verticalFov = vfov; + _equatorialAimIsDirty = true; +} + +void WwtCommunicator::setWebpageBorderColor(glm::ivec3 color) { + std::string stringColor = std::to_string(color.x) + "," + + std::to_string(color.y) + "," + std::to_string(color.z); + std::string script = "document.body.style.backgroundColor = 'rgb(" + + stringColor + ")';"; + executeJavascript(script); +} + +void WwtCommunicator::setIsSyncedWithWwt(bool isSynced) { + _isSyncedWithWwt = isSynced; +} + +void WwtCommunicator::setEquatorialAim(glm::dvec2 equatorial) { + _equatorialAim = std::move(equatorial); + _equatorialAimIsDirty = true; +} + +void WwtCommunicator::setBorderColor(glm::ivec3 color) { + _borderColor = std::move(color); + _borderColorIsDirty = true; +} + +void WwtCommunicator::highlight(glm::ivec3 addition) { + setWebpageBorderColor(_borderColor + addition); +} + +void WwtCommunicator::removeHighlight(glm::ivec3 removal) { + setWebpageBorderColor(_borderColor - removal); +} + +void WwtCommunicator::updateBorderColor() { + setWebpageBorderColor(_borderColor); +} + +void WwtCommunicator::updateAim() { + double roll = _isSyncedWithWwt ? skybrowser::cameraRoll() : 0.0; + // Message WorldWide Telescope current view + ghoul::Dictionary message = moveCameraMessage( + _equatorialAim, + _verticalFov, + roll + ); + sendMessageToWwt(message); +} + +glm::dvec2 WwtCommunicator::fieldsOfView() const { + glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio(), verticalFov()); + + return browserFov; +} + +bool WwtCommunicator::hasLoadedImages() const { + return _hasLoadedImages; +} + +glm::dvec2 WwtCommunicator::equatorialAim() const { + return _equatorialAim; +} + +void WwtCommunicator::setImageOrder(int i, int order) { + // Find in selected images list + auto current = std::find( + _selectedImages.begin(), + _selectedImages.end(), + i + ); + auto target = std::begin(_selectedImages) + order; + + // Make sure the image was found in the list + if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { + // Swap the two images + std::iter_swap(current, target); } - void WwtCommunicator::displayImage(const std::string& url, int i) - { - // Ensure there are no duplicates - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - if (it == std::end(_selectedImages)) { - // Push newly selected image to front - _selectedImages.push_front(i); - // Index of image is used as layer ID as it is unique in the image data set - sendMessageToWwt(addImage(std::to_string(i), url)); - sendMessageToWwt(setImageOpacity(std::to_string(i), 1.0)); + int reverseOrder = _selectedImages.size() - order - 1; + ghoul::Dictionary message = setLayerOrderMessage(std::to_string(i), reverseOrder); + sendMessageToWwt(message); +} + +void WwtCommunicator::loadImageCollection(const std::string& collection) { + sendMessageToWwt(loadCollectionMessage(collection)); + _hasLoadedImages = true; +} + +void WwtCommunicator::setImageOpacity(int i, float opacity) { + ghoul::Dictionary msg = setImageOpacityMessage(std::to_string(i), opacity); + sendMessageToWwt(msg); +} + +void WwtCommunicator::hideChromeInterface(bool shouldHide) { + ghoul::Dictionary msg = hideChromeGuiMessage(shouldHide); + sendMessageToWwt(msg); +} + +void WwtCommunicator::update() { + Browser::update(); + // Cap how messages are passed + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; + + if (timeSinceLastUpdate > TimeUpdateInterval) { + if (_equatorialAimIsDirty) { + updateAim(); + _equatorialAimIsDirty = false; } - } - - void WwtCommunicator::removeSelectedImage(int i) { - // Remove from selected list - auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i); - - if (it != std::end(_selectedImages)) { - _selectedImages.erase(it); - sendMessageToWwt(removeImage(std::to_string(i))); + if (_borderColorIsDirty) { + updateBorderColor(); + _borderColorIsDirty = false; } + _lastUpdateTime = std::chrono::system_clock::now(); } +} - void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) { - std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");"; - executeJavascript(script); - } +void WwtCommunicator::render() { + Browser::render(); +} - const std::deque& WwtCommunicator::getSelectedImages() { - return _selectedImages; - } +void WwtCommunicator::initializeGL() { + Browser::initializeGL(); +} - void WwtCommunicator::setVerticalFov(float vfov) { - _verticalFov = vfov; - _equatorialAimIsDirty = true; - } +void WwtCommunicator::deinitializeGL() { + Browser::deinitializeGL(); +} - void WwtCommunicator::setWebpageBorderColor(glm::ivec3 color) { - std::string stringColor = std::to_string(color.x) + "," - + std::to_string(color.y) + "," + std::to_string(color.z); - std::string script = "document.body.style.backgroundColor = 'rgb(" - + stringColor + ")';"; - executeJavascript(script); - } +void WwtCommunicator::setHasLoadedImages(bool isLoaded) { + _hasLoadedImages = isLoaded; +} - void WwtCommunicator::setIsSyncedWithWwt(bool isSynced) - { - _isSyncedWithWwt = isSynced; - } +void WwtCommunicator::setIdInBrowser(const std::string& id) { + // Send ID to it's browser + executeJavascript("setId('" + id + "')"); +} - void WwtCommunicator::setEquatorialAim(const glm::dvec2& equatorial) - { - _equatorialAim = equatorial; - _equatorialAimIsDirty = true; - } +glm::ivec3 WwtCommunicator::borderColor() const { + return _borderColor; +} - void WwtCommunicator::setBorderColor(const glm::ivec3& color) - { - _borderColor = color; - _borderColorIsDirty = true; - } +float WwtCommunicator::verticalFov() const { + return _verticalFov; +} - void WwtCommunicator::highlight(glm::ivec3 addition) - { - setWebpageBorderColor(_borderColor + addition); - } +// WWT messages +ghoul::Dictionary WwtCommunicator::moveCameraMessage(const glm::dvec2& celestCoords, + double fov, double roll, + bool shouldMoveInstantly) { + using namespace std::string_literals; + ghoul::Dictionary msg; - void WwtCommunicator::removeHighlight(glm::ivec3 removal) - { - setWebpageBorderColor(_borderColor - removal); - } + // Create message + msg.setValue("event", "center_on_coordinates"s); + msg.setValue("ra", celestCoords.x); + msg.setValue("dec", celestCoords.y); + msg.setValue("fov", fov); + msg.setValue("roll", roll); + msg.setValue("instant", shouldMoveInstantly); - void WwtCommunicator::updateBorderColor() - { - setWebpageBorderColor(_borderColor); - } + return msg; +} - void WwtCommunicator::updateAim() - { - double roll = _isSyncedWithWwt ? skybrowser::cameraRoll() : 0.0; - // Message WorldWide Telescope current view - ghoul::Dictionary message = moveCamera( - _equatorialAim, - _verticalFov, - roll - ); - sendMessageToWwt(message); - } +ghoul::Dictionary WwtCommunicator::loadCollectionMessage(const std::string& url) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "load_image_collection"s); + msg.setValue("url", url); + msg.setValue("loadChildFolders", true); - glm::dvec2 WwtCommunicator::fieldsOfView() { - glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio(), verticalFov()); + return msg; +} - return browserFov; - } +ghoul::Dictionary WwtCommunicator::setForegroundMessage(const std::string& name) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "set_foreground_by_name"s); + msg.setValue("name", name); - bool WwtCommunicator::hasLoadedImages() const { - return _hasLoadedImages; - } + return msg; +} - glm::dvec2 WwtCommunicator::equatorialAim() const - { - return _equatorialAim; - } +ghoul::Dictionary WwtCommunicator::addImageMessage(const std::string& id, + const std::string& url) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_create"s); + msg.setValue("id", id); + msg.setValue("url", url); + msg.setValue("mode", "preloaded"s); + msg.setValue("goto", false); - void WwtCommunicator::setImageOrder(int i, int order) { - // Find in selected images list - auto current = std::find( - std::begin(_selectedImages), - std::end(_selectedImages), - i - ); - auto target = std::begin(_selectedImages) + order; + return msg; +} - // Make sure the image was found in the list - if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) { - // Swap the two images - std::iter_swap(current, target); - } +ghoul::Dictionary WwtCommunicator::removeImageMessage(const std::string& imageId) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_remove"s); + msg.setValue("id", imageId); - int reverseOrder = _selectedImages.size() - order - 1; - ghoul::Dictionary message = setLayerOrder(std::to_string(i), - reverseOrder); - sendMessageToWwt(message); - } + return msg; +} - void WwtCommunicator::loadImageCollection(const std::string& collection) { - sendMessageToWwt(loadCollection(collection)); - _hasLoadedImages = true; - } +ghoul::Dictionary WwtCommunicator::setImageOpacityMessage(const std::string& imageId, + double opacity) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_set"s); + msg.setValue("id", imageId); + msg.setValue("setting", "opacity"s); + msg.setValue("value", opacity); - void WwtCommunicator::setImageOpacity(int i, float opacity) { - ghoul::Dictionary msg = setImageOpacity(std::to_string(i), opacity); - sendMessageToWwt(msg); - } + return msg; +} - void WwtCommunicator::hideChromeInterface(bool shouldHide) - { - ghoul::Dictionary msg = hideChromeGui(shouldHide); - sendMessageToWwt(msg); - } +ghoul::Dictionary WwtCommunicator::setLayerOrderMessage(const std::string& id, int order) { + // The lower the layer order, the more towards the back the image is placed + // 0 is the background + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "image_layer_order"s); + msg.setValue("id", id); + msg.setValue("order", order); + msg.setValue("version", messageCounter); - void WwtCommunicator::update() - { - Browser::update(); - // Cap how messages are passed - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime; + messageCounter++; - if (timeSinceLastUpdate > _timeUpdateInterval) { + return msg; +} - if (_equatorialAimIsDirty) { - updateAim(); - _equatorialAimIsDirty = false; - } - if (_borderColorIsDirty) { - updateBorderColor(); - _borderColorIsDirty = false; - } - _lastUpdateTime = std::chrono::system_clock::now(); - } - } - - void WwtCommunicator::render() - { - Browser::render(); - } - - void WwtCommunicator::initializeGL() - { - Browser::initializeGL(); - } - - void WwtCommunicator::deinitializeGL() - { - Browser::deinitializeGL(); - } - - void WwtCommunicator::setHasLoadedImages(bool isLoaded) { - _hasLoadedImages = isLoaded; - } - - void WwtCommunicator::setIdInBrowser(const std::string& id) { - // Send ID to it's browser - executeJavascript("setId('" + id + "')"); - } - - - glm::ivec3 WwtCommunicator::borderColor() const { - return _borderColor; - } - - float WwtCommunicator::verticalFov() const { - return _verticalFov; - } - - // WWT messages - ghoul::Dictionary WwtCommunicator::moveCamera(const glm::dvec2& celestCoords, - double fov, double roll, - bool shouldMoveInstantly) { - using namespace std::string_literals; - ghoul::Dictionary msg; - - // Create message - msg.setValue("event", "center_on_coordinates"s); - msg.setValue("ra", celestCoords.x); - msg.setValue("dec", celestCoords.y); - msg.setValue("fov", fov); - msg.setValue("roll", roll); - msg.setValue("instant", shouldMoveInstantly); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::loadCollection(const std::string& url) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "load_image_collection"s); - msg.setValue("url", url); - msg.setValue("loadChildFolders", true); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::setForeground(const std::string& name) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_by_name"s); - msg.setValue("name", name); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::addImage(const std::string& id, - const std::string& url) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_create"s); - msg.setValue("id", id); - msg.setValue("url", url); - msg.setValue("mode", "preloaded"s); - msg.setValue("goto", false); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::removeImage(const std::string& imageId) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_remove"s); - msg.setValue("id", imageId); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::setImageOpacity(const std::string& imageId, - double opacity) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_set"s); - msg.setValue("id", imageId); - msg.setValue("setting", "opacity"s); - msg.setValue("value", opacity); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::setForegroundOpacity(double val) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_opacity"s); - msg.setValue("value", val); - - return msg; - } - - ghoul::Dictionary WwtCommunicator::setLayerOrder(const std::string& id, int order) { - // The lower the layer order, the more towards the back the image is placed - // 0 is the background - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "image_layer_order"s); - msg.setValue("id", id); - msg.setValue("order", order); - msg.setValue("version", messageCounter); - - messageCounter++; - - return msg; - } - - ghoul::Dictionary WwtCommunicator::hideChromeGui(bool isHidden) - { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "modify_settings"s); - msg.setValue("settings", "[[\"hideAllChrome\", true]]"s); - msg.setValue("target", "app"s); - - return msg; - } +ghoul::Dictionary WwtCommunicator::hideChromeGuiMessage(bool isHidden) { + using namespace std::string_literals; + ghoul::Dictionary msg; + msg.setValue("event", "modify_settings"s); + msg.setValue("settings", "[[\"hideAllChrome\", true]]"s); + msg.setValue("target", "app"s); + return msg; +} } // namespace openspace diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 40aeabf4d1..0f3d8944b7 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -1,11 +1,34 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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 // For downloading files from url +#include #include #include -#include // To iterate through files in directory +#include #include #include #include @@ -16,351 +39,337 @@ namespace { namespace openspace { - bool hasAttribute(const tinyxml2::XMLElement* element, const std::string& name) { - return element->FindAttribute(name.c_str()); +bool hasAttribute(const tinyxml2::XMLElement* element, const std::string_view& name) { + return element->FindAttribute(std::string(name).c_str()); +} + +std::string attribute(const tinyxml2::XMLElement* element, const std::string& name) { + if (hasAttribute(element, name)) { + return element->FindAttribute(name.c_str())->Value(); } - - std::string attribute(const tinyxml2::XMLElement* element, const std::string& name) { - if (hasAttribute(element, name)) { - return element->FindAttribute(name.c_str())->Value(); - } - else { - return wwt::Undefined; - } + else { + return wwt::Undefined; } +} - // Parsing and downloading of wtml files - bool downloadFile(const std::string& url, const std::string& fileDestination) { - // Get the web page and save to file - HttpFileDownload wtml_root( - url, fileDestination, HttpFileDownload::Overwrite::Yes - ); - wtml_root.start(std::chrono::milliseconds(5)); - return wtml_root.hasSucceeded(); +// Parsing and downloading of wtml files +bool downloadFile(const std::string& url, const std::filesystem::path& fileDestination) { + // Get the web page and save to file + HttpFileDownload wtmlRoot( + url, + fileDestination, + HttpFileDownload::Overwrite::Yes + ); + wtmlRoot.start(std::chrono::milliseconds(10000)); + return wtmlRoot.wait(); +} + +bool directoryExists(const std::filesystem::path& path) { + return std::filesystem::exists(path) && std::filesystem::is_directory(path); +} + +std::string createSearchableString(std::string str) { + // Remove white spaces and all special characters + str.erase(std::remove_if(str.begin(), str.end(), [](char c) { + const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); + return !isNumberOrLetter; + }), + std::end(str)); + // Make the word lower case + std::transform(str.begin(), str.end(), str.begin(), [](char c) { + return std::tolower(c); + }); + return str; +} + +tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, + const std::string& name) +{ + while (node && node->Name() != name) { + node = node->FirstChildElement(); } + return node; +} - bool directoryExists(const std::string& path) - { - struct stat info; - - int statRC = stat(path.c_str(), &info); - if (statRC != 0) - { - // something along the path does not exist - if (errno == ENOENT) { - return false; - } - // something in path prefix is not a dir - if (errno == ENOTDIR) { - return false; - } - return false; - } - - const bool directoryExists = (info.st_mode & S_IFDIR); - - return directoryExists; - } - - std::string createSearchableString(std::string str) { - // Remove white spaces and all special characters - str.erase(std::remove_if(std::begin(str), std::end(str), [](char c) { - const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); - return !isNumberOrLetter; - }), - std::end(str)); - // Make the word lower case - std::transform(std::begin(str), std::end(str), std::begin(str), [](char c) { - return std::tolower(c); - }); - return str; - } - - tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, - const std::string& name) { - while (node && node->Name() != name) { - node = node->FirstChildElement(); - } - return node; - } - - tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, - const std::string& name) { +tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, + const std::string& name) +{ - tinyxml2::XMLElement* child = node->FirstChildElement(); - tinyxml2::XMLElement* imageSet = nullptr; + tinyxml2::XMLElement* child = node->FirstChildElement(); + tinyxml2::XMLElement* imageSet = nullptr; - // Traverse the children and look at all their first child to find ImageSet - while (child) { - imageSet = getDirectChildNode(child, name); - // Found - if (imageSet) { - break; - } - child = child->NextSiblingElement(); - } - return imageSet; - } - - std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, - const std::string& elementName) { - // Find the thumbnail image url - // The thumbnail is the last node so traverse backwards for speed - tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement( - elementName.c_str() - ); - - if (imageSetChild && imageSetChild->GetText()) { - return imageSetChild->GetText(); - } - else { - return wwt::Undefined; - } - } - - std::string getUrlFromPlace(tinyxml2::XMLElement* place) { - - // If the place has a thumbnail url, return it - if (hasAttribute(place, wwt::Thumbnail)) { - return attribute(place, wwt::Thumbnail); - } - - // If the place doesn't have a thumbnail url data attribute, - // Load the image set it stores instead - tinyxml2::XMLElement* imageSet = getChildNode(place, wwt::ImageSet); - - // If there is an imageSet, collect thumbnail url + // Traverse the children and look at all their first child to find ImageSet + while (child) { + imageSet = getDirectChildNode(child, name); + // Found if (imageSet) { - return getChildNodeContentFromImageSet(imageSet, wwt::ThumbnailUrl); + break; } - else { - // If it doesn't contain an ImageSet, it doesn't have an url - return wwt::Undefined; - } - } + child = child->NextSiblingElement(); + } + return imageSet; +} + +std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, + const std::string& elementName) +{ + // Find the thumbnail image url + // The thumbnail is the last node so traverse backwards for speed + tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement( + elementName.c_str() + ); + + if (imageSetChild && imageSetChild->GetText()) { + return imageSetChild->GetText(); + } + else { + return wwt::Undefined; + } +} + +std::string getUrlFromPlace(tinyxml2::XMLElement* place) { + // If the place has a thumbnail url, return it + if (hasAttribute(place, wwt::Thumbnail)) { + return attribute(place, wwt::Thumbnail); + } + + // If the place doesn't have a thumbnail url data attribute, + // Load the image set it stores instead + tinyxml2::XMLElement* imageSet = getChildNode(place, wwt::ImageSet); + + // If there is an imageSet, collect thumbnail url + if (imageSet) { + return getChildNodeContentFromImageSet(imageSet, wwt::ThumbnailUrl); + } + else { + // If it doesn't contain an ImageSet, it doesn't have an url + return wwt::Undefined; + } +} - void parseWtmlsFromDisc(std::vector& _xmls, - const std::string& directory) { - for (const auto& entry : std::filesystem::directory_iterator(directory)) { +void parseWtmlsFromDisc(std::vector& _xmls, + const std::filesystem::path& directory) +{ + for (const auto& entry : std::filesystem::directory_iterator(directory)) { - tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument(); - std::string path = entry.path().u8string(); - tinyxml2::XMLError successCode = document->LoadFile(path.c_str()); + tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument(); + std::string path = entry.path().u8string(); + tinyxml2::XMLError successCode = document->LoadFile(path.c_str()); - if (successCode == tinyxml2::XMLError::XML_SUCCESS) { - _xmls.push_back(document); - } + if (successCode == tinyxml2::XMLError::XML_SUCCESS) { + _xmls.push_back(document); } } - - bool downloadAndParseWtmlFilesFromUrl(std::vector& _xmls, - const std::string& directory, const std::string& url, - const std::string& fileName) - { - // Look for WWT image data folder, create folder if it doesn't exist - if (!directoryExists(directory)) { - std::string newDir = directory; - // Remove the '/' at the end - newDir.pop_back(); - LINFO("Creating directory WWTimagedata"); - std::filesystem::create_directory(newDir); - } - - // Download file from url - std::string file = directory.c_str() + fileName + ".aspx"; - if (!downloadFile(url, file)) { - LINFO("Couldn't download file " + url); - return false; - } - - // Parse file to XML - using namespace tinyxml2; - tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); - doc->LoadFile(file.c_str()); - - // Search XML file for folders with urls - XMLElement* root = doc->RootElement(); - XMLElement* element = root->FirstChildElement(wwt::Folder.c_str()); - const bool folderExists = element; - const bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url); - - // If the file contains no folders, or there are folders but without urls, - // stop recursion - if (!folderExists || folderContainNoUrls) { - _xmls.push_back(doc); - LINFO("Saving " + url); - - return true; - } - - // Iterate through all the folders in the XML file - while (element && std::string(element->Value()) == wwt::Folder) { - - // If folder contains urls, download and parse those urls - if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) { - std::string url = attribute(element, wwt::Url); - std::string fileName = attribute(element, wwt::Name); - downloadAndParseWtmlFilesFromUrl(_xmls, directory, url, fileName); - } - element = element->NextSiblingElement(); - } - - } - - WwtDataHandler::~WwtDataHandler() { - // Call destructor of all allocated xmls - _xmls.clear(); - } - - void WwtDataHandler::loadImages(const std::string& root, - const std::string& directory) { - - // Collect the wtml files, either by reading from disc or from a url - if (directoryExists(directory)) { - parseWtmlsFromDisc(_xmls, directory); - LINFO("Loading images from directory"); - } - else { - downloadAndParseWtmlFilesFromUrl(_xmls, directory, root, "root"); - LINFO("Loading images from url"); - } - - // Traverse through the collected wtml documents and collect the images - for (tinyxml2::XMLDocument* doc : _xmls) { - tinyxml2::XMLElement* root = doc->FirstChildElement(); - std::string collectionName = attribute(root, wwt::Name); - saveImagesFromXml(root, collectionName); - } - - // Sort images in alphabetical order - std::sort(_images.begin(), _images.end(), [](ImageData& a, ImageData& b) { - // If the first character in the names are lowercase, make it upper case - if (std::islower(a.name[0])) { - // convert string to upper case - a.name[0] = ::toupper(a.name[0]); - } - if (std::islower(b.name[0])) { - b.name[0] = ::toupper(b.name[0]); - } - return a.name < b.name; - }); - - LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope " - "images."); - } - - int WwtDataHandler::nLoadedImages() const - { - return _images.size(); - } - - const ImageData& WwtDataHandler::getImage(const int i) const - { - assert(i < _images.size(), "Index outside of image vector boundaries!"); - return _images[i]; - } - - void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, - std::string collection) { - - // Collect the image set of the node. The structure is different depending on if - // it is a Place or an ImageSet - std::string thumbnailUrl = { wwt::Undefined }; - tinyxml2::XMLElement* imageSet{ nullptr }; - std::string type = std::string(node->Name()); - - if (type == wwt::ImageSet) { - thumbnailUrl = getChildNodeContentFromImageSet(node, wwt::ThumbnailUrl); - imageSet = node; - } // Place - else if (type == wwt::Place) { - thumbnailUrl = getUrlFromPlace(node); - imageSet = getChildNode(node, wwt::ImageSet); - } - - // Only collect the images that have a thumbnail image, that are sky images and - // that have an image - const bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined; - const bool isSkyImage = attribute(node, wwt::DataSetType) == wwt::Sky; - const bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false; - - if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) { - return; - } - - // Collect name, image url and credits - std::string name = attribute(node, wwt::Name); - std::string imageUrl = attribute(imageSet, wwt::Url); - std::string credits = getChildNodeContentFromImageSet(imageSet, wwt::Credits); - std::string creditsUrl = getChildNodeContentFromImageSet( - imageSet, wwt::CreditsUrl - ); - - // Collect equatorial coordinates. All-sky surveys do not have this kind of - // coordinate - bool hasCelestialCoords = hasAttribute(node, wwt::RA) && - hasAttribute(node, wwt::Dec); - glm::dvec2 equatorialSpherical{ 0.0 }; - glm::dvec3 equatorialCartesian{ 0.0 }; - - if (hasCelestialCoords) { - // The RA from WWT is in the unit hours: - // to convert to degrees, multiply with 360 (deg) /24 (h) = 15 - double ra = 15.0 * std::stod(attribute(node, wwt::RA)); - double dec = std::stod(attribute(node, wwt::Dec)); - equatorialSpherical = { ra, dec }; - equatorialCartesian = skybrowser::sphericalToCartesian( - equatorialSpherical - ); - } - - // Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6 - float fov{ 0.f }; - if (hasAttribute(node, wwt::ZoomLevel)) { - fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0; - } - - ImageData image = { - name, - thumbnailUrl, - imageUrl, - credits, - creditsUrl, - collection, - hasCelestialCoords, - fov, - equatorialSpherical, - equatorialCartesian, - }; - - _images.push_back(image); - } - - void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root, - std::string collection) { - - // Get direct child of node called Place - using namespace tinyxml2; - XMLElement* node = root->FirstChildElement(); - - // Iterate through all siblings of node. If sibling is folder, open recursively. - // If sibling is image, save it. - while (node) { - const std::string name = node->Name(); - // If node is an image or place, load it - if (name == wwt::ImageSet || name == wwt::Place) { - saveImageFromNode(node, collection); - } - // If node is another folder, open recursively - else if (name == wwt::Folder) { - std::string newCollectionName = collection + "/"; - newCollectionName += attribute(node, wwt::Name); - - saveImagesFromXml(node, newCollectionName); - } - node = node->NextSiblingElement(); - } - } - } + +bool downloadAndParseWtmlFilesFromUrl(std::vector& _xmls, + const std::filesystem::path& directory, const std::string& url, + const std::string& fileName) +{ + // Look for WWT image data folder, create folder if it doesn't exist + if (!directoryExists(directory)) { + std::string newDir = directory.string(); + // Remove the '/' at the end + newDir.pop_back(); + LINFO("Creating directory WWTimagedata"); + std::filesystem::create_directory(newDir); + } + + // Download file from url + std::filesystem::path file = directory.string() + fileName + ".aspx"; + if (!downloadFile(url, file)) { + LINFO("Couldn't download file " + url + " to directory " + directory.string()); + return false; + } + + // Parse file to XML + using namespace tinyxml2; + tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); + doc->LoadFile(file.string().c_str()); + + // Search XML file for folders with urls + XMLElement* root = doc->RootElement(); + XMLElement* element = root->FirstChildElement(wwt::Folder.c_str()); + const bool folderExists = element; + const bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url); + + // If the file contains no folders, or there are folders but without urls, + // stop recursion + if (!folderExists || folderContainNoUrls) { + _xmls.push_back(doc); + LINFO("Saving " + url); + + return true; + } + + // Iterate through all the folders in the XML file + while (element && std::string(element->Value()) == wwt::Folder) { + + // If folder contains urls, download and parse those urls + if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) { + std::string url = attribute(element, wwt::Url); + std::string fileName = attribute(element, wwt::Name); + downloadAndParseWtmlFilesFromUrl(_xmls, directory, url, fileName); + } + element = element->NextSiblingElement(); + } + return true; +} + +WwtDataHandler::~WwtDataHandler() { + // Call destructor of all allocated xmls + _xmls.clear(); +} + +void WwtDataHandler::loadImages(const std::string& root, + const std::filesystem::path& directory) { + + // Collect the wtml files, either by reading from disc or from a url + if (directoryExists(directory)) { + parseWtmlsFromDisc(_xmls, directory); + LINFO("Loading images from directory"); + } + else { + downloadAndParseWtmlFilesFromUrl(_xmls, directory, root, "root"); + LINFO("Loading images from url"); + } + + // Traverse through the collected wtml documents and collect the images + for (tinyxml2::XMLDocument* doc : _xmls) { + tinyxml2::XMLElement* root = doc->FirstChildElement(); + std::string collectionName = attribute(root, wwt::Name); + saveImagesFromXml(root, collectionName); + } + + // Sort images in alphabetical order + std::sort(_images.begin(), _images.end(), [](ImageData& a, ImageData& b) { + // If the first character in the names are lowercase, make it upper case + if (std::islower(a.name[0])) { + // convert string to upper case + a.name[0] = ::toupper(a.name[0]); + } + if (std::islower(b.name[0])) { + b.name[0] = ::toupper(b.name[0]); + } + return a.name < b.name; + }); + + LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope " + "images."); +} + +int WwtDataHandler::nLoadedImages() const +{ + return _images.size(); +} + +const ImageData& WwtDataHandler::getImage(const int i) const +{ + ghoul_assert(i < _images.size(), "Index outside of image vector boundaries!"); + return _images[i]; +} + +void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, + std::string collection) { + + // Collect the image set of the node. The structure is different depending on if + // it is a Place or an ImageSet + std::string thumbnailUrl = { wwt::Undefined }; + tinyxml2::XMLElement* imageSet{ nullptr }; + std::string type = std::string(node->Name()); + + if (type == wwt::ImageSet) { + thumbnailUrl = getChildNodeContentFromImageSet(node, wwt::ThumbnailUrl); + imageSet = node; + } // Place + else if (type == wwt::Place) { + thumbnailUrl = getUrlFromPlace(node); + imageSet = getChildNode(node, wwt::ImageSet); + } + + // Only collect the images that have a thumbnail image, that are sky images and + // that have an image + const bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined; + const bool isSkyImage = attribute(node, wwt::DataSetType) == wwt::Sky; + const bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false; + + if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) { + return; + } + + // Collect name, image url and credits + std::string name = attribute(node, wwt::Name); + std::string imageUrl = attribute(imageSet, wwt::Url); + std::string credits = getChildNodeContentFromImageSet(imageSet, wwt::Credits); + std::string creditsUrl = getChildNodeContentFromImageSet( + imageSet, wwt::CreditsUrl + ); + + // Collect equatorial coordinates. All-sky surveys do not have this kind of + // coordinate + bool hasCelestialCoords = hasAttribute(node, wwt::RA) && + hasAttribute(node, wwt::Dec); + glm::dvec2 equatorialSpherical{ 0.0 }; + glm::dvec3 equatorialCartesian{ 0.0 }; + + if (hasCelestialCoords) { + // The RA from WWT is in the unit hours: + // to convert to degrees, multiply with 360 (deg) /24 (h) = 15 + double ra = 15.0 * std::stod(attribute(node, wwt::RA)); + double dec = std::stod(attribute(node, wwt::Dec)); + equatorialSpherical = { ra, dec }; + equatorialCartesian = skybrowser::sphericalToCartesian( + equatorialSpherical + ); + } + + // Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6 + float fov{ 0.f }; + if (hasAttribute(node, wwt::ZoomLevel)) { + fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0f; + } + + ImageData image = { + name, + thumbnailUrl, + imageUrl, + credits, + creditsUrl, + collection, + hasCelestialCoords, + fov, + equatorialSpherical, + equatorialCartesian, + }; + + _images.push_back(image); +} + +void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root, + std::string collection) +{ + + // Get direct child of node called Place + using namespace tinyxml2; + XMLElement* node = root->FirstChildElement(); + + // Iterate through all siblings of node. If sibling is folder, open recursively. + // If sibling is image, save it. + while (node) { + const std::string name = node->Name(); + // If node is an image or place, load it + if (name == wwt::ImageSet || name == wwt::Place) { + saveImageFromNode(node, collection); + } + // If node is another folder, open recursively + else if (name == wwt::Folder) { + std::string newCollectionName = collection + "/"; + newCollectionName += attribute(node, wwt::Name); + + saveImagesFromXml(node, newCollectionName); + } + node = node->NextSiblingElement(); + } +} +} // namespace openspace From bd43816060025d165d387d25e3a6114fa03121f4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 3 Mar 2022 12:10:41 -0500 Subject: [PATCH 206/251] Pull request fix requested changes --- .../rendering/screenspacerenderable.h | 2 +- .../skybrowser/include/screenspaceskytarget.h | 4 +- .../skybrowser/include/targetbrowserpair.h | 14 +- modules/skybrowser/include/wwtcommunicator.h | 4 +- modules/skybrowser/include/wwtdatahandler.h | 12 +- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- .../skybrowser/src/screenspaceskybrowser.cpp | 11 +- .../skybrowser/src/screenspaceskytarget.cpp | 582 +++++++++-------- modules/skybrowser/src/targetbrowserpair.cpp | 593 +++++++++--------- modules/skybrowser/src/utility.cpp | 15 +- modules/skybrowser/src/wwtcommunicator.cpp | 16 +- modules/skybrowser/src/wwtdatahandler.cpp | 103 +-- .../webbrowser/include/screenspacebrowser.h | 4 - src/rendering/renderengine.cpp | 1 - src/rendering/screenspacerenderable.cpp | 35 +- 15 files changed, 693 insertions(+), 705 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 8fb13795f8..690e6371fe 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -80,7 +80,7 @@ public: glm::vec2 screenSpaceDimensions(); glm::vec2 upperRightCornerScreenSpace(); glm::vec2 lowerLeftCornerScreenSpace(); - bool intersection(glm::vec2 coord); + bool isIntersecting(glm::vec2 coord); void translate(glm::vec2 translation, glm::vec2 position); void setCartesianPosition(const glm::vec3& position); void setRaeFromCartesianPosition(const glm::vec3& position); diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index 866a4d9869..e826c1d0f0 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -78,8 +78,8 @@ public: void startAnimation(glm::dvec3 end, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(float deltaTime); // Display - void highlight(glm::ivec3 addition); - void removeHighlight(glm::ivec3 removal); + void highlight(const glm::ivec3& addition); + void removeHighlight(const glm::ivec3& removal); private: // Properties diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 5fe396cfa8..bcd5ee4d9c 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -46,17 +46,17 @@ public: // Target & Browser void initialize(); // Highlighting - void removeHighlight(glm::ivec3 color); - void highlight(glm::ivec3 color); + void removeHighlight(const glm::ivec3& color); + void highlight(const glm::ivec3& color); // Animation void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(double deltaTime); void incrementallyFade(float goalState, float fadeTime, float deltaTime); // Mouse interaction - bool checkMouseIntersection(glm::vec2 mousePosition); - glm::vec2 selectedScreenSpacePosition(); - bool isBrowserSelected(); - bool isTargetSelected(); + bool checkMouseIntersection(const glm::vec2& mousePosition); + glm::vec2 selectedScreenSpacePosition() const; + bool isBrowserSelected() const; + bool isTargetSelected() const; void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); void translateSelected(const glm::vec2& start, const glm::vec2& translation); void synchronizeAim(); @@ -97,7 +97,7 @@ public: ScreenSpaceSkyTarget* getTarget(); ScreenSpaceSkyBrowser* getBrowser(); - const std::deque& getSelectedImages() const; + const std::deque& selectedImages() const; // WorldWide Telescope image handling void setImageOrder(int i, int order); diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 7ef1c1adf8..e17ccf406f 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -67,9 +67,9 @@ public: void setEquatorialAim(glm::dvec2 equatorial); void setBorderColor(glm::ivec3 color); - void highlight(glm::ivec3 addition); + void highlight(const glm::ivec3& addition); // The removal parameter decides what will be removed from the border color - void removeHighlight(glm::ivec3 removal); + void removeHighlight(const glm::ivec3& removal); void updateBorderColor(); void updateAim(); diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index eaf32819b8..3351c63bd9 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -53,12 +53,12 @@ namespace openspace::wwt { namespace openspace { struct ImageData { - std::string name{ wwt::Undefined }; - std::string thumbnailUrl{ wwt::Undefined }; - std::string imageUrl{ wwt::Undefined }; - std::string credits{ wwt::Undefined }; - std::string creditsUrl{ wwt::Undefined }; - std::string collection{ wwt::Undefined }; + std::string name = wwt::Undefined; + std::string thumbnailUrl = wwt::Undefined; + std::string imageUrl = wwt::Undefined; + std::string credits = wwt::Undefined; + std::string creditsUrl = wwt::Undefined; + std::string collection = wwt::Undefined; bool hasCelestialCoords = false; float fov = 0.f; glm::dvec2 equatorialSpherical = glm::dvec2(0.0); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 08e062ec9b..ec5f88e080 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -327,7 +327,7 @@ int getTargetData(lua_State* L) { std::string id = pair->browserId(); // Convert deque to vector so ghoul can read it std::vector selectedImagesVector; - const std::deque selectedImages = pair->getSelectedImages(); + const std::deque selectedImages = pair->selectedImages(); std::for_each( selectedImages.begin(), selectedImages.end(), diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index fb9b142015..515e624d03 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -39,18 +39,17 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; - constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = - { + constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { "AnimationSpeed", "Field Of View Animation Speed", - "The factor which is multiplied with the animation of the field of view." + "A factor that determines the speed of the animation of the field of view. A " + "higher number for the factor means a faster speed." }; - constexpr const openspace::properties::Property::PropertyInfo TextureQualityInfo = - { + constexpr const openspace::properties::Property::PropertyInfo TextureQualityInfo = { "TextureQuality", "Quality of Texture", "A parameter to set the resolution of the texture. 1 is full resolution and " - "slower framerate. Lower value means lower resolution of texture and faster " + "slower frame rate. Lower value means lower resolution of texture and faster " "frame rate." }; diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index a07ea8bd6a..d76e6497cc 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -72,8 +72,8 @@ namespace { "AnimationThreshold", "Animation Threshold", "The threshold for when the target is determined to have appeared at its " - "destination. Angle in radians between the destination and the target position in" - "equatorial Cartesian coordinate system." + "destination. Angle in radians between the destination and the target position " + "in equatorial Cartesian coordinate system." }; constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = @@ -101,330 +101,326 @@ namespace { }; #include "screenspaceskytarget_codegen.cpp" - } //namespace namespace openspace { - ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) - : ScreenSpaceRenderable(dictionary) - , _showCrosshairThreshold(CrosshairThresholdInfo, 4.f, 0.1f, 70.f) - , _showRectangleThreshold(RectangleThresholdInfo, 2.f, 0.1f, 70.f) - , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) - , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) - , _lineWidth(LineWidthInfo, 25.f, 1.f, 100.f) - , _borderColor(220, 220, 220) - { - // Handle target dimension property - const Parameters p = codegen::bake(dictionary); - _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); - _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); - _stopAnimationThreshold = p.crosshairThreshold.value_or(_stopAnimationThreshold); - _animationSpeed = p.animationSpeed.value_or(_animationSpeed); +ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) + : ScreenSpaceRenderable(dictionary) + , _showCrosshairThreshold(CrosshairThresholdInfo, 4.f, 0.1f, 70.f) + , _showRectangleThreshold(RectangleThresholdInfo, 2.f, 0.1f, 70.f) + , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) + , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) + , _lineWidth(LineWidthInfo, 25.f, 1.f, 100.f) + , _borderColor(220, 220, 220) +{ + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); + _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); + _stopAnimationThreshold = p.crosshairThreshold.value_or(_stopAnimationThreshold); + _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - addProperty(_showCrosshairThreshold); - addProperty(_showRectangleThreshold); - addProperty(_stopAnimationThreshold); - addProperty(_animationSpeed); - addProperty(_lineWidth); - - // Set a unique identifier - std::string identifier; - if (dictionary.hasValue(KeyIdentifier)) { - identifier = dictionary.value(KeyIdentifier); - } - else { - identifier = "ScreenSpaceSkyTarget"; - } - identifier = makeUniqueIdentifier(identifier); - setIdentifier(identifier); - - // Set the position to screen space z - _cartesianPosition = glm::dvec3( - _cartesianPosition.value().x, - _cartesianPosition.value().y, - skybrowser::ScreenSpaceZ - ); + addProperty(_showCrosshairThreshold); + addProperty(_showRectangleThreshold); + addProperty(_stopAnimationThreshold); + addProperty(_animationSpeed); + addProperty(_lineWidth); + // Set a unique identifier + std::string identifier; + if (dictionary.hasValue(KeyIdentifier)) { + identifier = dictionary.value(KeyIdentifier); } - - ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { - SkyBrowserModule* module = global::moduleEngine->module(); - - if (module && module->getPair(identifier())) { - module->removeTargetBrowserPair(identifier()); - } + else { + identifier = "ScreenSpaceSkyTarget"; } + identifier = makeUniqueIdentifier(identifier); + setIdentifier(identifier); - // Pure virtual in the screen space renderable class and hence must be defined - void ScreenSpaceSkyTarget::bindTexture() {} + // Set the position to screen space z + _cartesianPosition = glm::dvec3( + _cartesianPosition.value().x, + _cartesianPosition.value().y, + skybrowser::ScreenSpaceZ + ); +} - bool ScreenSpaceSkyTarget::isReady() const { - return _shader != nullptr; +ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { + SkyBrowserModule* module = global::moduleEngine->module(); + + if (module && module->getPair(identifier())) { + module->removeTargetBrowserPair(identifier()); } +} - bool ScreenSpaceSkyTarget::initializeGL() { - glGenVertexArrays(1, &_vertexArray); - glGenBuffers(1, &_vertexBuffer); - createShaders(); +// Pure virtual in the screen space renderable class and hence must be defined +void ScreenSpaceSkyTarget::bindTexture() {} - return isReady(); - } +bool ScreenSpaceSkyTarget::isReady() const { + return _shader != nullptr; +} - bool ScreenSpaceSkyTarget::deinitializeGL() { - return ScreenSpaceRenderable::deinitializeGL(); - } +bool ScreenSpaceSkyTarget::initializeGL() { + glGenVertexArrays(1, &_vertexArray); + glGenBuffers(1, &_vertexBuffer); + createShaders(); - glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { - // To ensure the plane has the right ratio - // The _scale us how much of the windows height the browser covers: e.g. a browser - // that covers 0.25 of the height of the window will have scale = 0.25 - glm::vec2 floatObjectSize = glm::abs(_objectSize); - float ratio = floatObjectSize.x / floatObjectSize.y; + return isReady(); +} - glm::mat4 scale = glm::scale( - glm::mat4(1.f), - glm::vec3(ratio * _scale, _scale, 1.f) - ); +bool ScreenSpaceSkyTarget::deinitializeGL() { + return ScreenSpaceRenderable::deinitializeGL(); +} - return scale; - } +glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { + // To ensure the plane has the right ratio + // The _scale us how much of the windows height the browser covers: e.g. a browser + // that covers 0.25 of the height of the window will have scale = 0.25 + glm::vec2 floatObjectSize = glm::abs(_objectSize); + float ratio = floatObjectSize.x / floatObjectSize.y; + + glm::mat4 scale = glm::scale( + glm::mat4(1.f), + glm::vec3(ratio * _scale, _scale, 1.f) + ); + + return scale; +} - void ScreenSpaceSkyTarget::createShaders() { - _shader = global::renderEngine->buildRenderProgram( - "ScreenSpaceProgram", - absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), - absPath("${MODULE_SKYBROWSER}/shaders/target_fs.glsl") - ); +void ScreenSpaceSkyTarget::createShaders() { + _shader = global::renderEngine->buildRenderProgram( + "ScreenSpaceProgram", + absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), + absPath("${MODULE_SKYBROWSER}/shaders/target_fs.glsl") + ); - ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} - } +void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) { + _borderColor = std::move(color); +} - void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) { - _borderColor = std::move(color); - } +glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { + return _borderColor; +} - glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { - return _borderColor; - } - - void ScreenSpaceSkyTarget::render() { - bool showCrosshair = _verticalFov < _showCrosshairThreshold; - bool showRectangle = _verticalFov > _showRectangleThreshold; +void ScreenSpaceSkyTarget::render() { + bool showCrosshair = _verticalFov < _showCrosshairThreshold; + bool showRectangle = _verticalFov > _showRectangleThreshold; - glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * - localRotationMatrix() * scaleMatrix(); - float lineWidth = (_lineWidth * 0.0001f) / _scale.value(); + glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; + glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * + localRotationMatrix() * scaleMatrix(); + float lineWidth = (_lineWidth * 0.0001f) / _scale.value(); - glDisable(GL_CULL_FACE); + glDisable(GL_CULL_FACE); - _shader->activate(); - _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); - _shader->setUniform(_uniformCache.showRectangle, showRectangle); - _shader->setUniform(_uniformCache.lineWidth, lineWidth); - _shader->setUniform(_uniformCache.dimensions, glm::vec2(_objectSize)); - _shader->setUniform(_uniformCache.modelTransform, modelTransform); - _shader->setUniform(_uniformCache.lineColor, color); - _shader->setUniform( - _uniformCache.viewProj, - global::renderEngine->scene()->camera()->viewProjectionMatrix() + _shader->activate(); + _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); + _shader->setUniform(_uniformCache.showRectangle, showRectangle); + _shader->setUniform(_uniformCache.lineWidth, lineWidth); + _shader->setUniform(_uniformCache.dimensions, glm::vec2(_objectSize)); + _shader->setUniform(_uniformCache.modelTransform, modelTransform); + _shader->setUniform(_uniformCache.lineColor, color); + _shader->setUniform( + _uniformCache.viewProj, + global::renderEngine->scene()->camera()->viewProjectionMatrix() + ); + + glBindVertexArray(rendering::helper::vertexObjects.square.vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glEnable(GL_CULL_FACE); + + _shader->deactivate(); +} + +void ScreenSpaceSkyTarget::update() { + if (_isLocked) { + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera( + _lockedCoordinates ); - glBindVertexArray(rendering::helper::vertexObjects.square.vao); - glDrawArrays(GL_TRIANGLES, 0, 6); - - glEnable(GL_CULL_FACE); - - _shader->deactivate(); - } - - void ScreenSpaceSkyTarget::update() { - if (_isLocked) { - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera( - _lockedCoordinates - ); - - if (_useRadiusAzimuthElevation) { - // Keep the set radius - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d( - localCamera - ); - } - - } - } - - void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { - // To avoid flooring of the size of the target, multiply by factor of 100 - // Object size is really the pixel size so this calculation is not exact - _objectSize = glm::ivec2(dimensions * 100.f); - } - - glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { - glm::vec3 localCamera = _cartesianPosition.value(); - - if (_useRadiusAzimuthElevation) { - localCamera = raeToCartesian(_raePosition.value()); - } - - glm::dmat4 rotation = glm::inverse( - global::navigationHandler->camera()->viewRotationMatrix() - ); - glm::dvec4 position = glm::dvec4(localCamera, 1.0); - - return glm::normalize(rotation * position); - } - - // Update the scale of the target (the height of the target in relation to the - // OpenSpace window) - void ScreenSpaceSkyTarget::setScaleFromVfov(float verticalFov) { - _verticalFov = verticalFov; - glm::dvec2 fovs = skybrowser::fovWindow(); - - // Cap the scale at small scales so it is still visible - float heightRatio = verticalFov / fovs.y; - float smallestHeightRatio = _showRectangleThreshold.value() / fovs.y; - - _scale = std::max(heightRatio, smallestHeightRatio); - } - - void ScreenSpaceSkyTarget::setFovFromScale() { - glm::dvec2 fovs = skybrowser::fovWindow(); - _verticalFov = _scale * fovs.y; - } - - bool ScreenSpaceSkyTarget::isLocked() const { - return _isLocked; - } - - bool ScreenSpaceSkyTarget::isAnimated() { - return _isAnimated; - } - - void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, - bool shouldLockAfter) { - _animationStart = glm::normalize( - skybrowser::sphericalToCartesian(equatorialAim()) - ); - _animationEnd = glm::normalize(equatorialCoordsEnd); - _shouldLockAfterAnimation = shouldLockAfter; - _isAnimated = true; - _isLocked = false; - } - - void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { - // At fps that are too low, the animation stops working. Just place target instead - bool fpsTooLow = deltaTime > DeltaTimeThreshold; - // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, - _animationEnd); - bool hasArrived = smallestAngle < _stopAnimationThreshold; - - // Only keep animating when target is not at goal position - if (!hasArrived && !fpsTooLow) { - glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( - _animationStart, - _animationEnd, - deltaTime, - _animationSpeed - ); - - // Rotate target direction - glm::dvec3 equatorial = glm::dvec3(rotMat * glm::dvec4(_animationStart, 1.0)); - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(equatorial); - // Convert to screen space - if (_useRadiusAzimuthElevation) { - // Keep the radius - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); - } - - // Update position - glm::dvec3 cartesian = skybrowser::sphericalToCartesian(equatorialAim()); - _animationStart = glm::normalize(cartesian); - } - else { - // Set the exact target position - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(_animationEnd); - - if (_useRadiusAzimuthElevation) { - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); - } - - _isAnimated = false; - // Lock target when it first arrives to the position - setLock(_shouldLockAfterAnimation); - } - } - - glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const { - glm::dvec3 cartesian; - // Get the local camera coordinates of the target - if (_useRadiusAzimuthElevation) { - cartesian = raeToCartesian(_raePosition.value()); - glm::dvec3 equatorial = skybrowser::localCameraToEquatorial(cartesian); - return skybrowser::cartesianToSpherical(equatorial); - - } - else { - cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value()); - return skybrowser::cartesianToSpherical(cartesian); - } - } - - void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) { - _borderColor += addition; - } - - void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal) { - _borderColor -= removal; - } - - float ScreenSpaceSkyTarget::opacity() const { - return _opacity; - } - - glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const { - return skybrowser::cartesianToSpherical(_lockedCoordinates); - } - - void ScreenSpaceSkyTarget::setOpacity(float opacity) { - _opacity = opacity; - } - - void ScreenSpaceSkyTarget::setLock(bool isLocked) { - _isLocked = isLocked; - if (_isLocked) { - _lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim()); - } - } - - void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) { - _isAnimated = false; - _isLocked = false; - - glm::dvec3 cartesianAim = skybrowser::sphericalToCartesian(aim); - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(cartesianAim); if (_useRadiusAzimuthElevation) { // Keep the set radius glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); _raePosition = cartesianToRae(position); } else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + _cartesianPosition = skybrowser::localCameraToScreenSpace3d( + localCamera + ); } } } + +void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { + // To avoid flooring of the size of the target, multiply by factor of 100 + // Object size is really the pixel size so this calculation is not exact + _objectSize = glm::ivec2(dimensions * 100.f); +} + +glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { + glm::vec3 localCamera = _cartesianPosition.value(); + + if (_useRadiusAzimuthElevation) { + localCamera = raeToCartesian(_raePosition.value()); + } + + glm::dmat4 rotation = glm::inverse( + global::navigationHandler->camera()->viewRotationMatrix() + ); + glm::dvec4 position = glm::dvec4(localCamera, 1.0); + + return glm::normalize(rotation * position); +} + +// Update the scale of the target (the height of the target in relation to the +// OpenSpace window) +void ScreenSpaceSkyTarget::setScaleFromVfov(float verticalFov) { + _verticalFov = verticalFov; + glm::dvec2 fovs = skybrowser::fovWindow(); + + // Cap the scale at small scales so it is still visible + float heightRatio = verticalFov / fovs.y; + float smallestHeightRatio = _showRectangleThreshold.value() / fovs.y; + + _scale = std::max(heightRatio, smallestHeightRatio); +} + +void ScreenSpaceSkyTarget::setFovFromScale() { + glm::dvec2 fovs = skybrowser::fovWindow(); + _verticalFov = _scale * fovs.y; +} + +bool ScreenSpaceSkyTarget::isLocked() const { + return _isLocked; +} + +bool ScreenSpaceSkyTarget::isAnimated() { + return _isAnimated; +} + +void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, + bool shouldLockAfter) +{ + _animationStart = glm::normalize( + skybrowser::sphericalToCartesian(equatorialAim()) + ); + _animationEnd = glm::normalize(equatorialCoordsEnd); + _shouldLockAfterAnimation = shouldLockAfter; + _isAnimated = true; + _isLocked = false; +} + +void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { + // At fps that are too low, the animation stops working. Just place target instead + bool fpsTooLow = deltaTime > DeltaTimeThreshold; + // Find smallest angle between the two vectors + double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, + _animationEnd); + bool hasArrived = smallestAngle < _stopAnimationThreshold; + + // Only keep animating when target is not at goal position + if (!hasArrived && !fpsTooLow) { + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( + _animationStart, + _animationEnd, + deltaTime, + _animationSpeed + ); + + // Rotate target direction + glm::dvec3 equatorial = glm::dvec3(rotMat * glm::dvec4(_animationStart, 1.0)); + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(equatorial); + // Convert to screen space + if (_useRadiusAzimuthElevation) { + // Keep the radius + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + } + + // Update position + glm::dvec3 cartesian = skybrowser::sphericalToCartesian(equatorialAim()); + _animationStart = glm::normalize(cartesian); + } + else { + // Set the exact target position + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(_animationEnd); + + if (_useRadiusAzimuthElevation) { + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + } + + _isAnimated = false; + // Lock target when it first arrives to the position + setLock(_shouldLockAfterAnimation); + } +} + +glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const { + glm::dvec3 cartesian; + // Get the local camera coordinates of the target + if (_useRadiusAzimuthElevation) { + cartesian = raeToCartesian(_raePosition.value()); + glm::dvec3 equatorial = skybrowser::localCameraToEquatorial(cartesian); + return skybrowser::cartesianToSpherical(equatorial); + } + else { + cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value()); + return skybrowser::cartesianToSpherical(cartesian); + } +} + +void ScreenSpaceSkyTarget::highlight(const glm::ivec3& addition) { + _borderColor += addition; +} + +void ScreenSpaceSkyTarget::removeHighlight(const glm::ivec3& removal) { + _borderColor -= removal; +} + +float ScreenSpaceSkyTarget::opacity() const { + return _opacity; +} + +glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const { + return skybrowser::cartesianToSpherical(_lockedCoordinates); +} + +void ScreenSpaceSkyTarget::setOpacity(float opacity) { + _opacity = opacity; +} + +void ScreenSpaceSkyTarget::setLock(bool isLocked) { + _isLocked = isLocked; + if (_isLocked) { + _lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim()); + } +} + +void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) { + _isAnimated = false; + _isLocked = false; + + glm::dvec3 cartesianAim = skybrowser::sphericalToCartesian(aim); + glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(cartesianAim); + if (_useRadiusAzimuthElevation) { + // Keep the set radius + glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); + _raePosition = cartesianToRae(position); + } + else { + _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); + } +} +} // namespace openspace diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 965091c62b..9554abc23f 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -37,348 +37,349 @@ namespace openspace { - TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, - ScreenSpaceSkyTarget* target) - : _target(target), _browser(browser) - { - ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); - ghoul_assert(target != nullptr, "Sky target is null pointer!"); - } +TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, + ScreenSpaceSkyTarget* target) + : _target(target), _browser(browser) +{ + ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); + ghoul_assert(target != nullptr, "Sky target is null pointer!"); +} - TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) { - std::swap(_target, other._target); - std::swap(_browser, other._browser); - return *this; - - } +TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) { + std::swap(_target, other._target); + std::swap(_browser, other._browser); + return *this; +} - void TargetBrowserPair::lock() { - _target->setLock(true); - } +void TargetBrowserPair::lock() { + _target->setLock(true); +} - void TargetBrowserPair::unlock() { - _target->setLock(false); - } +void TargetBrowserPair::unlock() { + _target->setLock(false); +} - void TargetBrowserPair::setImageOrder(int i, int order) { - _browser->setImageOrder(i, order); - } +void TargetBrowserPair::setImageOrder(int i, int order) { + _browser->setImageOrder(i, order); +} - void TargetBrowserPair::removeHighlight(glm::ivec3 color) { - _target->removeHighlight(color); - _browser->removeHighlight(color); - } +void TargetBrowserPair::removeHighlight(const glm::ivec3& color) { + _target->removeHighlight(color); + _browser->removeHighlight(color); +} - void TargetBrowserPair::highlight(glm::ivec3 color) { - _browser->highlight(color); - _target->highlight(color); - } +void TargetBrowserPair::highlight(const glm::ivec3& color) { + _browser->highlight(color); + _target->highlight(color); +} - bool TargetBrowserPair::isTargetFadeFinished(float goalState) const { - // Is fading finished? - float targetDiff = abs(_target->opacity() - goalState); +bool TargetBrowserPair::isTargetFadeFinished(float goalState) const { + float targetDiff = abs(_target->opacity() - goalState); - return targetDiff < FadeThreshold; + return targetDiff < FadeThreshold; +} + +bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const { + float browserDiff = abs(_browser->opacity() - goalState); + return browserDiff < FadeThreshold; +} + +bool TargetBrowserPair::checkMouseIntersection(const glm::vec2& mousePosition) { + bool onBrowser = _browser->isIntersecting(mousePosition); + bool onTarget = _target->isIntersecting(mousePosition); + if (onBrowser) { + _selected = _browser; + _isSelectedBrowser = true; } - - bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const { - float browserDiff = abs(_browser->opacity() - goalState); - return browserDiff < FadeThreshold; + else if (onTarget) { + _selected = _target; + _isSelectedBrowser = false; } - - bool TargetBrowserPair::checkMouseIntersection(glm::vec2 mousePosition) { - bool onBrowser = _browser->intersection(mousePosition); - bool onTarget = _target->intersection(mousePosition); - if (onBrowser) { - _selected = _browser; - _isSelectedBrowser = true; - } - else if (onTarget) { - _selected = _target; - _isSelectedBrowser = false; - } - else { - _selected = nullptr; - _isSelectedBrowser = false; - } - return onBrowser || onTarget; + else { + _selected = nullptr; + _isSelectedBrowser = false; } + return onBrowser || onTarget; +} - glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() { - return _selected->screenSpacePosition(); - } +glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() const { + return _selected->screenSpacePosition(); +} - bool TargetBrowserPair::isBrowserSelected() { - return _isSelectedBrowser; - } +bool TargetBrowserPair::isBrowserSelected() const { + return _isSelectedBrowser; +} - bool TargetBrowserPair::isTargetSelected() { - return _selected && !_isSelectedBrowser; - } +bool TargetBrowserPair::isTargetSelected() const { + return _selected && !_isSelectedBrowser; +} - void TargetBrowserPair::fineTuneTarget(const glm::vec2& start, - const glm::vec2& translation) - { - glm::vec2 fineTune = _browser->fineTuneVector(translation); +// The fine tune of the target is a way to "drag and drop" the target with right click +// drag on the sky browser window. This is to be able to drag the target around when it +// has a very small field of view +void TargetBrowserPair::fineTuneTarget(const glm::vec2& start, + const glm::vec2& translation) +{ + glm::vec2 fineTune = _browser->fineTuneVector(translation); + openspace::global::scriptEngine->queueScript( + "openspace.skybrowser.translateScreenSpaceRenderable(\"" + targetId() + "\"," + + std::to_string(start.x) + "," + std::to_string(start.y) + "," + + std::to_string(fineTune.x) + "," + std::to_string(fineTune.y) + ")", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + +void TargetBrowserPair::translateSelected(const glm::vec2& start, + const glm::vec2& trans) +{ + if (this && _selected) { + std::string id = _selected->identifier(); openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.translateScreenSpaceRenderable(\"" + targetId() + "\"," + "openspace.skybrowser.translateScreenSpaceRenderable(\"" + id + "\"," + std::to_string(start.x) + "," + std::to_string(start.y) + "," - + std::to_string(fineTune.x) + "," + std::to_string(fineTune.y) + ")", + + std::to_string(trans.x) + "," + std::to_string(trans.y) + ")", scripting::ScriptEngine::RemoteScripting::Yes ); } +} - void TargetBrowserPair::translateSelected(const glm::vec2& start, - const glm::vec2& trans) - { - if (this && _selected) { - std::string id = _selected->identifier(); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.translateScreenSpaceRenderable(\"" + id + "\"," - + std::to_string(start.x) + "," + std::to_string(start.y) + "," - + std::to_string(trans.x) + "," + std::to_string(trans.y) + ")", - scripting::ScriptEngine::RemoteScripting::Yes - ); +void TargetBrowserPair::synchronizeAim() { + if (!_target->isAnimated()) { + glm::dvec2 aim; + // To remove the lag effect when moving the camera while having a locked + // target, send the locked coordinates to wwt + if (_target->isLocked()) { + aim = _target->lockedCoordinates(); + } + else { + aim = _target->equatorialAim(); } - } - - void TargetBrowserPair::synchronizeAim() { - if (!_target->isAnimated()) { - glm::dvec2 aim; - // To remove the lag effect when moving the camera while having a locked - // target, send the locked coordinates to wwt - if (_target->isLocked()) { - aim = _target->lockedCoordinates(); - } - else { - aim = _target->equatorialAim(); - } - _browser->setEquatorialAim(aim); - _target->setScaleFromVfov(_browser->verticalFov()); - } - } - - void TargetBrowserPair::setEnabled(bool enable) { - _browser->setEnabled(enable); - _target->setEnabled(enable); - } - - bool TargetBrowserPair::isEnabled() const { - return _target->isEnabled() && _browser->isEnabled(); - } - - bool TargetBrowserPair::isLocked() const { - return _target->isLocked(); - } - - void TargetBrowserPair::initialize() { - _target->setColor(_browser->borderColor()); - _target->setDimensions(_browser->browserPixelDimensions()); - _target->setScaleFromVfov(_browser->verticalFov()); - _browser->updateBorderColor(); - } - - glm::ivec3 TargetBrowserPair::borderColor() const { - return _browser->borderColor(); - } - - glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const { - return _target->equatorialAim(); - } - - glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const { - return _target->directionGalactic(); - } - - std::string TargetBrowserPair::browserGuiName() const { - return _browser->guiName(); - } - - std::string TargetBrowserPair::browserId() const { - return _browser->identifier(); - } - - std::string TargetBrowserPair::targetId() const { - return _target->identifier(); - } - - std::string TargetBrowserPair::selectedId() { - return _selected->identifier(); - } - - glm::vec2 TargetBrowserPair::size() const { - return _browser->size(); - } - - float TargetBrowserPair::verticalFov() const { - return _browser->verticalFov(); - } - - const std::deque& TargetBrowserPair::getSelectedImages() const { - return _browser->getSelectedImages(); - } - - void TargetBrowserPair::selectImage(const ImageData& image, int i) { - // Load image into browser - _browser->displayImage(image.imageUrl, i); - - // If the image has coordinates, move the target - if (image.hasCelestialCoords) { - - // Animate the target to the image coordinate position - unlock(); - startAnimation(image.equatorialCartesian, image.fov, true); - } - } - - void TargetBrowserPair::removeSelectedImage(int i) { - _browser->removeSelectedImage(i); - } - - void TargetBrowserPair::loadImageCollection(const std::string& collection) { - _browser->loadImageCollection(collection); - } - - void TargetBrowserPair::setImageOpacity(int i, float opacity) { - _browser->setImageOpacity(i, opacity); - } - - void TargetBrowserPair::hideChromeInterface(bool shouldHide) { - _browser->hideChromeInterface(shouldHide); - } - - void TargetBrowserPair::sendIdToBrowser() { - _browser->setIdInBrowser(); - } - - void TargetBrowserPair::updateBrowserSize() { - _browser->updateBrowserSize(); - } - - void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { - _browser->setIsSyncedWithWwt(isSynced); - } - - void TargetBrowserPair::setVerticalFov(float vfov) { - _verticalFov = vfov; - _browser->setVerticalFov(vfov); - _target->setScaleFromVfov(vfov); - } - - void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) { - _equatorialAim = aim; - _target->setEquatorialAim(aim); _browser->setEquatorialAim(aim); + _target->setScaleFromVfov(_browser->verticalFov()); } +} - void TargetBrowserPair::setBorderColor(const glm::ivec3& color) { - _borderColor = color; - _target->setColor(color); - _browser->setBorderColor(color); - } +void TargetBrowserPair::setEnabled(bool enable) { + _browser->setEnabled(enable); + _target->setEnabled(enable); +} - void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) { - _dimensions = dimensions; - _target->setDimensions(dimensions); - _browser->setScreenSpaceSize(dimensions); - } +bool TargetBrowserPair::isEnabled() const { + return _target->isEnabled() && _browser->isEnabled(); +} - void TargetBrowserPair::setVerticalFovWithScroll(float scroll) { - _browser->setVerticalFovWithScroll(scroll); - } +bool TargetBrowserPair::isLocked() const { + return _target->isLocked(); +} - void TargetBrowserPair::setSelectedWithId(const std::string& id) { - if (browserId() == id) { - _isSelectedBrowser = true; - _selected = _browser; - } - else if (targetId() == id) { - _isSelectedBrowser = false; - _selected = _target; - } - else { - _isSelectedBrowser = false; - _selected = nullptr; - } - } +void TargetBrowserPair::initialize() { + _target->setColor(_browser->borderColor()); + _target->setDimensions(_browser->browserPixelDimensions()); + _target->setScaleFromVfov(_browser->verticalFov()); + _browser->updateBorderColor(); +} - void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { - // Animate the target before the field of view starts to animate - if (_target->isAnimated()) { - _target->incrementallyAnimateToCoordinate(static_cast(deltaTime)); - } - else if (_browser->isAnimated()) { - _browser->incrementallyAnimateToFov(static_cast(deltaTime)); - } - } +glm::ivec3 TargetBrowserPair::borderColor() const { + return _browser->borderColor(); +} - void TargetBrowserPair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, - bool shouldLockAfter) - { - _target->startAnimation(equatorialCoords, shouldLockAfter); - _browser->startFovAnimation(fovEnd); - } +glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const { + return _target->equatorialAim(); +} - void TargetBrowserPair::centerTargetOnScreen() { - // Animate the target to the center of the screen +glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const { + return _target->directionGalactic(); +} + +std::string TargetBrowserPair::browserGuiName() const { + return _browser->guiName(); +} + +std::string TargetBrowserPair::browserId() const { + return _browser->identifier(); +} + +std::string TargetBrowserPair::targetId() const { + return _target->identifier(); +} + +std::string TargetBrowserPair::selectedId() { + return _selected->identifier(); +} + +glm::vec2 TargetBrowserPair::size() const { + return _browser->size(); +} + +float TargetBrowserPair::verticalFov() const { + return _browser->verticalFov(); +} + +const std::deque& TargetBrowserPair::selectedImages() const { + return _browser->getSelectedImages(); +} + +void TargetBrowserPair::selectImage(const ImageData& image, int i) { + // Load image into browser + _browser->displayImage(image.imageUrl, i); + + // If the image has coordinates, move the target + if (image.hasCelestialCoords) { + + // Animate the target to the image coordinate position unlock(); - // Get camera direction in celestial spherical coordinates - glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); - // Keep the current fov - float currentFov = verticalFov(); - startAnimation(viewDirection, currentFov, false); + startAnimation(image.equatorialCartesian, image.fov, true); } +} - bool TargetBrowserPair::hasFinishedFading(float goalState) const { - return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); +void TargetBrowserPair::removeSelectedImage(int i) { + _browser->removeSelectedImage(i); +} + +void TargetBrowserPair::loadImageCollection(const std::string& collection) { + _browser->loadImageCollection(collection); +} + +void TargetBrowserPair::setImageOpacity(int i, float opacity) { + _browser->setImageOpacity(i, opacity); +} + +void TargetBrowserPair::hideChromeInterface(bool shouldHide) { + _browser->hideChromeInterface(shouldHide); +} + +void TargetBrowserPair::sendIdToBrowser() { + _browser->setIdInBrowser(); +} + +void TargetBrowserPair::updateBrowserSize() { + _browser->updateBrowserSize(); +} + +void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { + _browser->setIsSyncedWithWwt(isSynced); +} + +void TargetBrowserPair::setVerticalFov(float vfov) { + _verticalFov = vfov; + _browser->setVerticalFov(vfov); + _target->setScaleFromVfov(vfov); +} + +void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) { + _equatorialAim = aim; + _target->setEquatorialAim(aim); + _browser->setEquatorialAim(aim); +} + +void TargetBrowserPair::setBorderColor(const glm::ivec3& color) { + _borderColor = color; + _target->setColor(color); + _browser->setBorderColor(color); +} + +void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) { + _dimensions = dimensions; + _target->setDimensions(dimensions); + _browser->setScreenSpaceSize(dimensions); +} + +void TargetBrowserPair::setVerticalFovWithScroll(float scroll) { + _browser->setVerticalFovWithScroll(scroll); +} + +void TargetBrowserPair::setSelectedWithId(const std::string& id) { + if (browserId() == id) { + _isSelectedBrowser = true; + _selected = _browser; } - - bool TargetBrowserPair::isFacingCamera() const { - return _browser->isFacingCamera() || _target->isFacingCamera(); + else if (targetId() == id) { + _isSelectedBrowser = false; + _selected = _target; } - - bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const { - return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); + else { + _isSelectedBrowser = false; + _selected = nullptr; } +} - ScreenSpaceSkyTarget* TargetBrowserPair::getTarget() { - return _target; +void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { + // Animate the target before the field of view starts to animate + if (_target->isAnimated()) { + _target->incrementallyAnimateToCoordinate(static_cast(deltaTime)); } - - ScreenSpaceSkyBrowser* TargetBrowserPair::getBrowser() { - return _browser; + else if (_browser->isAnimated()) { + _browser->incrementallyAnimateToFov(static_cast(deltaTime)); } +} - void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, - float deltaTime) - { - float opacityDelta = static_cast(deltaTime / fadeTime); - if (_target->opacity() > goalState) { - opacityDelta *= -1.f; - } +void TargetBrowserPair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, + bool shouldLockAfter) +{ + _target->startAnimation(equatorialCoords, shouldLockAfter); + _browser->startFovAnimation(fovEnd); +} + +void TargetBrowserPair::centerTargetOnScreen() { + // Animate the target to the center of the screen + unlock(); + // Get camera direction in celestial spherical coordinates + glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); + // Keep the current fov + float currentFov = verticalFov(); + startAnimation(viewDirection, currentFov, false); +} + +bool TargetBrowserPair::hasFinishedFading(float goalState) const { + return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); +} + +bool TargetBrowserPair::isFacingCamera() const { + return _browser->isFacingCamera() || _target->isFacingCamera(); +} + +bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const { + return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); +} + +ScreenSpaceSkyTarget* TargetBrowserPair::getTarget() { + return _target; +} + +ScreenSpaceSkyBrowser* TargetBrowserPair::getBrowser() { + return _browser; +} + +void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, + float deltaTime) +{ + float opacityDelta = static_cast(deltaTime / fadeTime); + if (_target->opacity() > goalState) { + opacityDelta *= -1.f; + } - if (!isTargetFadeFinished(goalState)) { - _target->setOpacity(_target->opacity() + opacityDelta); - } - else { - _target->setOpacity(goalState); - } + if (!isTargetFadeFinished(goalState)) { + _target->setOpacity(_target->opacity() + opacityDelta); + } + else { + _target->setOpacity(goalState); + } - if (!isBrowserFadeFinished(goalState)) { - _browser->setOpacity(_browser->opacity() + opacityDelta); - } - else { - _browser->setOpacity(goalState); - } + if (!isBrowserFadeFinished(goalState)) { + _browser->setOpacity(_browser->opacity() + opacityDelta); } + else { + _browser->setOpacity(goalState); + } +} - bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { - return lhs._target == rhs._target && lhs._browser == rhs._browser; - } +bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { + return lhs._target == rhs._target && lhs._browser == rhs._browser; +} - bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { - return !(lhs == rhs); - } +bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { + return !(lhs == rhs); +} } // namespace openspace diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index c98260cdf1..3060b05497 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -34,7 +34,6 @@ namespace openspace::skybrowser { // Converts from spherical coordinates in the unit of degrees to cartesian coordianates glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) { - glm::dvec2 coordsRadians = glm::radians(coords); glm::dvec3 cartesian = glm::dvec3( @@ -100,8 +99,7 @@ glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) { return skybrowser::galacticToEquatorial(galactic); } -glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) -{ +glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) { // Transform equatorial J2000 to galactic coord with infinite radius glm::dvec3 galactic = equatorialToGalactic(coords); glm::dvec3 localCamera = galacticToLocalCamera(galactic); @@ -161,7 +159,6 @@ bool isCoordinateInView(const glm::dvec3& equatorial) { bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f && coordsScreen.z < 0; - // If the coordinate is not in view, rotate camera return isCoordInView; } @@ -187,17 +184,15 @@ glm::dvec2 fovWindow() { return OpenSpaceFOV; } -double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { - +double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { // Find smallest angle between the two vectors double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); return std::acos(cos); } -glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, - const glm::dvec3& end, double deltaTime, - double speedFactor) { - +glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, + double deltaTime, double speedFactor) +{ double smallestAngle = angleBetweenVectors(start, end); // Calculate rotation this frame double rotationAngle = smallestAngle * deltaTime * speedFactor; diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 4336074f47..6237f7e63b 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -99,11 +99,11 @@ void WwtCommunicator::setBorderColor(glm::ivec3 color) { _borderColorIsDirty = true; } -void WwtCommunicator::highlight(glm::ivec3 addition) { +void WwtCommunicator::highlight(const glm::ivec3& addition) { setWebpageBorderColor(_borderColor + addition); } -void WwtCommunicator::removeHighlight(glm::ivec3 removal) { +void WwtCommunicator::removeHighlight(const glm::ivec3& removal) { setWebpageBorderColor(_borderColor - removal); } @@ -221,12 +221,12 @@ float WwtCommunicator::verticalFov() const { // WWT messages ghoul::Dictionary WwtCommunicator::moveCameraMessage(const glm::dvec2& celestCoords, - double fov, double roll, - bool shouldMoveInstantly) { + double fov, double roll, + bool shouldMoveInstantly) +{ using namespace std::string_literals; ghoul::Dictionary msg; - // Create message msg.setValue("event", "center_on_coordinates"s); msg.setValue("ra", celestCoords.x); msg.setValue("dec", celestCoords.y); @@ -257,7 +257,8 @@ ghoul::Dictionary WwtCommunicator::setForegroundMessage(const std::string& name) } ghoul::Dictionary WwtCommunicator::addImageMessage(const std::string& id, - const std::string& url) { + const std::string& url) +{ using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_create"s); @@ -279,7 +280,8 @@ ghoul::Dictionary WwtCommunicator::removeImageMessage(const std::string& imageId } ghoul::Dictionary WwtCommunicator::setImageOpacityMessage(const std::string& imageId, - double opacity) { + double opacity) +{ using namespace std::string_literals; ghoul::Dictionary msg; msg.setValue("event", "image_layer_set"s); diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 0f3d8944b7..7382a8a10f 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -40,16 +40,14 @@ namespace { namespace openspace { bool hasAttribute(const tinyxml2::XMLElement* element, const std::string_view& name) { - return element->FindAttribute(std::string(name).c_str()); + return element->FindAttribute(std::string(name).c_str()); } std::string attribute(const tinyxml2::XMLElement* element, const std::string& name) { if (hasAttribute(element, name)) { return element->FindAttribute(name.c_str())->Value(); } - else { - return wwt::Undefined; - } + return wwt::Undefined; } // Parsing and downloading of wtml files @@ -70,15 +68,26 @@ bool directoryExists(const std::filesystem::path& path) { std::string createSearchableString(std::string str) { // Remove white spaces and all special characters - str.erase(std::remove_if(str.begin(), str.end(), [](char c) { - const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); - return !isNumberOrLetter; - }), - std::end(str)); + str.erase( + std::remove_if( + str.begin(), + str.end(), + [](char c) { + const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c); + return !isNumberOrLetter; + } + ), + str.end() + ); // Make the word lower case - std::transform(str.begin(), str.end(), str.begin(), [](char c) { - return std::tolower(c); - }); + std::transform( + str.begin(), + str.end(), + str.begin(), + [](char c) { + return std::tolower(c); + } + ); return str; } @@ -94,7 +103,6 @@ tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node, tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, const std::string& name) { - tinyxml2::XMLElement* child = node->FirstChildElement(); tinyxml2::XMLElement* imageSet = nullptr; @@ -122,9 +130,7 @@ std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, if (imageSetChild && imageSetChild->GetText()) { return imageSetChild->GetText(); } - else { - return wwt::Undefined; - } + return wwt::Undefined; } std::string getUrlFromPlace(tinyxml2::XMLElement* place) { @@ -141,10 +147,8 @@ std::string getUrlFromPlace(tinyxml2::XMLElement* place) { if (imageSet) { return getChildNodeContentFromImageSet(imageSet, wwt::ThumbnailUrl); } - else { - // If it doesn't contain an ImageSet, it doesn't have an url - return wwt::Undefined; - } + // If it doesn't contain an ImageSet, it doesn't have an url + return wwt::Undefined; } @@ -152,7 +156,6 @@ void parseWtmlsFromDisc(std::vector& _xmls, const std::filesystem::path& directory) { for (const auto& entry : std::filesystem::directory_iterator(directory)) { - tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument(); std::string path = entry.path().u8string(); tinyxml2::XMLError successCode = document->LoadFile(path.c_str()); @@ -179,7 +182,9 @@ bool downloadAndParseWtmlFilesFromUrl(std::vector& _xmls // Download file from url std::filesystem::path file = directory.string() + fileName + ".aspx"; if (!downloadFile(url, file)) { - LINFO("Couldn't download file " + url + " to directory " + directory.string()); + LINFO( + fmt::format("Couldn't download file '{}' to directory '{}'", url, directory) + ); return false; } @@ -199,13 +204,11 @@ bool downloadAndParseWtmlFilesFromUrl(std::vector& _xmls if (!folderExists || folderContainNoUrls) { _xmls.push_back(doc); LINFO("Saving " + url); - return true; } // Iterate through all the folders in the XML file while (element && std::string(element->Value()) == wwt::Folder) { - // If folder contains urls, download and parse those urls if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) { std::string url = attribute(element, wwt::Url); @@ -223,8 +226,8 @@ WwtDataHandler::~WwtDataHandler() { } void WwtDataHandler::loadImages(const std::string& root, - const std::filesystem::path& directory) { - + const std::filesystem::path& directory) +{ // Collect the wtml files, either by reading from disc or from a url if (directoryExists(directory)) { parseWtmlsFromDisc(_xmls, directory); @@ -243,36 +246,37 @@ void WwtDataHandler::loadImages(const std::string& root, } // Sort images in alphabetical order - std::sort(_images.begin(), _images.end(), [](ImageData& a, ImageData& b) { - // If the first character in the names are lowercase, make it upper case - if (std::islower(a.name[0])) { - // convert string to upper case - a.name[0] = ::toupper(a.name[0]); + std::sort( + _images.begin(), + _images.end(), + [](ImageData& a, ImageData& b) { + // If the first character in the names are lowercase, make it upper case + if (std::islower(a.name[0])) { + // convert string to upper case + a.name[0] = ::toupper(a.name[0]); + } + if (std::islower(b.name[0])) { + b.name[0] = ::toupper(b.name[0]); + } + return a.name < b.name; } - if (std::islower(b.name[0])) { - b.name[0] = ::toupper(b.name[0]); - } - return a.name < b.name; - }); + ); - LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope " - "images."); + LINFO(fmt::format("Loaded {} WorldWide Telescope images.", _images.size())); } -int WwtDataHandler::nLoadedImages() const -{ +int WwtDataHandler::nLoadedImages() const { return _images.size(); } -const ImageData& WwtDataHandler::getImage(const int i) const -{ +const ImageData& WwtDataHandler::getImage(const int i) const { ghoul_assert(i < _images.size(), "Index outside of image vector boundaries!"); return _images[i]; } -void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, - std::string collection) { - +void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, + std::string collection) +{ // Collect the image set of the node. The structure is different depending on if // it is a Place or an ImageSet std::string thumbnailUrl = { wwt::Undefined }; @@ -282,7 +286,7 @@ void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, if (type == wwt::ImageSet) { thumbnailUrl = getChildNodeContentFromImageSet(node, wwt::ThumbnailUrl); imageSet = node; - } // Place + } else if (type == wwt::Place) { thumbnailUrl = getUrlFromPlace(node); imageSet = getChildNode(node, wwt::ImageSet); @@ -325,7 +329,7 @@ void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, } // Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6 - float fov{ 0.f }; + float fov = 0.f; if (hasAttribute(node, wwt::ZoomLevel)) { fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0f; } @@ -346,10 +350,9 @@ void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node, _images.push_back(image); } -void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root, - std::string collection) +void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root, + std::string collection) { - // Get direct child of node called Place using namespace tinyxml2; XMLElement* node = root->FirstChildElement(); diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 0803f4de26..417706e9a8 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -78,7 +78,6 @@ protected: std::unique_ptr _texture; private: - class ScreenSpaceRenderHandler : public WebRenderHandler { public: void draw() override; @@ -93,16 +92,13 @@ private: void bindTexture() override; properties::StringProperty _url; - properties::TriggerProperty _reload; - CefRefPtr _keyboardHandler; bool _isUrlDirty = false; bool _isDimensionsDirty = false; }; - } // namespace openspace #endif // __OPENSPACE_MODULE_WEBBROWSER___SCREEN_SPACE_BROWSER___H__ diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 77a3769c98..0e9b71d653 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -1133,7 +1133,6 @@ void RenderEngine::removeScreenSpaceRenderable(ScreenSpaceRenderable* s) { ); if (it != global::screenSpaceRenderables->end()) { - global::eventEngine->publishEvent(s); s->deinitializeGL(); s->deinitialize(); diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 9d8c9c8aa1..0e5b476b22 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -476,18 +476,19 @@ void ScreenSpaceRenderable::update() {} bool ScreenSpaceRenderable::isEnabled() const { return _enabled; } -bool ScreenSpaceRenderable::isUsingRaeCoords() const -{ + +bool ScreenSpaceRenderable::isUsingRaeCoords() const { return _useRadiusAzimuthElevation; } -bool ScreenSpaceRenderable::isFacingCamera() const -{ + +bool ScreenSpaceRenderable::isFacingCamera() const { return _faceCamera; } -void ScreenSpaceRenderable::setEnabled(bool isEnabled) -{ + +void ScreenSpaceRenderable::setEnabled(bool isEnabled) { _enabled = isEnabled; } + float ScreenSpaceRenderable::depth() { return _useRadiusAzimuthElevation ? _raePosition.value().x : @@ -538,8 +539,9 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { return scale; } -glm::vec2 ScreenSpaceRenderable::screenSpacePosition() { - return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y); + +glm::vec2 ScreenSpaceRenderable::screenSpacePosition() { + return glm::vec2(_cartesianPosition.value()); } glm::vec2 ScreenSpaceRenderable::screenSpaceDimensions() { @@ -555,7 +557,7 @@ glm::vec2 ScreenSpaceRenderable::lowerLeftCornerScreenSpace() { return screenSpacePosition() - (screenSpaceDimensions() / 2.0f); } -bool ScreenSpaceRenderable::intersection(glm::vec2 coord) { +bool ScreenSpaceRenderable::isIntersecting(glm::vec2 coord) { bool isUnderTopBorder = coord.x < upperRightCornerScreenSpace().x; bool isLeftToRightBorder = coord.y < upperRightCornerScreenSpace().y; bool isRightToLeftBorder = coord.x > lowerLeftCornerScreenSpace().x; @@ -574,18 +576,15 @@ void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) _cartesianPosition = translationMatrix * origin; } -void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) -{ +void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) { _cartesianPosition = position; } -void ScreenSpaceRenderable::setRaeFromCartesianPosition(const glm::vec3& position) -{ +void ScreenSpaceRenderable::setRaeFromCartesianPosition(const glm::vec3& position) { _raePosition = cartesianToRae(position); } -glm::vec3 ScreenSpaceRenderable::raePosition() const -{ +glm::vec3 ScreenSpaceRenderable::raePosition() const { return _raePosition; } @@ -623,13 +622,11 @@ glm::mat4 ScreenSpaceRenderable::localRotationMatrix() { return rotation * glm::mat4(glm::quat(glm::vec3(pitch, yaw, roll))); } -glm::vec3 ScreenSpaceRenderable::raeToCartesian(const glm::vec3& rae) const -{ +glm::vec3 ScreenSpaceRenderable::raeToCartesian(const glm::vec3& rae) const { return sphericalToCartesian(raeToSpherical(rae)); } -glm::vec3 ScreenSpaceRenderable::cartesianToRae(const glm::vec3& cartesian) const -{ +glm::vec3 ScreenSpaceRenderable::cartesianToRae(const glm::vec3& cartesian) const { return sphericalToRae(cartesianToSpherical(cartesian)); } From ec201d954ac7614c5d53f1d14d832c5b95f906aa Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 4 Mar 2022 12:30:12 -0500 Subject: [PATCH 207/251] Pull request code style fixes --- data/assets/hoverCircle.asset | 4 +- modules/skybrowser/include/browser.h | 1 - .../skybrowser/include/screenspaceskytarget.h | 6 +- .../skybrowser/include/targetbrowserpair.h | 21 ++-- modules/skybrowser/include/utility.h | 112 +++++++++++++++++- modules/skybrowser/include/wwtcommunicator.h | 5 +- modules/skybrowser/include/wwtdatahandler.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 15 +-- .../skybrowser/src/screenspaceskybrowser.cpp | 1 + .../skybrowser/src/screenspaceskytarget.cpp | 8 +- modules/skybrowser/src/targetbrowserpair.cpp | 4 +- 11 files changed, 138 insertions(+), 41 deletions(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index 54fc5fd2ce..2a00549c29 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -6,11 +6,11 @@ local circle = { Name = "HoverCircle", FaceCamera = false, UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = {1.0, 0.0, 0.0}, -- use for dome + RadiusAzimuthElevation = { 1.0, 0.0, 0.0 }, -- use for dome Scale = 0.025, Enabled = false, TexturePath = "${ASSETS}/circle.png", - CartesianPosition = { 0, 0, -2.1 }, + CartesianPosition = { 0, 0, -2.1 }, }; asset.onInitialize(function () diff --git a/modules/skybrowser/include/browser.h b/modules/skybrowser/include/browser.h index f33d1e6be2..cb79d09428 100644 --- a/modules/skybrowser/include/browser.h +++ b/modules/skybrowser/include/browser.h @@ -73,7 +73,6 @@ public: void updateBrowserSize(); - // Getters glm::vec2 browserPixelDimensions() const; float browserRatio() const; void setCallbackDimensions(const std::function& function); diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index e826c1d0f0..ea6e6aa57c 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -38,7 +38,6 @@ namespace openspace { class ScreenSpaceSkyBrowser; class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { - public: constexpr static const float DeltaTimeThreshold = 0.03f; @@ -74,7 +73,7 @@ public: bool isLocked() const; // Animation - bool isAnimated(); + bool isAnimated() const; void startAnimation(glm::dvec3 end, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(float deltaTime); // Display @@ -112,7 +111,6 @@ private: glm::dvec3 _animationEnd; // Cartesian equatorial coordinates glm::dvec3 _animationStart; // Cartesian equatorial coordinates }; -} +} // namespace openspace #endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ - diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index bcd5ee4d9c..440e2bf1b1 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -38,7 +38,6 @@ class ImageData; class TargetBrowserPair { public: constexpr static const float FadeThreshold = 0.01f; - constexpr static const double AnimationThreshold = 0.0001f; TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); TargetBrowserPair& operator=(TargetBrowserPair other); @@ -95,8 +94,8 @@ public: std::string selectedId(); glm::vec2 size() const; - ScreenSpaceSkyTarget* getTarget(); - ScreenSpaceSkyBrowser* getBrowser(); + ScreenSpaceSkyTarget* target() const; + ScreenSpaceSkyBrowser* browser() const; const std::deque& selectedImages() const; // WorldWide Telescope image handling @@ -117,18 +116,18 @@ private: bool isBrowserFadeFinished(float goalState) const; // Selection - ScreenSpaceRenderable* _selected{ nullptr }; - bool _isSelectedBrowser{ false }; + ScreenSpaceRenderable* _selected = nullptr; + bool _isSelectedBrowser = false; // Target and browser - ScreenSpaceSkyTarget* _target{ nullptr }; - ScreenSpaceSkyBrowser* _browser{ nullptr }; + ScreenSpaceSkyTarget* _target = nullptr; + ScreenSpaceSkyBrowser* _browser = nullptr; // Shared properties between the target and the browser - float _verticalFov{ 70.0f }; - glm::dvec2 _equatorialAim{ 0.0 }; - glm::ivec3 _borderColor{ 255 }; - glm::vec2 _dimensions{ 0.5f, 0.5f }; + float _verticalFov = 70.f; + glm::dvec2 _equatorialAim = glm::dvec2(0.0); + glm::ivec3 _borderColor = glm::ivec3(255); + glm::vec2 _dimensions = glm::vec2(0.5f); }; } // namespace openspace diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 37756b13f9..b2fc32fa8c 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -30,7 +30,7 @@ namespace openspace::skybrowser { // Constants constexpr const double ScreenSpaceZ = -2.1; -constexpr const glm::dvec3 NorthPole = { 0.0 , 0.0 , 1.0 }; +constexpr const glm::dvec3 NorthPole = { 0.0, 0.0, 1.0 }; constexpr const double CelestialSphereRadius = std::numeric_limits::max(); // Conversion matrix - J2000 equatorial <-> galactic @@ -44,35 +44,135 @@ const glm::dmat3 conversionMatrix = glm::dmat3({ // Galactic coordinates are projected onto the celestial sphere // Equatorial coordinates are unit length // Conversion spherical <-> Cartesian +/** + * Converts from Cartesian coordinates to spherical coordinates with unit length. + * \param coords Cartesian coordinates + * \return Spherical coordinates with unit length in degrees + */ glm::dvec2 cartesianToSpherical(const glm::dvec3& coords); +/** + * Converts from spherical coordinates to Cartesian coordinates with unit length. + * \param coords Spherical coordinates in degrees + * \return Cartesian coordinates with unit length + */ glm::dvec3 sphericalToCartesian(const glm::dvec2& coords); // Conversion J2000 equatorial <-> galactic +/** + * Converts from Cartesian galactic coordinates to Cartesian equatorial coordinates in epoch + * J2000 with unit length. + * \param coords Cartesian galactic coordinates + * \return Cartesian equatorial coordinates in the epoch of J2000 with unit length + */ glm::dvec3 galacticToEquatorial(const glm::dvec3& coords); +/** + * Converts from Cartesian equatorial coordinates to Cartesian galactic + * coordinates. The galactic coordinates vector has the length of the radius of the + * Celestial sphere. + * \param coords Cartesian equatorial coordinates + * \return Cartesian galactic coordinates placed on the Celestial sphere + */ glm::dvec3 equatorialToGalactic(const glm::dvec3& coords); -// Conversion to screen space from local camera / pixels +// Conversion to screenspace from local camera / pixels +/** + * Converts from local camera coordinates to screenspace coordinates. The screenspace + * coordinates are placed on the screenspace plane which has the z-coordinate as -2.1. + * \param coords Cartesian local camera coordinates + * \return Cartesian galactic coordinates placed on the Celestial sphere + */ glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords); +/** + * Converts from pixel coordinates to screenspace coordinates in 2D. + * \param mouseCoordinate Pixel coordinate + * \return Cartesian ScreenSpace coordinate + */ glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate); // Conversion local camera space <-> galactic / equatorial +/** + * Converts from Cartesian equatorial coordinates in epoch J2000 to local camera space. + * \param coords Cartesian equatorial coordinates in epoch J2000 + * \return Local camera coordinates with unit length + */ glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords); -glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords); -glm::dvec3 localCameraToGalactic(const glm::dvec3& coords); -glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); +/** + * Converts from Cartesian galactic coordinates to local camera space with unit length. + * \param coords Cartesian galactic coordinates + * \return Cartesian local camera coordinates with unit length + */ +glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords); +/** + * Converts from Cartesian local camera coordinates to galactic coordinates. + * \param coords Cartesian local camera coordinates + * \return Cartesian galactic coordinates placed on the Celestial sphere + */ +glm::dvec3 localCameraToGalactic(const glm::dvec3& coords); +/** + * Converts from local camera coordinates to Cartesian equatorial coordinates in the epoch + * J2000. + * \param coords Cartesian local camera coordinates + * \return Cartesian equatorial coordinates with unit length + */ +glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); // Camera roll and direction -double cameraRoll(); // Camera roll is with respect to the equatorial North Pole +/** + * Returns the angle between the up direction of the OpenSpace camera and the equatorial + * North Pole direction. + * \return Angle in degrees between the OpenSpace camera's up direction vector and the + * equatorial North Pole direction. + */ +double cameraRoll(); +/** + * Returns the view direction of the OpenSpace camera in galactic coordinates. + * \return View direction of the OpenSpace camera in Cartesian galactic coordinates. + */ glm::dvec3 cameraDirectionGalactic(); +/** + * Returns the view direction of the OpenSpace camera in equatorial coordinates in epoch + * J2000. + * \return View direction of the OpenSpace camera in Cartesian equatorial coordinates in + * epoch J2000. + */ glm::dvec3 cameraDirectionEquatorial(); // Window and field of view +/** + * Returns the window ratio r which is calculated as x / y. + * \return The window ratio x / y + */ float windowRatio(); +/** + * Returns the vertical and horizontal field of view of the OpenSpace window. + * \return The horizontal and vertical field of view in degrees. + */ glm::dvec2 fovWindow(); +/** + * Returns true if the Cartesian equatorial coordinate is in the current view of the + * camera. + * \param equatorial Cartesian equatorial coordinates in epoch J2000 + * \return True if the coordinates are in the camera's current field of view + */ bool isCoordinateInView(const glm::dvec3& equatorial); // Animation for target and camera +/** + * Returns the angle between two vectors. + * \param start Cartesian vector + * \param end Cartesian vector + * \return Angle between two vectors in radians + */ double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); +/** + * Returns a 4x4 matrix for an incremental rotation of a vector. The matrix should be used + * multiple times in order to animate. + * \param start Cartesian vector + * \param end Cartesian vector + * \param deltaTime The time between the current frame and the last + * \param speedFactor Factor that determines how fast the animation will be + * \return 4x4 matrix for incremental rotation animation of a vector + */ glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, double deltaTime, double speedFactor = 1.0); diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index e17ccf406f..29a9ffed32 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -100,11 +100,12 @@ private: bool _isSyncedWithWwt = false; bool _borderColorIsDirty = false; bool _equatorialAimIsDirty = false; - int messageCounter{ 0 }; + int messageCounter = 0; // Time variables // For capping the message passing to WWT - constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 }; + constexpr static const std::chrono::milliseconds TimeUpdateInterval = + std::chrono::milliseconds(10); std::chrono::system_clock::time_point _lastUpdateTime; }; } // namespace openspace diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 3351c63bd9..83a8e93fce 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -82,7 +82,7 @@ private: std::vector _images; std::vector _xmls; }; -} +} // namespace openspace #endif // __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__ diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 5ed31a0836..3ef5b95e76 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -40,16 +40,14 @@ #include "skybrowsermodule_lua.inl" namespace { - constexpr const openspace::properties::Property::PropertyInfo AllowInteractionInfo = - { + constexpr const openspace::properties::Property::PropertyInfo AllowInteractionInfo = { "AllowMouseInteraction", "Allow Mouse Interaction", "Toggles if it is possible to interact with the sky browser and sky targets with " "the mouse or not." }; - constexpr const openspace::properties::Property::PropertyInfo AllowRotationInfo = - { + constexpr const openspace::properties::Property::PropertyInfo AllowRotationInfo = { "AllowCameraRotation", "Allow Camera Rotation", "Toggles if the camera should rotate to look at the sky target if it is going " @@ -77,7 +75,10 @@ namespace openspace { &skybrowser::luascriptfunctions::getListOfImages, "", "Returns a list of all the loaded AAS WorldWide Telescope images that " - "has been loaded." + "have been loaded. Each image has a name, thumbnail url, equatorial " + "spherical coordinates RA and Dec, equatorial Cartesian coordinates, " + "if the image has celestial coordinates, credits text, credits url " + "and the identifier of the image which is a unique number." }, { "setHoverCircle", @@ -97,7 +98,7 @@ namespace openspace { &skybrowser::luascriptfunctions::disableHoverCircle, "", "Disables the hover circle, if there is one added to the sky browser " - "module. " + "module." }, { "loadImagesToWWT", @@ -533,7 +534,7 @@ void SkyBrowserModule::handleMouseClick(const MouseButton& button) { // Change view (by moving target) within browser if right mouse // click on browser _startMousePosition = _mousePosition; - _startDragPosition = _mouseOnPair->getTarget()->screenSpacePosition(); + _startDragPosition = _mouseOnPair->target()->screenSpacePosition(); _interactionMode = MouseInteraction::FineTune; } } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 515e624d03..d9dbd77b79 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -45,6 +45,7 @@ namespace { "A factor that determines the speed of the animation of the field of view. A " "higher number for the factor means a faster speed." }; + constexpr const openspace::properties::Property::PropertyInfo TextureQualityInfo = { "TextureQuality", "Quality of Texture", diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index d76e6497cc..3b1adf6b23 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -60,8 +60,7 @@ namespace { "be rendered in the target." }; - constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = - { + constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { "AnimationSpeed", "Animation Speed", "The factor which is multiplied with the animation speed of the target." @@ -76,8 +75,7 @@ namespace { "in equatorial Cartesian coordinate system." }; - constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = - { + constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = { "LineWidth", "Line Width", "The thickness of the line of the target. The larger number, the thicker line." @@ -299,7 +297,7 @@ bool ScreenSpaceSkyTarget::isLocked() const { return _isLocked; } -bool ScreenSpaceSkyTarget::isAnimated() { +bool ScreenSpaceSkyTarget::isAnimated() const { return _isAnimated; } diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 9554abc23f..4dffd7a581 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -344,11 +344,11 @@ bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const { return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); } -ScreenSpaceSkyTarget* TargetBrowserPair::getTarget() { +ScreenSpaceSkyTarget* TargetBrowserPair::target() const { return _target; } -ScreenSpaceSkyBrowser* TargetBrowserPair::getBrowser() { +ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const { return _browser; } From d7fa2a31a8603f0aeaf3d69ba0002ceac47813fe Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 4 Mar 2022 12:30:58 -0500 Subject: [PATCH 208/251] Make conversion use the combinedViewMatrix to use the SGCT view matrix, that hopefully will make the target work in the dome --- modules/skybrowser/src/utility.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 3060b05497..76dc61059c 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -83,11 +83,15 @@ glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) { } glm::dvec3 localCameraToGalactic(const glm::dvec3& coords) { - glm::dmat4 rotation = glm::inverse( - global::navigationHandler->camera()->viewRotationMatrix()); - glm::dvec4 position = glm::dvec4(coords, 1.0); + glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec4 coordsVec4 = glm::dvec4(coords, 1.0) ; + glm::dmat4 camMat = glm::inverse( + global::navigationHandler->camera()->combinedViewMatrix() + ); + // Subtract gamera position to get the view direction + glm::dvec3 galactic = glm::dvec3(camMat * coordsVec4) - camPos; - return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius; + return glm::normalize(galactic) * skybrowser::CelestialSphereRadius; } glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) { @@ -108,10 +112,8 @@ glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) { glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) { // Transform vector to camera's local coordinate system - glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); - glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix(); - glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos); - glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0); + glm::dmat4 camMat = global::navigationHandler->camera()->combinedViewMatrix(); + glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(coords, 1.0); return glm::normalize(viewDirectionLocal); } From 119016ee54454e67331049f6a78b7b82c7cf24aa Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 4 Mar 2022 17:24:07 -0500 Subject: [PATCH 209/251] Change default position of the target to upper right part of the screen --- modules/skybrowser/skybrowsermodule_lua.inl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index ec5f88e080..f7d764c939 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -428,6 +428,7 @@ int createTargetBrowserPair(lua_State* L) { std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; + glm::vec3 positionTarget = { 1.0f, 0.5f, -2.1f }; std::string guiPath = "/SkyBrowser"; std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; @@ -444,6 +445,7 @@ int createTargetBrowserPair(lua_State* L) { "Type = 'ScreenSpaceSkyTarget'," "Name = '" + nameTarget + "'," "FaceCamera = false," + "CartesianPosition = " + ghoul::to_string(positionTarget) + "}"; global::scriptEngine->queueScript( From ae86396317deb6eb6d497df891a5db11582af555 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 4 Mar 2022 17:37:11 -0500 Subject: [PATCH 210/251] Make crosshair appear at all times with a fixed size --- .../skybrowser/include/screenspaceskytarget.h | 4 +-- modules/skybrowser/shaders/target_fs.glsl | 15 +++++----- .../skybrowser/src/screenspaceskytarget.cpp | 28 +++++++++---------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h index ea6e6aa57c..7c8bb3df38 100644 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ b/modules/skybrowser/include/screenspaceskytarget.h @@ -82,7 +82,7 @@ public: private: // Properties - properties::FloatProperty _showCrosshairThreshold; + properties::FloatProperty _crossHairSize; properties::FloatProperty _showRectangleThreshold; properties::FloatProperty _lineWidth; properties::DoubleProperty _stopAnimationThreshold; @@ -94,7 +94,7 @@ private: bool _shouldLockAfterAnimation = false; // Shader - UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, + UniformCache(modelTransform, viewProj, crossHairSize, showRectangle, lineWidth, dimensions, lineColor) _uniformCache; GLuint _vertexArray = 0; GLuint _vertexBuffer = 0; diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 4d70cad072..adb4c6d5c0 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -27,7 +27,7 @@ in vec4 vs_position; uniform float lineWidth; uniform vec2 dimensions; -uniform bool showCrosshair; +uniform float crossHairSize; uniform bool showRectangle; uniform vec4 lineColor; @@ -43,6 +43,10 @@ float createLine(float lineCenter, float lineWidth, float coord) { return step(startEdge, coord) - step(endEdge, coord); } +float createFilledRectangle(float width, vec2 coord) { + return createLine(0.5, width, coord.x) * createLine(0.5, width, coord.y); +} + float createRectangle(float linewidthY, float ratio, vec2 coord) { // Calculate the widths and centers for the lines float linewidthX = linewidthY * ratio * VerticalThickness; @@ -70,14 +74,11 @@ float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { Fragment getFragment() { float ratio = dimensions.y / dimensions.x; - float crosshair = 0.0; float rectangle = 0.0; + float crossHairBox = createFilledRectangle(crossHairSize/dimensions.x, vs_st); - if (showCrosshair) { - crosshair = createCrosshair(lineWidth, ratio, vs_st); - float border = 1.0 - createRectangle(lineWidth * 5.0, ratio, vs_st); - crosshair *= border; - } + float crosshair = createCrosshair(lineWidth, ratio, vs_st); + crosshair *= crossHairBox; if (showRectangle) { rectangle = createRectangle(lineWidth, ratio, vs_st); diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp index 3b1adf6b23..19e7eaac9b 100644 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ b/modules/skybrowser/src/screenspaceskytarget.cpp @@ -40,16 +40,15 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; constexpr const std::array UniformNames = { - "modelTransform", "viewProj", "showCrosshair", "showRectangle", "lineWidth", + "modelTransform", "viewProj", "crossHairSize", "showRectangle", "lineWidth", "dimensions", "lineColor" }; - constexpr const openspace::properties::Property::PropertyInfo CrosshairThresholdInfo = + constexpr const openspace::properties::Property::PropertyInfo crossHairSizeInfo = { - "CrosshairThreshold", - "Crosshair Threshold", - "When the field of view is smaller than the crosshair threshold, a crosshair will" - "be rendered in the target." + "CrosshairSize", + "Crosshair Size", + "Determines the size of the crosshair." }; constexpr const openspace::properties::Property::PropertyInfo RectangleThresholdInfo = @@ -82,8 +81,8 @@ namespace { }; struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { - // [[codegen::verbatim(CrosshairThresholdInfo.description)]] - std::optional crosshairThreshold; + // [[codegen::verbatim(crossHairSizeInfo.description)]] + std::optional crossHairSize; // [[codegen::verbatim(RectangleThresholdInfo.description)]] std::optional rectangleThreshold; @@ -104,7 +103,7 @@ namespace { namespace openspace { ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _showCrosshairThreshold(CrosshairThresholdInfo, 4.f, 0.1f, 70.f) + , _crossHairSize(crossHairSizeInfo, 0.05f, 0.005f, 0.2f) , _showRectangleThreshold(RectangleThresholdInfo, 2.f, 0.1f, 70.f) , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) @@ -113,12 +112,12 @@ ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) { // Handle target dimension property const Parameters p = codegen::bake(dictionary); - _showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold); + _crossHairSize = p.crossHairSize.value_or(_crossHairSize); _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); - _stopAnimationThreshold = p.crosshairThreshold.value_or(_stopAnimationThreshold); + _stopAnimationThreshold = p.crossHairSize.value_or(_stopAnimationThreshold); _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - addProperty(_showCrosshairThreshold); + addProperty(_crossHairSize); addProperty(_showRectangleThreshold); addProperty(_stopAnimationThreshold); addProperty(_animationSpeed); @@ -205,7 +204,6 @@ glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { } void ScreenSpaceSkyTarget::render() { - bool showCrosshair = _verticalFov < _showCrosshairThreshold; bool showRectangle = _verticalFov > _showRectangleThreshold; glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; @@ -216,10 +214,10 @@ void ScreenSpaceSkyTarget::render() { glDisable(GL_CULL_FACE); _shader->activate(); - _shader->setUniform(_uniformCache.showCrosshair, showCrosshair); + _shader->setUniform(_uniformCache.crossHairSize, _crossHairSize); _shader->setUniform(_uniformCache.showRectangle, showRectangle); _shader->setUniform(_uniformCache.lineWidth, lineWidth); - _shader->setUniform(_uniformCache.dimensions, glm::vec2(_objectSize)); + _shader->setUniform(_uniformCache.dimensions, screenSpaceDimensions()); _shader->setUniform(_uniformCache.modelTransform, modelTransform); _shader->setUniform(_uniformCache.lineColor, color); _shader->setUniform( From f7be9c05e032c1a239b8ec192594866229a7e203 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 7 Mar 2022 15:11:03 -0500 Subject: [PATCH 211/251] Add property to module for controlling the rotation speed of the camera --- modules/skybrowser/skybrowsermodule.cpp | 18 +++++++++++++++--- modules/skybrowser/skybrowsermodule.h | 5 +++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 3ef5b95e76..8d2dd8ffb6 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -54,12 +54,22 @@ namespace { "outside of the current field of view." }; + constexpr const openspace::properties::Property::PropertyInfo CameraRotSpeedInfo = { + "CameraRotationSpeed", + "Camera Rotation Speed", + "The speed of the rotation of the camera when the camera rotates to look at a " + "coordinate which is outside of the field of view." + }; + struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { // [[codegen::verbatim(AllowInteractionInfo.description)]] std::optional allowMouseInteraction; // [[codegen::verbatim(AllowRotationInfo.description)]] std::optional allowCameraRotation; + + // [[codegen::verbatim(CameraRotSpeedInfo.description)]] + std::optional cameraRotSpeed; }; #include "skybrowsermodule_codegen.cpp" @@ -263,9 +273,11 @@ SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _allowMouseInteraction(AllowInteractionInfo, true) , _allowCameraRotation(AllowRotationInfo, true) + , _cameraRotationSpeed(CameraRotSpeedInfo, 1.f, 0.1f, 10.f) { addProperty(_allowMouseInteraction); addProperty(_allowCameraRotation); + addProperty(_cameraRotationSpeed); // Set callback functions global::callback::mouseButton->emplace_back( @@ -371,7 +383,7 @@ SkyBrowserModule::SkyBrowserModule() incrementallyAnimateTargets(deltaTime); } if (_isCameraRotating && _allowCameraRotation) { - incrementallyRotateCamera(deltaTime); + incrementallyRotateCamera(deltaTime, _cameraRotationSpeed); } }); } @@ -576,7 +588,7 @@ void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { _isCameraRotating = true; } -void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { +void SkyBrowserModule::incrementallyRotateCamera(double deltaTime, double animationSpeed) { // Find smallest angle between the two vectors double angle = skybrowser::angleBetweenVectors(_startAnimation, _endAnimation); @@ -587,7 +599,7 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) { _startAnimation, _endAnimation, deltaTime, - AnimationSpeed + animationSpeed ); // Rotate diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 6c81635737..22fb0b6c32 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace openspace { @@ -57,7 +58,6 @@ public: constexpr static const char* Name = "SkyBrowser"; constexpr static const double StopAnimationThreshold = 0.0005; constexpr static const double FadingTime = 2.0; - constexpr static const double AnimationSpeed = 1.0; const double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; SkyBrowserModule(); @@ -77,7 +77,7 @@ public: // Rotation, animation, placement void lookAtTarget(const std::string& id); void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate - void incrementallyRotateCamera(double deltaTime); + void incrementallyRotateCamera(double deltaTime, double animationSpeed); void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); void incrementallyAnimateTargets(double deltaTime); @@ -109,6 +109,7 @@ protected: private: properties::BoolProperty _allowMouseInteraction; properties::BoolProperty _allowCameraRotation; + properties::DoubleProperty _cameraRotationSpeed; glm::ivec3 _highlightAddition = glm::ivec3(35); // Highlight object when mouse hovers // The browsers and targets From 6f4b91696cf6a5c50c842a32af284c096393d650 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 7 Mar 2022 15:34:43 -0500 Subject: [PATCH 212/251] Change image directory name to lower case --- modules/skybrowser/skybrowsermodule_lua.inl | 2 +- modules/skybrowser/src/wwtdatahandler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index f7d764c939..1e4c6cb38b 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -239,7 +239,7 @@ int getListOfImages(lua_State* L) { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" "wwt-web-client/master/assets/webclient-explore-root.wtml"; - std::filesystem::path directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); + std::filesystem::path directory = absPath("${MODULE_SKYBROWSER}/wwtimagedata/"); module->loadImages(root, directory); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 7382a8a10f..4fd343fe3e 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -175,7 +175,7 @@ bool downloadAndParseWtmlFilesFromUrl(std::vector& _xmls std::string newDir = directory.string(); // Remove the '/' at the end newDir.pop_back(); - LINFO("Creating directory WWTimagedata"); + LINFO("Creating directory" + newDir); std::filesystem::create_directory(newDir); } From 990d7e0a989aa520aa81455f3c233f9ff7639010 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 7 Mar 2022 15:34:59 -0500 Subject: [PATCH 213/251] Add image directory to gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a20830ba55..92d0697d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ customization.lua # The COMMIT info is generated everytime CMake is run COMMIT.md *_codegen.cpp +# SkyBrowser Module downloaded data +/modules/skybrowser/wwtimagedata From bf5069fbf61efc7087c5c7378d320edc4d502d65 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 14 Mar 2022 16:49:30 -0400 Subject: [PATCH 214/251] Change screenspaceskybrowser to renderableskybrowser --- modules/base/rendering/renderableplane.h | 15 +- modules/skybrowser/CMakeLists.txt | 4 +- .../skybrowser/include/screenspaceskytarget.h | 116 ----- .../skybrowser/include/targetbrowserpair.h | 34 +- modules/skybrowser/include/utility.h | 13 +- modules/skybrowser/shaders/target_fs.glsl | 37 +- modules/skybrowser/shaders/target_vs.glsl | 37 +- modules/skybrowser/skybrowsermodule.cpp | 50 +-- modules/skybrowser/skybrowsermodule_lua.inl | 70 +-- .../skybrowser/src/screenspaceskytarget.cpp | 422 ------------------ modules/skybrowser/src/targetbrowserpair.cpp | 229 +++++----- modules/skybrowser/src/utility.cpp | 15 +- 12 files changed, 291 insertions(+), 751 deletions(-) delete mode 100644 modules/skybrowser/include/screenspaceskytarget.h delete mode 100644 modules/skybrowser/src/screenspaceskytarget.cpp diff --git a/modules/base/rendering/renderableplane.h b/modules/base/rendering/renderableplane.h index b70c609656..843cdd9a36 100644 --- a/modules/base/rendering/renderableplane.h +++ b/modules/base/rendering/renderableplane.h @@ -67,23 +67,20 @@ public: protected: virtual void bindTexture(); virtual void unbindTexture(); - -protected: - properties::OptionProperty _blendMode; - -private: void createPlane(); - - properties::BoolProperty _billboard; + + properties::OptionProperty _blendMode; properties::BoolProperty _mirrorBackside; + properties::BoolProperty _billboard; properties::FloatProperty _size; properties::Vec3Property _multiplyColor; - + ghoul::opengl::ProgramObject* _shader = nullptr; - + GLuint _quad = 0; GLuint _vertexPositionBuffer = 0; +private: bool _planeIsDirty = false; }; diff --git a/modules/skybrowser/CMakeLists.txt b/modules/skybrowser/CMakeLists.txt index 60387683c1..0eba482bc2 100644 --- a/modules/skybrowser/CMakeLists.txt +++ b/modules/skybrowser/CMakeLists.txt @@ -26,7 +26,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES skybrowsermodule.h - include/screenspaceskytarget.h + include/renderableskytarget.h include/wwtdatahandler.h include/utility.h include/targetbrowserpair.h @@ -40,7 +40,7 @@ source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES skybrowsermodule.cpp skybrowsermodule_lua.inl - src/screenspaceskytarget.cpp + src/renderableskytarget.cpp src/wwtdatahandler.cpp src/utility.cpp src/targetbrowserpair.cpp diff --git a/modules/skybrowser/include/screenspaceskytarget.h b/modules/skybrowser/include/screenspaceskytarget.h deleted file mode 100644 index 7c8bb3df38..0000000000 --- a/modules/skybrowser/include/screenspaceskytarget.h +++ /dev/null @@ -1,116 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2022 * - * * - * 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_SKYBROWSER___SCREENSPACESKYTARGET___H__ -#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ - -#include - -#include -#include -#include - -namespace openspace::documentation { struct Documentation; } - -namespace openspace { - -class ScreenSpaceSkyBrowser; - -class ScreenSpaceSkyTarget : public ScreenSpaceRenderable { -public: - constexpr static const float DeltaTimeThreshold = 0.03f; - - explicit ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary); - virtual ~ScreenSpaceSkyTarget(); - - bool initializeGL() override; - bool deinitializeGL() override; - bool isReady() const override; - void render() override; - void update() override; - glm::mat4 scaleMatrix() override; - void bindTexture() override; // Empty function but has to be defined - void createShaders(); - - glm::ivec3 borderColor() const; - float opacity() const; - glm::dvec2 lockedCoordinates() const; - - void setScaleFromVfov(float verticalFov); - void setFovFromScale(); - void setDimensions(glm::vec2 dimensions); - void setColor(glm::ivec3 color); - void setOpacity(float opacity); - void setLock(bool isLocked); - void setEquatorialAim(const glm::dvec2& aim); - - // Target directions - glm::dvec3 directionGalactic() const; - glm::dvec2 equatorialAim() const; - - // Locking functionality - bool isLocked() const; - - // Animation - bool isAnimated() const; - void startAnimation(glm::dvec3 end, bool shouldLockAfter = true); - void incrementallyAnimateToCoordinate(float deltaTime); - // Display - void highlight(const glm::ivec3& addition); - void removeHighlight(const glm::ivec3& removal); - -private: - // Properties - properties::FloatProperty _crossHairSize; - properties::FloatProperty _showRectangleThreshold; - properties::FloatProperty _lineWidth; - properties::DoubleProperty _stopAnimationThreshold; - properties::DoubleProperty _animationSpeed; - - // Flags - bool _isLocked = false; - bool _isAnimated = false; - bool _shouldLockAfterAnimation = false; - - // Shader - UniformCache(modelTransform, viewProj, crossHairSize, showRectangle, lineWidth, - dimensions, lineColor) _uniformCache; - GLuint _vertexArray = 0; - GLuint _vertexBuffer = 0; - - // Sky browser - float _verticalFov = 70.0f; - glm::dvec2 _equatorialAim = glm::dvec2(0.0); - glm::ivec3 _borderColor = glm::ivec3(255); - - // Lock target to a coordinate on the sky - glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates - - // Animation - glm::dvec3 _animationEnd; // Cartesian equatorial coordinates - glm::dvec3 _animationStart; // Cartesian equatorial coordinates -}; -} // namespace openspace - -#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__ diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 440e2bf1b1..cdf1446f7a 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -31,15 +31,17 @@ namespace openspace { class ScreenSpaceSkyBrowser; -class ScreenSpaceSkyTarget; +class RenderableSkyTarget; class ScreenSpaceRenderable; class ImageData; +class SceneGraphNode; class TargetBrowserPair { public: constexpr static const float FadeThreshold = 0.01f; + constexpr static const float DeltaTimeThreshold = 0.03f; - TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target); + TargetBrowserPair(SceneGraphNode* target, ScreenSpaceSkyBrowser* browser); TargetBrowserPair& operator=(TargetBrowserPair other); // Target & Browser @@ -54,8 +56,6 @@ public: // Mouse interaction bool checkMouseIntersection(const glm::vec2& mousePosition); glm::vec2 selectedScreenSpacePosition() const; - bool isBrowserSelected() const; - bool isTargetSelected() const; void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); void translateSelected(const glm::vec2& start, const glm::vec2& translation); void synchronizeAim(); @@ -68,12 +68,12 @@ public: void centerTargetOnScreen(); void lock(); void unlock(); + void incrementallyAnimateTarget(float deltaTime); bool hasFinishedFading(float goalState) const; bool isFacingCamera() const; bool isUsingRadiusAzimuthElevation() const; bool isEnabled() const; - bool isLocked() const; void setEnabled(bool enable); void setIsSyncedWithWwt(bool isSynced); @@ -82,7 +82,6 @@ public: void setBorderColor(const glm::ivec3& color); void setScreenSpaceSize(const glm::vec2& dimensions); void setVerticalFovWithScroll(float scroll); - void setSelectedWithId(const std::string& id); float verticalFov() const; glm::ivec3 borderColor() const; @@ -90,11 +89,12 @@ public: glm::dvec3 targetDirectionGalactic() const; std::string browserGuiName() const; std::string browserId() const; - std::string targetId() const; + std::string targetRenderableId() const; + std::string targetNodeId() const; std::string selectedId(); glm::vec2 size() const; - ScreenSpaceSkyTarget* target() const; + RenderableSkyTarget* target() const; ScreenSpaceSkyBrowser* browser() const; const std::deque& selectedImages() const; @@ -115,16 +115,22 @@ private: bool isTargetFadeFinished(float goalState) const; bool isBrowserFadeFinished(float goalState) const; + void aimTargetGalactic(glm::dvec3 position); + + void setFovTarget(double fov); + // Selection - ScreenSpaceRenderable* _selected = nullptr; - bool _isSelectedBrowser = false; + ScreenSpaceSkyBrowser* _selected = nullptr; // Target and browser - ScreenSpaceSkyTarget* _target = nullptr; + RenderableSkyTarget* _targetRenderable = nullptr; ScreenSpaceSkyBrowser* _browser = nullptr; - - // Shared properties between the target and the browser - float _verticalFov = 70.f; + SceneGraphNode* _targetNode = nullptr; + glm::dvec3 _animationStart = glm::dvec3(0); + glm::dvec3 _animationEnd = glm::dvec3(0); + bool _shouldLockAfterAnimation = false; + bool _targetIsAnimated = false; + glm::dvec2 _equatorialAim = glm::dvec2(0.0); glm::ivec3 _borderColor = glm::ivec3(255); glm::vec2 _dimensions = glm::vec2(0.5f); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index b2fc32fa8c..cd81f72197 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -26,12 +26,13 @@ #define __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__ #include +#include namespace openspace::skybrowser { // Constants constexpr const double ScreenSpaceZ = -2.1; constexpr const glm::dvec3 NorthPole = { 0.0, 0.0, 1.0 }; -constexpr const double CelestialSphereRadius = std::numeric_limits::max(); +constexpr const double CelestialSphereRadius = 4 * distanceconstants::Parsec; // Conversion matrix - J2000 equatorial <-> galactic // https://arxiv.org/abs/1010.3773v1 @@ -174,7 +175,15 @@ double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); * \return 4x4 matrix for incremental rotation animation of a vector */ glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, - double deltaTime, double speedFactor = 1.0); + double deltaTime, double speedFactor = 1.0); +/** + * Returns the size in meters that for example a plane would need to have in order to + * display a specified field of view. + * \param fov The set field of view + * \param worldPosition The galactic position of the plane + * \return Field of view + */ +double sizeFromFov(double fov, glm::dvec3 worldPosition); } // namespace openspace::skybrowser diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index adb4c6d5c0..21784e923a 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -22,14 +22,23 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ + +in vec4 vs_gPosition; +in vec3 vs_gNormal; +in float vs_screenSpaceDepth; in vec2 vs_st; in vec4 vs_position; -uniform float lineWidth; -uniform vec2 dimensions; uniform float crossHairSize; uniform bool showRectangle; +uniform float lineWidth; +uniform vec2 dimensions; uniform vec4 lineColor; +uniform float fov; + +uniform bool additiveBlending; +uniform float opacity = 1.0; +uniform vec3 multiplyColor; // A factor which states how much thicker vertical lines are rendered than horizontal // This compensates for the optical illusion that vertical lines appear thinner @@ -75,13 +84,14 @@ float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { Fragment getFragment() { float ratio = dimensions.y / dimensions.x; float rectangle = 0.0; - float crossHairBox = createFilledRectangle(crossHairSize/dimensions.x, vs_st); + float lineWidthUsed = (lineWidth * 0.01)/max(fov,2); - float crosshair = createCrosshair(lineWidth, ratio, vs_st); + float crosshair = createCrosshair(lineWidthUsed, ratio, vs_st); + float crossHairBox = createFilledRectangle(crossHairSize/max(fov,2), vs_st); crosshair *= crossHairBox; if (showRectangle) { - rectangle = createRectangle(lineWidth, ratio, vs_st); + rectangle = createRectangle(lineWidthUsed, ratio, vs_st); } float result = clamp(crosshair + rectangle, 0.0, 1.0); @@ -90,5 +100,22 @@ Fragment getFragment() { frag.color = lineColor; frag.color.a *= result; + frag.color.rgb *= multiplyColor; + + frag.color.a *= opacity; + if (frag.color.a == 0.0) { + discard; + } + + frag.depth = vs_screenSpaceDepth; + + if (additiveBlending) { + frag.blend = BLEND_MODE_ADDITIVE; + } + + // G-Buffer + frag.gPosition = vs_gPosition; + frag.gNormal = vec4(vs_gNormal, 1.0); + return frag; } diff --git a/modules/skybrowser/shaders/target_vs.glsl b/modules/skybrowser/shaders/target_vs.glsl index 9d91c1e636..497e19384a 100644 --- a/modules/skybrowser/shaders/target_vs.glsl +++ b/modules/skybrowser/shaders/target_vs.glsl @@ -21,19 +21,32 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#version __CONTEXT__ + #version __CONTEXT__ -out vec2 vs_st; -out vec4 vs_position; + #include "PowerScaling/powerScaling_vs.hglsl" -uniform mat4 modelTransform; -uniform mat4 viewProj; + layout(location = 0) in vec4 in_position; + layout(location = 1) in vec2 in_st; -layout(location = 0) in vec4 in_position; -layout(location = 1) in vec2 in_st; + out vec4 vs_gPosition; + out vec3 vs_gNormal; + out float vs_screenSpaceDepth; + out vec2 vs_st; -void main(){ - vs_st = in_st; - vs_position = viewProj * modelTransform * in_position; - gl_Position = vec4(vs_position); -} + uniform mat4 modelViewProjectionTransform; + uniform mat4 modelViewTransform; + + void main() { + vec4 position = vec4(in_position.xyz * pow(10, in_position.w), 1); + vec4 positionClipSpace = modelViewProjectionTransform * position; + vec4 positionScreenSpace = z_normalization(positionClipSpace); + + gl_Position = positionScreenSpace; + + // G-Buffer + vs_gNormal = vec3(0.0); + vs_gPosition = vec4(modelViewTransform * position); // Must be in SGCT eye space; + + vs_st = in_st; + vs_screenSpaceDepth = positionScreenSpace.w; + } diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 8d2dd8ffb6..9c7d5d58c7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -152,19 +152,6 @@ namespace openspace { "Returns a table of data regarding the current view and the sky browsers " "and targets." }, - { - "lockTarget", - &skybrowser::luascriptfunctions::lockTarget, - "string", - "Takes an identifier to a sky browser or target. Locks the target " - "to its current position." - }, - { - "unlockTarget", - &skybrowser::luascriptfunctions::unlockTarget, - "string", - "Takes an identifier to a sky browser or target. Unlocks the target." - }, { "createTargetBrowserPair", &skybrowser::luascriptfunctions::createTargetBrowserPair, @@ -396,12 +383,18 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); - // Register ScreenSpaceSkyTarget - fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); // Register ScreenSpaceSkyBrowser fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); + // Register ScreenSpaceRenderable + ghoul::TemplateFactory* fRenderable = + FactoryManager::ref().factory(); + ghoul_assert(fRenderable, "Renderable factory was not created"); + + // Register ScreenSpaceSkyTarget + fRenderable->registerClass("RenderableSkyTarget"); + // Create data handler dynamically to avoid the linking error that // came up when including the include file in the module header file _dataHandler = std::make_unique(); @@ -444,16 +437,18 @@ void SkyBrowserModule::setSelectedObject() { } void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const std::string& browserId) { - ScreenSpaceSkyTarget* target = dynamic_cast( - global::renderEngine->screenSpaceRenderable(targetId) - ); + if (!global::renderEngine->scene()) { + return; + } + + SceneGraphNode* target = global::renderEngine->scene()->sceneGraphNode(targetId); ScreenSpaceSkyBrowser* browser = dynamic_cast( global::renderEngine->screenSpaceRenderable(browserId) ); // Ensure pair has both target and browser if (browser && target) { - _targetsBrowsers.push_back(std::make_unique(browser, target)); + _targetsBrowsers.push_back(std::make_unique(target, browser)); } } @@ -533,20 +528,13 @@ void SkyBrowserModule::handleMouseClick(const MouseButton& button) { // If it's not resize mode, it's drag mode _interactionMode = MouseInteraction::Drag; - - // If target is clicked, it should unlock - if (_mouseOnPair->isTargetSelected()) { - _mouseOnPair->unlock(); - } } // Fine tuning mode of target - else if (button == MouseButton::Right && _mouseOnPair->isBrowserSelected()) { - // If you start dragging around on the browser, the target unlocks - _mouseOnPair->unlock(); + else if (button == MouseButton::Right) { // Change view (by moving target) within browser if right mouse // click on browser _startMousePosition = _mousePosition; - _startDragPosition = _mouseOnPair->target()->screenSpacePosition(); + //_startDragPosition = _mouseOnPair->target()->screenSpacePosition(); _interactionMode = MouseInteraction::FineTune; } } @@ -569,7 +557,7 @@ TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) { _targetsBrowsers.end(), [&](const std::unique_ptr& pair) { bool foundBrowser = pair->browserId() == id; - bool foundTarget = pair->targetId() == id; + bool foundTarget = pair->targetRenderableId() == id; return foundBrowser || foundTarget; } ); @@ -668,7 +656,7 @@ std::string SkyBrowserModule::selectedBrowserId() const { std::string SkyBrowserModule::selectedTargetId() { TargetBrowserPair* found = getPair(_selectedBrowser); if (found) { - return found->targetId(); + return found->targetRenderableId(); } else { return ""; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 1e4c6cb38b..6cc71deddc 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -57,7 +57,9 @@ int selectImage(lua_State* L) { // If the coordinate is not in view, rotate camera if (image.hasCelestialCoords && !isInView) { module->startRotatingCamera( - equatorialToGalactic(image.equatorialCartesian) + equatorialToGalactic( + image.equatorialCartesian * skybrowser::CelestialSphereRadius + ) ); } } @@ -92,27 +94,7 @@ int disableHoverCircle(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); SkyBrowserModule* module = global::moduleEngine->module(); module->disableHoverCircle(); - - return 0; -} -int lockTarget(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->lock(); - } - return 0; -} - -int unlockTarget(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); - const std::string id = ghoul::lua::value(L, 1); - SkyBrowserModule* module = global::moduleEngine->module(); - if (module->getPair(id)) { - module->getPair(id)->unlock(); - } return 0; } @@ -358,8 +340,6 @@ int getTargetData(lua_State* L) { lua_settable(L, -3); ghoul::lua::push(L, "color", pair->borderColor()); lua_settable(L, -3); - ghoul::lua::push(L, "isLocked", pair->isLocked()); - lua_settable(L, -3); ghoul::lua::push(L, "size", pair->size()); lua_settable(L, -3); @@ -427,10 +407,14 @@ int createTargetBrowserPair(lua_State* L) { std::string nameTarget = "Sky Target " + std::to_string(noOfPairs); std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); + // Determine starting point on screen for the target glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; glm::vec3 positionTarget = { 1.0f, 0.5f, -2.1f }; + glm::dvec3 galacticTarget = skybrowser::localCameraToGalactic(positionTarget); std::string guiPath = "/SkyBrowser"; std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; + double fov = 5.0; + double size = skybrowser::sizeFromFov(fov, galacticTarget); const std::string browser = "{" "Identifier = '" + idBrowser + "'," @@ -440,13 +424,39 @@ int createTargetBrowserPair(lua_State* L) { "FaceCamera = false," "CartesianPosition = " + ghoul::to_string(positionBrowser) + "}"; + const std::string target = "{" "Identifier = '" + idTarget + "'," - "Type = 'ScreenSpaceSkyTarget'," + "Type = 'SkyTarget'," "Name = '" + nameTarget + "'," - "FaceCamera = false," - "CartesianPosition = " + ghoul::to_string(positionTarget) + - "}"; + "Transform = {" + "Translation = {" + "Type = 'StaticTranslation'," + "Position = {" + + std::to_string(galacticTarget.x) + ", " + + std::to_string(galacticTarget.y) + ", " + + std::to_string(galacticTarget.z) + ", " + "}," + "}," + "Rotation = {" + "Type = 'StaticRotation'," + "Rotation = {0.0, 0.0, 0.0}" + "}" + "}," + "Renderable = {" + "Identifier = 'RenderableSkyTarget'," + "Type = 'RenderableSkyTarget'," + "Size = " + std::to_string(size) + "," + "VerticalFieldOfView = " + std::to_string(fov) + "," + "Origin = 'Center'," + "Billboard = true," + "Opacity = 0.99" + "}," + "GUI = {" + "Name = 'Sky Target', " + "Path = '/SkyBrowser', " + "}" + "}"; global::scriptEngine->queueScript( "openspace.addScreenSpaceRenderable(" + browser + ");", @@ -454,7 +464,7 @@ int createTargetBrowserPair(lua_State* L) { ); global::scriptEngine->queueScript( - "openspace.addScreenSpaceRenderable(" + target + ");", + "openspace.addSceneGraphNode(" + target + ");", scripting::ScriptEngine::RemoteScripting::No ); @@ -479,7 +489,7 @@ int removeTargetBrowserPair(lua_State* L) { TargetBrowserPair* found = module->getPair(id); if (found) { std::string browser = found->browserId(); - std::string target = found->targetId(); + std::string target = found->targetNodeId(); module->removeTargetBrowserPair(id); @@ -490,7 +500,7 @@ int removeTargetBrowserPair(lua_State* L) { ); global::scriptEngine->queueScript( - "openspace.removeScreenSpaceRenderable('" + target + "');", + "openspace.removeSceneGraphNode('" + target + "');", scripting::ScriptEngine::RemoteScripting::Yes ); } diff --git a/modules/skybrowser/src/screenspaceskytarget.cpp b/modules/skybrowser/src/screenspaceskytarget.cpp deleted file mode 100644 index 19e7eaac9b..0000000000 --- a/modules/skybrowser/src/screenspaceskytarget.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2022 * - * * - * 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 -#include -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const char* _loggerCat = "ScreenSpaceSkyTarget"; - - constexpr const std::array UniformNames = { - "modelTransform", "viewProj", "crossHairSize", "showRectangle", "lineWidth", - "dimensions", "lineColor" - }; - - constexpr const openspace::properties::Property::PropertyInfo crossHairSizeInfo = - { - "CrosshairSize", - "Crosshair Size", - "Determines the size of the crosshair." - }; - - constexpr const openspace::properties::Property::PropertyInfo RectangleThresholdInfo = - { - "RectangleThreshold", - "Rectangle Threshold", - "When the field of view is larger than the rectangle threshold, a rectangle will" - "be rendered in the target." - }; - - constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { - "AnimationSpeed", - "Animation Speed", - "The factor which is multiplied with the animation speed of the target." - }; - - constexpr const openspace::properties::Property::PropertyInfo AnimationThresholdInfo = - { - "AnimationThreshold", - "Animation Threshold", - "The threshold for when the target is determined to have appeared at its " - "destination. Angle in radians between the destination and the target position " - "in equatorial Cartesian coordinate system." - }; - - constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = { - "LineWidth", - "Line Width", - "The thickness of the line of the target. The larger number, the thicker line." - }; - - struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters { - // [[codegen::verbatim(crossHairSizeInfo.description)]] - std::optional crossHairSize; - - // [[codegen::verbatim(RectangleThresholdInfo.description)]] - std::optional rectangleThreshold; - - // [[codegen::verbatim(AnimationSpeedInfo.description)]] - std::optional animationSpeed; - - // [[codegen::verbatim(AnimationThresholdInfo.description)]] - std::optional animationThreshold; - - // [[codegen::verbatim(LineWidthInfo.description)]] - std::optional lineWidth; - }; - -#include "screenspaceskytarget_codegen.cpp" -} //namespace - -namespace openspace { -ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary) - : ScreenSpaceRenderable(dictionary) - , _crossHairSize(crossHairSizeInfo, 0.05f, 0.005f, 0.2f) - , _showRectangleThreshold(RectangleThresholdInfo, 2.f, 0.1f, 70.f) - , _stopAnimationThreshold(AnimationThresholdInfo, 0.0005, 0.0, 0.005) - , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) - , _lineWidth(LineWidthInfo, 25.f, 1.f, 100.f) - , _borderColor(220, 220, 220) -{ - // Handle target dimension property - const Parameters p = codegen::bake(dictionary); - _crossHairSize = p.crossHairSize.value_or(_crossHairSize); - _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); - _stopAnimationThreshold = p.crossHairSize.value_or(_stopAnimationThreshold); - _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - - addProperty(_crossHairSize); - addProperty(_showRectangleThreshold); - addProperty(_stopAnimationThreshold); - addProperty(_animationSpeed); - addProperty(_lineWidth); - - // Set a unique identifier - std::string identifier; - if (dictionary.hasValue(KeyIdentifier)) { - identifier = dictionary.value(KeyIdentifier); - } - else { - identifier = "ScreenSpaceSkyTarget"; - } - identifier = makeUniqueIdentifier(identifier); - setIdentifier(identifier); - - // Set the position to screen space z - _cartesianPosition = glm::dvec3( - _cartesianPosition.value().x, - _cartesianPosition.value().y, - skybrowser::ScreenSpaceZ - ); -} - -ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() { - SkyBrowserModule* module = global::moduleEngine->module(); - - if (module && module->getPair(identifier())) { - module->removeTargetBrowserPair(identifier()); - } -} - -// Pure virtual in the screen space renderable class and hence must be defined -void ScreenSpaceSkyTarget::bindTexture() {} - -bool ScreenSpaceSkyTarget::isReady() const { - return _shader != nullptr; -} - -bool ScreenSpaceSkyTarget::initializeGL() { - glGenVertexArrays(1, &_vertexArray); - glGenBuffers(1, &_vertexBuffer); - createShaders(); - - return isReady(); -} - -bool ScreenSpaceSkyTarget::deinitializeGL() { - return ScreenSpaceRenderable::deinitializeGL(); -} - -glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() { - // To ensure the plane has the right ratio - // The _scale us how much of the windows height the browser covers: e.g. a browser - // that covers 0.25 of the height of the window will have scale = 0.25 - glm::vec2 floatObjectSize = glm::abs(_objectSize); - float ratio = floatObjectSize.x / floatObjectSize.y; - - glm::mat4 scale = glm::scale( - glm::mat4(1.f), - glm::vec3(ratio * _scale, _scale, 1.f) - ); - - return scale; -} - - -void ScreenSpaceSkyTarget::createShaders() { - _shader = global::renderEngine->buildRenderProgram( - "ScreenSpaceProgram", - absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), - absPath("${MODULE_SKYBROWSER}/shaders/target_fs.glsl") - ); - - ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); -} - -void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) { - _borderColor = std::move(color); -} - -glm::ivec3 ScreenSpaceSkyTarget::borderColor() const { - return _borderColor; -} - -void ScreenSpaceSkyTarget::render() { - bool showRectangle = _verticalFov > _showRectangleThreshold; - - glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; - glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() * - localRotationMatrix() * scaleMatrix(); - float lineWidth = (_lineWidth * 0.0001f) / _scale.value(); - - glDisable(GL_CULL_FACE); - - _shader->activate(); - _shader->setUniform(_uniformCache.crossHairSize, _crossHairSize); - _shader->setUniform(_uniformCache.showRectangle, showRectangle); - _shader->setUniform(_uniformCache.lineWidth, lineWidth); - _shader->setUniform(_uniformCache.dimensions, screenSpaceDimensions()); - _shader->setUniform(_uniformCache.modelTransform, modelTransform); - _shader->setUniform(_uniformCache.lineColor, color); - _shader->setUniform( - _uniformCache.viewProj, - global::renderEngine->scene()->camera()->viewProjectionMatrix() - ); - - glBindVertexArray(rendering::helper::vertexObjects.square.vao); - glDrawArrays(GL_TRIANGLES, 0, 6); - - glEnable(GL_CULL_FACE); - - _shader->deactivate(); -} - -void ScreenSpaceSkyTarget::update() { - if (_isLocked) { - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera( - _lockedCoordinates - ); - - if (_useRadiusAzimuthElevation) { - // Keep the set radius - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d( - localCamera - ); - } - } -} - -void ScreenSpaceSkyTarget::setDimensions(glm::vec2 dimensions) { - // To avoid flooring of the size of the target, multiply by factor of 100 - // Object size is really the pixel size so this calculation is not exact - _objectSize = glm::ivec2(dimensions * 100.f); -} - -glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const { - glm::vec3 localCamera = _cartesianPosition.value(); - - if (_useRadiusAzimuthElevation) { - localCamera = raeToCartesian(_raePosition.value()); - } - - glm::dmat4 rotation = glm::inverse( - global::navigationHandler->camera()->viewRotationMatrix() - ); - glm::dvec4 position = glm::dvec4(localCamera, 1.0); - - return glm::normalize(rotation * position); -} - -// Update the scale of the target (the height of the target in relation to the -// OpenSpace window) -void ScreenSpaceSkyTarget::setScaleFromVfov(float verticalFov) { - _verticalFov = verticalFov; - glm::dvec2 fovs = skybrowser::fovWindow(); - - // Cap the scale at small scales so it is still visible - float heightRatio = verticalFov / fovs.y; - float smallestHeightRatio = _showRectangleThreshold.value() / fovs.y; - - _scale = std::max(heightRatio, smallestHeightRatio); -} - -void ScreenSpaceSkyTarget::setFovFromScale() { - glm::dvec2 fovs = skybrowser::fovWindow(); - _verticalFov = _scale * fovs.y; -} - -bool ScreenSpaceSkyTarget::isLocked() const { - return _isLocked; -} - -bool ScreenSpaceSkyTarget::isAnimated() const { - return _isAnimated; -} - -void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd, - bool shouldLockAfter) -{ - _animationStart = glm::normalize( - skybrowser::sphericalToCartesian(equatorialAim()) - ); - _animationEnd = glm::normalize(equatorialCoordsEnd); - _shouldLockAfterAnimation = shouldLockAfter; - _isAnimated = true; - _isLocked = false; -} - -void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) { - // At fps that are too low, the animation stops working. Just place target instead - bool fpsTooLow = deltaTime > DeltaTimeThreshold; - // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleBetweenVectors(_animationStart, - _animationEnd); - bool hasArrived = smallestAngle < _stopAnimationThreshold; - - // Only keep animating when target is not at goal position - if (!hasArrived && !fpsTooLow) { - glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( - _animationStart, - _animationEnd, - deltaTime, - _animationSpeed - ); - - // Rotate target direction - glm::dvec3 equatorial = glm::dvec3(rotMat * glm::dvec4(_animationStart, 1.0)); - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(equatorial); - // Convert to screen space - if (_useRadiusAzimuthElevation) { - // Keep the radius - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); - } - - // Update position - glm::dvec3 cartesian = skybrowser::sphericalToCartesian(equatorialAim()); - _animationStart = glm::normalize(cartesian); - } - else { - // Set the exact target position - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(_animationEnd); - - if (_useRadiusAzimuthElevation) { - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); - } - - _isAnimated = false; - // Lock target when it first arrives to the position - setLock(_shouldLockAfterAnimation); - } -} - -glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const { - glm::dvec3 cartesian; - // Get the local camera coordinates of the target - if (_useRadiusAzimuthElevation) { - cartesian = raeToCartesian(_raePosition.value()); - glm::dvec3 equatorial = skybrowser::localCameraToEquatorial(cartesian); - return skybrowser::cartesianToSpherical(equatorial); - } - else { - cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value()); - return skybrowser::cartesianToSpherical(cartesian); - } -} - -void ScreenSpaceSkyTarget::highlight(const glm::ivec3& addition) { - _borderColor += addition; -} - -void ScreenSpaceSkyTarget::removeHighlight(const glm::ivec3& removal) { - _borderColor -= removal; -} - -float ScreenSpaceSkyTarget::opacity() const { - return _opacity; -} - -glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const { - return skybrowser::cartesianToSpherical(_lockedCoordinates); -} - -void ScreenSpaceSkyTarget::setOpacity(float opacity) { - _opacity = opacity; -} - -void ScreenSpaceSkyTarget::setLock(bool isLocked) { - _isLocked = isLocked; - if (_isLocked) { - _lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim()); - } -} - -void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) { - _isAnimated = false; - _isLocked = false; - - glm::dvec3 cartesianAim = skybrowser::sphericalToCartesian(aim); - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(cartesianAim); - if (_useRadiusAzimuthElevation) { - // Keep the set radius - glm::vec3 position = _raePosition.value().x * glm::vec3(localCamera); - _raePosition = cartesianToRae(position); - } - else { - _cartesianPosition = skybrowser::localCameraToScreenSpace3d(localCamera); - } -} -} // namespace openspace diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 4dffd7a581..86e2111da7 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -37,44 +37,38 @@ namespace openspace { -TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, - ScreenSpaceSkyTarget* target) - : _target(target), _browser(browser) +TargetBrowserPair::TargetBrowserPair(SceneGraphNode* targetNode, + ScreenSpaceSkyBrowser* browser) + : _targetNode(targetNode), _browser(browser) { ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); ghoul_assert(target != nullptr, "Sky target is null pointer!"); + + _targetRenderable = dynamic_cast(_targetNode->renderable()); } TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) { - std::swap(_target, other._target); + std::swap(_targetNode, other._targetNode); std::swap(_browser, other._browser); return *this; } - -void TargetBrowserPair::lock() { - _target->setLock(true); -} - -void TargetBrowserPair::unlock() { - _target->setLock(false); -} void TargetBrowserPair::setImageOrder(int i, int order) { _browser->setImageOrder(i, order); } void TargetBrowserPair::removeHighlight(const glm::ivec3& color) { - _target->removeHighlight(color); + _targetRenderable->removeHighlight(color); _browser->removeHighlight(color); } void TargetBrowserPair::highlight(const glm::ivec3& color) { _browser->highlight(color); - _target->highlight(color); + _targetRenderable->highlight(color); } bool TargetBrowserPair::isTargetFadeFinished(float goalState) const { - float targetDiff = abs(_target->opacity() - goalState); + float targetDiff = abs(_targetRenderable->opacity() - goalState); return targetDiff < FadeThreshold; } @@ -84,36 +78,48 @@ bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const { return browserDiff < FadeThreshold; } +void TargetBrowserPair::aimTargetGalactic(glm::dvec3 direction) { + std::string id = _targetNode->identifier(); + // Uris for properties + std::string positionUri = "Scene." + id + ".Translation.Position"; + glm::dvec3 positionCelestial = glm::normalize(direction) * + skybrowser::CelestialSphereRadius; + std::string setValue = "openspace.setPropertyValueSingle('"; + + openspace::global::scriptEngine->queueScript( + setValue + positionUri + "', " + ghoul::to_string(positionCelestial) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} + +void TargetBrowserPair::setFovTarget(double fov) { + std::string id = _targetNode->identifier(); + std::string renderableId = _targetRenderable->identifier(); + // Uris for properties + std::string sizeUri = "Scene." + id + "." + renderableId + ".Size"; + + double renderedFov = std::max(fov, _targetRenderable->smallestFov()); + double size = skybrowser::sizeFromFov(renderedFov, _targetNode->worldPosition()); + + std::string setValue = "openspace.setPropertyValueSingle('"; + + openspace::global::scriptEngine->queueScript( + setValue + sizeUri + "', " + std::to_string(size) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); + _targetRenderable->setVerticalFov(renderedFov); +} + bool TargetBrowserPair::checkMouseIntersection(const glm::vec2& mousePosition) { - bool onBrowser = _browser->isIntersecting(mousePosition); - bool onTarget = _target->isIntersecting(mousePosition); - if (onBrowser) { - _selected = _browser; - _isSelectedBrowser = true; - } - else if (onTarget) { - _selected = _target; - _isSelectedBrowser = false; - } - else { - _selected = nullptr; - _isSelectedBrowser = false; - } - return onBrowser || onTarget; + _selected = _browser->isIntersecting(mousePosition) ? _browser : nullptr; + + return _selected; } glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() const { return _selected->screenSpacePosition(); } -bool TargetBrowserPair::isBrowserSelected() const { - return _isSelectedBrowser; -} - -bool TargetBrowserPair::isTargetSelected() const { - return _selected && !_isSelectedBrowser; -} - // The fine tune of the target is a way to "drag and drop" the target with right click // drag on the sky browser window. This is to be able to drag the target around when it // has a very small field of view @@ -122,12 +128,7 @@ void TargetBrowserPair::fineTuneTarget(const glm::vec2& start, { glm::vec2 fineTune = _browser->fineTuneVector(translation); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.translateScreenSpaceRenderable(\"" + targetId() + "\"," - + std::to_string(start.x) + "," + std::to_string(start.y) + "," - + std::to_string(fineTune.x) + "," + std::to_string(fineTune.y) + ")", - scripting::ScriptEngine::RemoteScripting::Yes - ); + } void TargetBrowserPair::translateSelected(const glm::vec2& start, @@ -145,39 +146,26 @@ void TargetBrowserPair::translateSelected(const glm::vec2& start, } void TargetBrowserPair::synchronizeAim() { - if (!_target->isAnimated()) { - glm::dvec2 aim; + if (!_targetIsAnimated) { // To remove the lag effect when moving the camera while having a locked // target, send the locked coordinates to wwt - if (_target->isLocked()) { - aim = _target->lockedCoordinates(); - } - else { - aim = _target->equatorialAim(); - } - + glm::dvec2 aim = targetDirectionEquatorial(); _browser->setEquatorialAim(aim); - _target->setScaleFromVfov(_browser->verticalFov()); + setFovTarget(_browser->verticalFov()); } } void TargetBrowserPair::setEnabled(bool enable) { _browser->setEnabled(enable); - _target->setEnabled(enable); } bool TargetBrowserPair::isEnabled() const { - return _target->isEnabled() && _browser->isEnabled(); -} - -bool TargetBrowserPair::isLocked() const { - return _target->isLocked(); + return _targetRenderable->isEnabled() && _browser->isEnabled(); } void TargetBrowserPair::initialize() { - _target->setColor(_browser->borderColor()); - _target->setDimensions(_browser->browserPixelDimensions()); - _target->setScaleFromVfov(_browser->verticalFov()); + _targetRenderable->setColor(_browser->borderColor()); + _targetRenderable->setDimensions(_browser->browserPixelDimensions()); _browser->updateBorderColor(); } @@ -186,11 +174,14 @@ glm::ivec3 TargetBrowserPair::borderColor() const { } glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const { - return _target->equatorialAim(); + glm::dvec3 cartesian = skybrowser::galacticToEquatorial( + glm::normalize(_targetNode->worldPosition()) + ); + return skybrowser::cartesianToSpherical(cartesian); } glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const { - return _target->directionGalactic(); + return glm::normalize(_targetNode->worldPosition()); } std::string TargetBrowserPair::browserGuiName() const { @@ -201,8 +192,12 @@ std::string TargetBrowserPair::browserId() const { return _browser->identifier(); } -std::string TargetBrowserPair::targetId() const { - return _target->identifier(); +std::string TargetBrowserPair::targetRenderableId() const { + return _targetRenderable->identifier(); +} + +std::string TargetBrowserPair::targetNodeId() const { + return _targetNode->identifier(); } std::string TargetBrowserPair::selectedId() { @@ -229,8 +224,9 @@ void TargetBrowserPair::selectImage(const ImageData& image, int i) { if (image.hasCelestialCoords) { // Animate the target to the image coordinate position - unlock(); - startAnimation(image.equatorialCartesian, image.fov, true); + // unlock(); + glm::dvec3 galactic = skybrowser::equatorialToGalactic(image.equatorialCartesian); + startAnimation(galactic * skybrowser::CelestialSphereRadius, image.fov, true); } } @@ -263,26 +259,25 @@ void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { } void TargetBrowserPair::setVerticalFov(float vfov) { - _verticalFov = vfov; _browser->setVerticalFov(vfov); - _target->setScaleFromVfov(vfov); + setFovTarget(vfov); } void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) { _equatorialAim = aim; - _target->setEquatorialAim(aim); + aimTargetGalactic( + skybrowser::equatorialToGalactic(skybrowser::sphericalToCartesian(aim)) + ); _browser->setEquatorialAim(aim); } void TargetBrowserPair::setBorderColor(const glm::ivec3& color) { _borderColor = color; - _target->setColor(color); + _targetRenderable->setColor(color); _browser->setBorderColor(color); } void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) { - _dimensions = dimensions; - _target->setDimensions(dimensions); _browser->setScreenSpaceSize(dimensions); } @@ -290,43 +285,65 @@ void TargetBrowserPair::setVerticalFovWithScroll(float scroll) { _browser->setVerticalFovWithScroll(scroll); } -void TargetBrowserPair::setSelectedWithId(const std::string& id) { - if (browserId() == id) { - _isSelectedBrowser = true; - _selected = _browser; - } - else if (targetId() == id) { - _isSelectedBrowser = false; - _selected = _target; - } - else { - _isSelectedBrowser = false; - _selected = nullptr; - } -} - void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { // Animate the target before the field of view starts to animate - if (_target->isAnimated()) { - _target->incrementallyAnimateToCoordinate(static_cast(deltaTime)); + if (_targetIsAnimated) { + incrementallyAnimateTarget(static_cast(deltaTime)); } else if (_browser->isAnimated()) { _browser->incrementallyAnimateToFov(static_cast(deltaTime)); + setFovTarget(_browser->verticalFov()); } } -void TargetBrowserPair::startAnimation(glm::dvec3 equatorialCoords, float fovEnd, +void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, float fovEnd, bool shouldLockAfter) { - _target->startAnimation(equatorialCoords, shouldLockAfter); _browser->startFovAnimation(fovEnd); + + // Target animation + _animationStart = glm::normalize(_targetNode->worldPosition()) * + skybrowser::CelestialSphereRadius; + _animationEnd = galacticCoords; + _shouldLockAfterAnimation = shouldLockAfter; + _targetIsAnimated = true; +} + +void TargetBrowserPair::incrementallyAnimateTarget(float deltaTime) { + // At fps that are too low, the animation stops working. Just place target instead + bool fpsTooLow = deltaTime > DeltaTimeThreshold; + // Find smallest angle between the two vectors + double smallestAngle = skybrowser::angleBetweenVectors(glm::normalize(_animationStart), + glm::normalize(_animationEnd)); + bool hasArrived = smallestAngle < _targetRenderable->stopAnimationThreshold(); + + // Only keep animating when target is not at goal position + if (!hasArrived && !fpsTooLow) { + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( + glm::normalize(_animationStart), + glm::normalize(_animationEnd), + deltaTime, + _targetRenderable->animationSpeed() + ); + + // Rotate target direction + glm::dvec3 newPos = glm::dvec3(rotMat * glm::dvec4(_animationStart, 1.0)); + + aimTargetGalactic(newPos); + + // Update position + _animationStart = newPos; + } + else { + // Set the exact target position + aimTargetGalactic(_animationEnd); + _targetIsAnimated = false; + } } void TargetBrowserPair::centerTargetOnScreen() { - // Animate the target to the center of the screen - unlock(); // Get camera direction in celestial spherical coordinates - glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial(); + glm::dvec3 viewDirection = skybrowser::cameraDirectionGalactic(); // Keep the current fov float currentFov = verticalFov(); startAnimation(viewDirection, currentFov, false); @@ -337,15 +354,15 @@ bool TargetBrowserPair::hasFinishedFading(float goalState) const { } bool TargetBrowserPair::isFacingCamera() const { - return _browser->isFacingCamera() || _target->isFacingCamera(); + return _browser->isFacingCamera(); } bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const { - return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords(); + return _browser->isUsingRaeCoords(); } -ScreenSpaceSkyTarget* TargetBrowserPair::target() const { - return _target; +RenderableSkyTarget* TargetBrowserPair::target() const { + return _targetRenderable; } ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const { @@ -356,15 +373,15 @@ void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, float deltaTime) { float opacityDelta = static_cast(deltaTime / fadeTime); - if (_target->opacity() > goalState) { + if (_targetRenderable->opacity() > goalState) { opacityDelta *= -1.f; } if (!isTargetFadeFinished(goalState)) { - _target->setOpacity(_target->opacity() + opacityDelta); + _targetRenderable->setOpacity(_targetRenderable->opacity() + opacityDelta); } else { - _target->setOpacity(goalState); + _targetRenderable->setOpacity(goalState); } if (!isBrowserFadeFinished(goalState)) { @@ -376,7 +393,7 @@ void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, } bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { - return lhs._target == rhs._target && lhs._browser == rhs._browser; + return lhs._targetNode == rhs._targetNode && lhs._browser == rhs._browser; } bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) { diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 76dc61059c..69275767f0 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -65,7 +65,7 @@ glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) { glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) { // On the unit sphere glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); - return rGalactic * CelestialSphereRadius; + return rGalactic; } glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) { @@ -105,7 +105,7 @@ glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) { glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) { // Transform equatorial J2000 to galactic coord with infinite radius - glm::dvec3 galactic = equatorialToGalactic(coords); + glm::dvec3 galactic = equatorialToGalactic(coords) * CelestialSphereRadius; glm::dvec3 localCamera = galacticToLocalCamera(galactic); return localCamera; } @@ -203,6 +203,17 @@ glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end)); return glm::rotate(rotationAngle, rotationAxis); } +double sizeFromFov(double fov, glm::dvec3 worldPosition) { + + // Calculate the size with trigonometry + // /| + // /_| Adjacent is the horizontal line, opposite the vertical + // \ | Calculate for half the triangle first, then multiply with 2 + // \| + double adjacent = glm::length(worldPosition); + double opposite = 2 * adjacent * glm::tan(glm::radians(fov * 0.5)); + return opposite; +} } // namespace openspace From 99bfd1cf5782af1b8244540299714045f0675d26 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 16 Mar 2022 12:06:15 -0400 Subject: [PATCH 215/251] Implement fine tuning of target in world space coordinates --- .../skybrowser/include/targetbrowserpair.h | 5 +++-- modules/skybrowser/skybrowsermodule.cpp | 8 +++++-- modules/skybrowser/skybrowsermodule.h | 1 + .../skybrowser/src/screenspaceskybrowser.cpp | 4 ++++ modules/skybrowser/src/targetbrowserpair.cpp | 21 ++++++++++++++----- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index cdf1446f7a..43106960ce 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -56,7 +56,8 @@ public: // Mouse interaction bool checkMouseIntersection(const glm::vec2& mousePosition); glm::vec2 selectedScreenSpacePosition() const; - void fineTuneTarget(const glm::vec2& start, const glm::vec2& translation); + void fineTuneTarget(const glm::dvec3& startWorld, const glm::vec2& startMouse, + const glm::vec2& translation); void translateSelected(const glm::vec2& start, const glm::vec2& translation); void synchronizeAim(); @@ -94,7 +95,7 @@ public: std::string selectedId(); glm::vec2 size() const; - RenderableSkyTarget* target() const; + SceneGraphNode* targetNode() const; ScreenSpaceSkyBrowser* browser() const; const std::deque& selectedImages() const; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 9c7d5d58c7..03e7cfe233 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -312,7 +312,11 @@ SkyBrowserModule::SkyBrowserModule() _mouseOnPair->translateSelected(_startDragPosition, translation); break; case MouseInteraction::FineTune: - _mouseOnPair->fineTuneTarget(_startDragPosition, translation); + _mouseOnPair->fineTuneTarget( + _startTargetPosition, + _startDragPosition, + translation + ); break; default: setSelectedObject(); @@ -534,7 +538,7 @@ void SkyBrowserModule::handleMouseClick(const MouseButton& button) { // Change view (by moving target) within browser if right mouse // click on browser _startMousePosition = _mousePosition; - //_startDragPosition = _mouseOnPair->target()->screenSpacePosition(); + _startTargetPosition = _mouseOnPair->targetNode()->worldPosition(); _interactionMode = MouseInteraction::FineTune; } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 22fb0b6c32..53bc7c0197 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -131,6 +131,7 @@ private: glm::vec2 _mousePosition; // Current mouse position in screen space coordinates glm::vec2 _startMousePosition; glm::vec2 _startDragPosition; + glm::dvec3 _startTargetPosition; // Animation of rotation of camera to look at coordinate galactic coordinates glm::dvec3 _startAnimation; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index d9dbd77b79..a2328d87c8 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -208,6 +208,10 @@ void ScreenSpaceSkyBrowser::render() { localRotationMatrix() * scaleMatrix() ); + + // scale and translation probably + //if(global::windowDelegate->isMaster() && property) + } void ScreenSpaceSkyBrowser::update() { diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 86e2111da7..fdefb3c683 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -123,12 +123,23 @@ glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() const { // The fine tune of the target is a way to "drag and drop" the target with right click // drag on the sky browser window. This is to be able to drag the target around when it // has a very small field of view -void TargetBrowserPair::fineTuneTarget(const glm::vec2& start, - const glm::vec2& translation) +void TargetBrowserPair::fineTuneTarget(const glm::dvec3& startWorldPosition, + const glm::vec2& startMouse, + const glm::vec2& translation) { glm::vec2 fineTune = _browser->fineTuneVector(translation); + glm::vec2 endMouse = startMouse + fineTune; + + // Translation world + glm::dvec3 startWorld = skybrowser::localCameraToGalactic( + glm::vec3(startMouse, skybrowser::ScreenSpaceZ) + ); + glm::dvec3 endWorld = skybrowser::localCameraToGalactic( + glm::vec3(endMouse, skybrowser::ScreenSpaceZ) + ); - + glm::dvec3 translationWorld = endWorld - startWorld; + aimTargetGalactic(startWorldPosition + translationWorld); } void TargetBrowserPair::translateSelected(const glm::vec2& start, @@ -361,8 +372,8 @@ bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const { return _browser->isUsingRaeCoords(); } -RenderableSkyTarget* TargetBrowserPair::target() const { - return _targetRenderable; +SceneGraphNode* TargetBrowserPair::targetNode() const { + return _targetNode; } ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const { From 7d3a88f007e7c83026b5ae8aac2ba4e5c8543c5c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 16 Mar 2022 16:22:56 -0400 Subject: [PATCH 216/251] Make it possible to add two copies of the sky browser, which will make it possible to display many copies in a dome environment and have an interactive copy on the master node --- .../rendering/screenspacerenderable.h | 6 + .../include/screenspaceskybrowser.h | 4 + .../skybrowser/src/screenspaceskybrowser.cpp | 82 ++++++++- src/rendering/screenspacerenderable.cpp | 158 +++++++++--------- 4 files changed, 169 insertions(+), 81 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 690e6371fe..34c5de6372 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -105,6 +105,12 @@ protected: virtual void bindTexture() = 0; virtual void unbindTexture(); + glm::vec3 sphericalToRae(glm::vec3 spherical) const; + glm::vec3 raeToSpherical(glm::vec3 rae) const; + glm::vec3 cartesianToSpherical(const glm::vec3& cartesian) const; + glm::vec3 sphericalToCartesian(glm::vec3 spherical) const; + glm::vec3 sanitizeSphericalCoordinates(glm::vec3 spherical) const; + properties::BoolProperty _enabled; properties::BoolProperty _usePerspectiveProjection; properties::BoolProperty _useRadiusAzimuthElevation; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index b9ba42efeb..596f66db34 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -72,6 +72,10 @@ public: private: properties::DoubleProperty _animationSpeed; properties::FloatProperty _textureQuality; + properties::BoolProperty _renderCopy1; + properties::Vec3Property _copyPosition1; + properties::BoolProperty _renderCopy2; + properties::Vec3Property _copyPosition2; void bindTexture() override; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index a2328d87c8..959b7472f2 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -54,12 +54,50 @@ namespace { "frame rate." }; + constexpr const openspace::properties::Property::PropertyInfo RenderCopy1Info = { + "RenderCopy1", + "Render A Copy Of The Sky Browser", + "Render a copy of this sky browser at an additional position. This copy will not " + "be interactive." + }; + + constexpr const openspace::properties::Property::PropertyInfo CopyPosition1Info = { + "CopyPosition1", + "Position Of First Copy Of Sky Browser", + "The (radius, azimuth, elevation) position where the copy will be placed. " + }; + + constexpr const openspace::properties::Property::PropertyInfo RenderCopy2Info = { + "RenderCopy2", + "Render An Additional Copy Of The Sky Browser", + "Render a copy of this sky browser at an additional position. This copy will not " + "be interactive." + }; + + constexpr const openspace::properties::Property::PropertyInfo CopyPosition2Info = { + "CopyPosition2", + "Position Of Second Copy Of Sky Browser", + "The (radius, azimuth, elevation) position where the copy will be placed. " + }; + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { // [[codegen::verbatim(AnimationSpeedInfo.description)]] std::optional animationSpeed; // [[codegen::verbatim(TextureQualityInfo.description)]] std::optional textureQuality; + + // [[codegen::verbatim(RenderCopy1Info.description)]] + std::optional renderCopy1; + + // [[codegen::verbatim(CopyPosition1Info.description)]] + std::optional copyPosition1; + + // [[codegen::verbatim(RenderCopy2Info.description)]] + std::optional renderCopy2; + + // [[codegen::verbatim(CopyPosition2Info.description)]] + std::optional copyPosition2; }; #include "screenspaceskybrowser_codegen.cpp" @@ -87,11 +125,23 @@ glm::ivec3 randomBorderColor(glm::ivec3 highlight) { namespace openspace { -ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) + ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) , WwtCommunicator(dictionary) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) + , _renderCopy1(RenderCopy1Info) + , _copyPosition1(CopyPosition1Info, + glm::vec3(2.1f, 0.f, 0.f), + glm::vec3(-4.f, -4.f, 0.f), + glm::vec3(4.f, 4.f, 10.f) + ) + , _renderCopy2(RenderCopy2Info) + , _copyPosition2(CopyPosition2Info, + glm::vec3(2.1f, 0.f, 0.f), + glm::vec3(-4.f, -4.f, 0.f), + glm::vec3(4.f, 4.f, 10.f) + ) { _identifier = makeUniqueIdentifier(_identifier); @@ -99,11 +149,19 @@ ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary const Parameters p = codegen::bake(dictionary); _textureQuality = p.textureQuality.value_or(_textureQuality); _animationSpeed = p.animationSpeed.value_or(_animationSpeed); + _renderCopy1 = p.renderCopy1.value_or(_renderCopy1); + _copyPosition1 = p.copyPosition1.value_or(_copyPosition1); + _renderCopy2 = p.renderCopy1.value_or(_renderCopy2); + _copyPosition2 = p.copyPosition1.value_or(_copyPosition2); addProperty(_url); addProperty(_browserPixeldimensions); addProperty(_reload); addProperty(_textureQuality); + addProperty(_renderCopy1); + addProperty(_copyPosition1); + addProperty(_renderCopy2); + addProperty(_copyPosition2); _textureQuality.onChange([this]() { _textureDimensionsIsDirty = true; @@ -209,8 +267,26 @@ void ScreenSpaceSkyBrowser::render() { scaleMatrix() ); - // scale and translation probably - //if(global::windowDelegate->isMaster() && property) + // Render a copy that is not interactive + if (_renderCopy1) { + glm::vec3 spherical = sphericalToCartesian(raeToSpherical(_copyPosition1)); + draw( + globalRotationMatrix() * + glm::translate(glm::mat4(1.f), spherical)* + localRotationMatrix() * + scaleMatrix() + ); + } + // Render a copy that is not interactive + if (_renderCopy2) { + glm::vec3 spherical = sphericalToCartesian(raeToSpherical(_copyPosition2)); + draw( + globalRotationMatrix() * + glm::translate(glm::mat4(1.f), spherical) * + localRotationMatrix() * + scaleMatrix() + ); + } } diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 0e5b476b22..9f4e4e1d86 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -142,84 +142,6 @@ namespace { return glm::mod(value - min, max - min) + min; } - glm::vec3 sanitizeSphericalCoordinates(glm::vec3 spherical) { - const float r = spherical.x; - float phi = spherical.z; - - // Sanitize coordinates. - float theta = wrap(spherical.y, 0.f, glm::two_pi()); - if (theta > glm::pi()) { - theta = glm::two_pi() - theta; - phi += glm::pi(); - } - - return glm::vec3(r, theta, phi); - } - - glm::vec3 sphericalToCartesian(glm::vec3 spherical) { - // First convert to ISO convention spherical coordinates according to - // https://en.wikipedia.org/wiki/Spherical_coordinate_system - // (radius, theta, phi), where theta is the polar angle from the z axis, - // and phi is the azimuth. - - const glm::vec3 sanitized = sanitizeSphericalCoordinates(std::move(spherical)); - const float x = sanitized[0] * sin(sanitized[1]) * cos(sanitized[2]); - const float y = sanitized[0] * sin(sanitized[1]) * sin(sanitized[2]); - const float z = sanitized[0] * cos(sanitized[1]); - - // Now, convert rotate the coordinate system, so that z maps to y, - // and y maps to -z. We want the pole to be in y instead of z. - return glm::vec3(x, -z, y); - } - - glm::vec3 cartesianToSpherical(const glm::vec3& cartesian) { - // Rotate cartesian coordinates. - glm::vec3 rotated = glm::vec3(cartesian.x, cartesian.z, -cartesian.y); - - const float r = sqrt( - pow(rotated.x, 2.f) + pow(rotated.y, 2.f) + pow(rotated.z, 2.f) - ); - const float theta = acos(rotated.z/r); - const float phi = atan2(rotated.y, rotated.x); - return sanitizeSphericalCoordinates(glm::vec3(r, theta, phi)); - } - - // Radius, azimiuth, elevation to spherical coordinates. - glm::vec3 raeToSpherical(glm::vec3 rae) { - //return rae; - const float r = rae.x; - - // Polar angle, theta, is elevation + pi/2. - const float theta = rae.z + glm::half_pi(); - - // Azimuth in ISO spherical coordiantes (phi) is angle from x, - // as opposed to from negative y on screen. - const float phi = rae.y - glm::half_pi(); - - return glm::vec3(r, theta, phi); - } - - // Spherical coordinates to radius, azimuth and elevation. - glm::vec3 sphericalToRae(glm::vec3 spherical) { - //return spherical; - const float r = spherical.x; - - // Azimuth on screen is angle from negative y, as opposed to from x. - float azimuth = spherical.z + glm::half_pi(); - - // Elevation is polar angle - pi/2 - float elevation = wrap( - spherical.y - glm::half_pi(), - -glm::pi(), - glm::pi() - ); - - return glm::vec3( - r, - wrap(azimuth, -glm::pi(), glm::pi()), - wrap(elevation, -glm::pi(), glm::pi()) - ); - } struct [[codegen::Dictionary(ScreenSpaceRenderable)]] Parameters { // The type of the Screenspace renderable that is to be created. The available @@ -668,4 +590,84 @@ void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) { void ScreenSpaceRenderable::unbindTexture() {} +glm::vec3 ScreenSpaceRenderable::sanitizeSphericalCoordinates(glm::vec3 spherical) const { + const float r = spherical.x; + float phi = spherical.z; + + // Sanitize coordinates. + float theta = wrap(spherical.y, 0.f, glm::two_pi()); + if (theta > glm::pi()) { + theta = glm::two_pi() - theta; + phi += glm::pi(); + } + + return glm::vec3(r, theta, phi); +} + +glm::vec3 ScreenSpaceRenderable::sphericalToCartesian(glm::vec3 spherical) const { + // First convert to ISO convention spherical coordinates according to + // https://en.wikipedia.org/wiki/Spherical_coordinate_system + // (radius, theta, phi), where theta is the polar angle from the z axis, + // and phi is the azimuth. + + const glm::vec3 sanitized = sanitizeSphericalCoordinates(std::move(spherical)); + const float x = sanitized[0] * sin(sanitized[1]) * cos(sanitized[2]); + const float y = sanitized[0] * sin(sanitized[1]) * sin(sanitized[2]); + const float z = sanitized[0] * cos(sanitized[1]); + + // Now, convert rotate the coordinate system, so that z maps to y, + // and y maps to -z. We want the pole to be in y instead of z. + return glm::vec3(x, -z, y); +} + +glm::vec3 ScreenSpaceRenderable::cartesianToSpherical(const glm::vec3& cartesian) const { + // Rotate cartesian coordinates. + glm::vec3 rotated = glm::vec3(cartesian.x, cartesian.z, -cartesian.y); + + const float r = sqrt( + pow(rotated.x, 2.f) + pow(rotated.y, 2.f) + pow(rotated.z, 2.f) + ); + const float theta = acos(rotated.z / r); + const float phi = atan2(rotated.y, rotated.x); + return sanitizeSphericalCoordinates(glm::vec3(r, theta, phi)); +} + +// Radius, azimiuth, elevation to spherical coordinates. +glm::vec3 ScreenSpaceRenderable::raeToSpherical(glm::vec3 rae) const { + //return rae; + const float r = rae.x; + + // Polar angle, theta, is elevation + pi/2. + const float theta = rae.z + glm::half_pi(); + + // Azimuth in ISO spherical coordiantes (phi) is angle from x, + // as opposed to from negative y on screen. + const float phi = rae.y - glm::half_pi(); + + return glm::vec3(r, theta, phi); +} + +// Spherical coordinates to radius, azimuth and elevation. +glm::vec3 ScreenSpaceRenderable::sphericalToRae(glm::vec3 spherical) const { + //return spherical; + const float r = spherical.x; + + // Azimuth on screen is angle from negative y, as opposed to from x. + float azimuth = spherical.z + glm::half_pi(); + + // Elevation is polar angle - pi/2 + float elevation = wrap( + spherical.y - glm::half_pi(), + -glm::pi(), + glm::pi() + ); + + return glm::vec3( + r, + wrap(azimuth, -glm::pi(), glm::pi()), + wrap(elevation, -glm::pi(), glm::pi()) + ); +} + + } // namespace openspace From 9c3b61aaf9ba6a05994612c8cac4295bf4faec3d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 16 Mar 2022 16:28:44 -0400 Subject: [PATCH 217/251] Ensure that the TargetBrowserPair can be found regardless if the identifier of the renderable or the node is passed to the api. This fixes a bug with the "openspace.skybrowser.adjustCamera" function --- modules/skybrowser/skybrowsermodule.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 03e7cfe233..5610623ed5 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -562,6 +562,7 @@ TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) { [&](const std::unique_ptr& pair) { bool foundBrowser = pair->browserId() == id; bool foundTarget = pair->targetRenderableId() == id; + bool foundTargetNode = pair->targetNodeId() == id; return foundBrowser || foundTarget; } ); From b405756ce9dc3687ca0b73635e8542541d2dc102 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 17 Mar 2022 09:43:24 -0400 Subject: [PATCH 218/251] Add missing files for target renderable --- .../skybrowser/include/renderableskytarget.h | 83 +++++ .../skybrowser/src/renderableskytarget.cpp | 293 ++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 modules/skybrowser/include/renderableskytarget.h create mode 100644 modules/skybrowser/src/renderableskytarget.cpp diff --git a/modules/skybrowser/include/renderableskytarget.h b/modules/skybrowser/include/renderableskytarget.h new file mode 100644 index 0000000000..85859b8a86 --- /dev/null +++ b/modules/skybrowser/include/renderableskytarget.h @@ -0,0 +1,83 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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_SKYBROWSER___RENDERABLESKYTARGET___H__ +#define __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYTARGET___H__ + +#include + +#include +#include +#include + +namespace openspace::documentation { struct Documentation; } + +namespace openspace { + +class ScreenSpaceSkyBrowser; + +class RenderableSkyTarget : public RenderablePlane { +public: + constexpr static const float DeltaTimeThreshold = 0.03f; + + explicit RenderableSkyTarget(const ghoul::Dictionary& dictionary); + + void initializeGL() override; + void deinitializeGL() override; + void render(const RenderData& data, RendererTasks& rendererTask) override; + void update(const UpdateData& data) override; + void bindTexture() override; // Empty function but has to be defined + + glm::ivec3 borderColor() const; + float opacity() const; + double animationSpeed() const; + double stopAnimationThreshold() const; + double smallestFov() const; + + void setDimensions(glm::vec2 dimensions); + void setColor(glm::ivec3 color); + void setOpacity(float opacity); + void setVerticalFov(double fov); + + // Display + void highlight(const glm::ivec3& addition); + void removeHighlight(const glm::ivec3& removal); + +private: + // Properties + properties::FloatProperty _crossHairSize; + properties::FloatProperty _showRectangleThreshold; + properties::FloatProperty _lineWidth; + properties::DoubleProperty _smallestFov; + properties::DoubleProperty _stopAnimationThreshold; + properties::DoubleProperty _animationSpeed; + + double _verticalFov = 10.0; + + glm::ivec3 _borderColor = glm::ivec3(230); + glm::vec2 _dimensions = glm::vec2(1.f); +}; +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SKYBROWSER___RENDERABLESKYTARGET___H__ diff --git a/modules/skybrowser/src/renderableskytarget.cpp b/modules/skybrowser/src/renderableskytarget.cpp new file mode 100644 index 0000000000..4f5a513057 --- /dev/null +++ b/modules/skybrowser/src/renderableskytarget.cpp @@ -0,0 +1,293 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma optimize("", off) +namespace { + constexpr const char* _loggerCat = "RenderableSkyTarget"; + + enum BlendMode { + Normal = 0, + Additive + }; + + constexpr const openspace::properties::Property::PropertyInfo crossHairSizeInfo = + { + "CrosshairSize", + "Crosshair Size", + "Determines the size of the crosshair." + }; + + constexpr const openspace::properties::Property::PropertyInfo RectangleThresholdInfo = + { + "RectangleThreshold", + "Rectangle Threshold", + "When the field of view is larger than the rectangle threshold, a rectangle will" + "be rendered in the target." + }; + + constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { + "AnimationSpeed", + "Animation Speed", + "The factor which is multiplied with the animation speed of the target." + }; + + constexpr const openspace::properties::Property::PropertyInfo AnimationThresholdInfo = + { + "AnimationThreshold", + "Animation Threshold", + "The threshold for when the target is determined to have appeared at its " + "destination. Angle in radians between the destination and the target position " + "in equatorial Cartesian coordinate system." + }; + + constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = { + "LineWidth", + "Line Width", + "The thickness of the line of the target. The larger number, the thicker line." + }; + + constexpr const openspace::properties::Property::PropertyInfo SmallestFovInfo = { + "SmallestFov", + "Smallest Vertical Field Of View", + "The smallest field of view that the target will display on screen." + }; + + struct [[codegen::Dictionary(RenderableSkyTarget)]] Parameters { + // [[codegen::verbatim(crossHairSizeInfo.description)]] + std::optional crossHairSize; + + // [[codegen::verbatim(RectangleThresholdInfo.description)]] + std::optional rectangleThreshold; + + // [[codegen::verbatim(AnimationSpeedInfo.description)]] + std::optional animationSpeed; + + // [[codegen::verbatim(AnimationThresholdInfo.description)]] + std::optional animationThreshold; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(SmallestFovInfo.description)]] + std::optional smallestFov; + }; + +#include "renderableskytarget_codegen.cpp" +} //namespace + +namespace openspace { + RenderableSkyTarget::RenderableSkyTarget(const ghoul::Dictionary& dictionary) + : RenderablePlane(dictionary) + , _crossHairSize(crossHairSizeInfo, 2.f, 1.f, 10.f) + , _showRectangleThreshold(RectangleThresholdInfo, 5.f, 0.1f, 70.f) + , _stopAnimationThreshold(AnimationThresholdInfo, 5.0f, 1.f, 10.f) + , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) + , _lineWidth(LineWidthInfo, 13.f, 1.f, 100.f) + , _smallestFov(SmallestFovInfo, 3.0, 0.5, 20.0) + , _borderColor(220, 220, 220) + { + // Handle target dimension property + const Parameters p = codegen::bake(dictionary); + _crossHairSize = p.crossHairSize.value_or(_crossHairSize); + _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); + _stopAnimationThreshold = p.crossHairSize.value_or(_stopAnimationThreshold); + _animationSpeed = p.animationSpeed.value_or(_animationSpeed); + _smallestFov = p.smallestFov.value_or(_smallestFov); + + addProperty(_crossHairSize); + addProperty(_showRectangleThreshold); + addProperty(_stopAnimationThreshold); + addProperty(_animationSpeed); + addProperty(_lineWidth); + addProperty(_smallestFov); +} + +void RenderableSkyTarget::bindTexture() {} + +void RenderableSkyTarget::initializeGL() { + glGenVertexArrays(1, &_quad); // generate array + glGenBuffers(1, &_vertexPositionBuffer); // generate buffer + createPlane(); + + std::string ProgramName = identifier() + "Shader"; + + _shader = BaseModule::ProgramObjectManager.request( + ProgramName, + [&]() -> std::unique_ptr { + return global::renderEngine->buildRenderProgram( + ProgramName, + absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"), + absPath("${MODULE_SKYBROWSER}/shaders/target_fs.glsl") + ); + } + ); +} + +void RenderableSkyTarget::deinitializeGL() { + RenderablePlane::deinitializeGL(); +} + +void RenderableSkyTarget::setColor(glm::ivec3 color) { + _borderColor = std::move(color); +} + +glm::ivec3 RenderableSkyTarget::borderColor() const { + return _borderColor; +} + + +void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) { + ZoneScoped + bool showRectangle = _verticalFov > _showRectangleThreshold; + + glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() }; + + _shader->activate(); + _shader->setUniform("opacity", _opacity); + + _shader->setUniform("crossHairSize", _crossHairSize); + _shader->setUniform("showRectangle", showRectangle); + _shader->setUniform("lineWidth", _lineWidth); + _shader->setUniform("dimensions", _dimensions); + _shader->setUniform("lineColor", color); + _shader->setUniform("fov", static_cast(_verticalFov)); + + glm::dvec3 objectPositionWorld = glm::dvec3( + glm::translate( + glm::dmat4(1.0), + data.modelTransform.translation) * glm::dvec4(0.0, 0.0, 0.0, 1.0) + ); + + glm::dvec3 normal = glm::normalize(data.camera.positionVec3() - objectPositionWorld); + glm::dvec3 newRight = glm::normalize( + glm::cross(data.camera.lookUpVectorWorldSpace(), normal) + ); + glm::dvec3 newUp = glm::cross(normal, newRight); + + glm::dmat4 cameraOrientedRotation = glm::dmat4(1.0); + cameraOrientedRotation[0] = glm::dvec4(newRight, 0.0); + cameraOrientedRotation[1] = glm::dvec4(newUp, 0.0); + cameraOrientedRotation[2] = glm::dvec4(normal, 0.0); + + const glm::dmat4 rotationTransform = _billboard ? + cameraOrientedRotation : + glm::dmat4(data.modelTransform.rotation); + + const glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + rotationTransform * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)) * + glm::dmat4(1.0); + const glm::dmat4 modelViewTransform = + data.camera.combinedViewMatrix() * modelTransform; + + _shader->setUniform("modelViewProjectionTransform", + data.camera.projectionMatrix() * glm::mat4(modelViewTransform)); + + _shader->setUniform("modelViewTransform", + glm::mat4(data.camera.combinedViewMatrix() * glm::dmat4(modelViewTransform))); + + _shader->setUniform("multiplyColor", _multiplyColor); + + bool additiveBlending = (_blendMode == static_cast(BlendMode::Additive)); + if (additiveBlending) { + glDepthMask(false); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + + glBindVertexArray(_quad); + glEnable(GL_LINE_SMOOTH); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisable(GL_LINE_SMOOTH); + glBindVertexArray(0); + + if (additiveBlending) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(true); + } + + _shader->deactivate(); +} + +void RenderableSkyTarget::update(const UpdateData& data) { + RenderablePlane::update(data); + +} + +void RenderableSkyTarget::setDimensions(glm::vec2 dimensions) { + // To avoid flooring of the size of the target, multiply by factor of 100 + // Object size is really the pixel size so this calculation is not exact + _dimensions = glm::ivec2(dimensions * 100.f); +} + +void RenderableSkyTarget::highlight(const glm::ivec3& addition) { + _borderColor += addition; +} + +void RenderableSkyTarget::removeHighlight(const glm::ivec3& removal) { + _borderColor -= removal; +} + +float RenderableSkyTarget::opacity() const { + return _opacity; +} + +double RenderableSkyTarget::animationSpeed() const { + return _animationSpeed; +} + +double RenderableSkyTarget::stopAnimationThreshold() const { + return _stopAnimationThreshold * 0.0001; +} + +double RenderableSkyTarget::smallestFov() const { + return _smallestFov; +} + +void RenderableSkyTarget::setOpacity(float opacity) { + _opacity = opacity; +} + +void RenderableSkyTarget::setVerticalFov(double fov) { + _verticalFov = fov; +} +} // namespace openspace From 128d21b7598c1b92f04c931ac515c553a32dce3e Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 17 Mar 2022 10:36:04 -0400 Subject: [PATCH 219/251] Transform the hovercircle to a renderable so it works in a dome environment --- data/assets/hoverCircle.asset | 40 +++++++++++---------- modules/skybrowser/skybrowsermodule.cpp | 24 +++++-------- modules/skybrowser/skybrowsermodule.h | 4 +-- modules/skybrowser/skybrowsermodule_lua.inl | 3 +- 4 files changed, 34 insertions(+), 37 deletions(-) diff --git a/data/assets/hoverCircle.asset b/data/assets/hoverCircle.asset index 2a00549c29..f5673b1bd3 100644 --- a/data/assets/hoverCircle.asset +++ b/data/assets/hoverCircle.asset @@ -1,25 +1,29 @@ -local id = "HoverCircle" +-- This asset requires OpenSpace to be built with the OPENSPACE_MODULE_SPOUT enabled + +local transforms = asset.require("scene/solarsystem/sun/transforms") local circle = { - Identifier = id, - Type = "ScreenSpaceImageLocal", - Name = "HoverCircle", - FaceCamera = false, - UseRadiusAzimuthElevation = false, - RadiusAzimuthElevation = { 1.0, 0.0, 0.0 }, -- use for dome - Scale = 0.025, - Enabled = false, - TexturePath = "${ASSETS}/circle.png", - CartesianPosition = { 0, 0, -2.1 }, -}; + Identifier = "hoverCircle", + Parent = transforms.SolarSystemBarycenter.Identifier, + Renderable = { + Type = "RenderablePlaneImageLocal", + Size = 3.0E15, + Origin = "Center", + Billboard = true, + Texture = "${ASSETS}/circle.png" + }, + GUI = { + Path = "/SkyBrowser" + } +} -asset.onInitialize(function () - openspace.addScreenSpaceRenderable(circle) - openspace.skybrowser.setHoverCircle(id) +asset.onInitialize(function() + openspace.addSceneGraphNode(circle) + openspace.skybrowser.setHoverCircle('hoverCircle') end) -asset.onDeinitialize(function () - openspace.removeScreenSpaceRenderable(circle) +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(circle) end) -asset.export("circle", circle) +asset.export(circle) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 5610623ed5..2905df7f48 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -481,7 +481,7 @@ void SkyBrowserModule::lookAtTarget(const std::string& id) { } } -void SkyBrowserModule::setHoverCircle(ScreenSpaceImageLocal* circle) { +void SkyBrowserModule::setHoverCircle(SceneGraphNode* circle) { _hoverCircle = circle; } @@ -491,26 +491,20 @@ void SkyBrowserModule::moveHoverCircle(int i) { // Only move and show circle if the image has coordinates if (_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem) { // Make circle visible - _hoverCircle->setEnabled(true); + _hoverCircle->renderable()->property("Enabled")->set(true); // Set the exact target position - glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(image.equatorialCartesian); - - if (_hoverCircle->isUsingRaeCoords()) { - glm::vec3 position = _hoverCircle->raePosition().x * glm::vec3(localCamera); - _hoverCircle->setRaeFromCartesianPosition(position); - } - else { - _hoverCircle->setCartesianPosition( - skybrowser::localCameraToScreenSpace3d(localCamera) - ); - } + // Move it slightly outside of the celestial sphere so it doesn't overlap with + // the target + glm::dvec3 pos = skybrowser::equatorialToGalactic(image.equatorialCartesian); + pos *= skybrowser::CelestialSphereRadius * 1.1; + _hoverCircle->property("Translation.Position")->set(pos); } } void SkyBrowserModule::disableHoverCircle() { - if (_hoverCircle && _hoverCircle->isEnabled()) { - _hoverCircle->setEnabled(false); + if (_hoverCircle && _hoverCircle->renderable()) { + _hoverCircle->renderable()->property("Enabled")->set(false); } } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 53bc7c0197..f754e7f567 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -72,7 +72,7 @@ public: void setSelectedBrowser(const std::string& id); void setSelectedObject(); // Manage mouse interactions - void setHoverCircle(ScreenSpaceImageLocal* circle); + void setHoverCircle(SceneGraphNode* circle); // Rotation, animation, placement void lookAtTarget(const std::string& id); @@ -115,7 +115,7 @@ private: // The browsers and targets std::vector> _targetsBrowsers; TargetBrowserPair* _mouseOnPair = nullptr; - ScreenSpaceImageLocal* _hoverCircle = nullptr; + SceneGraphNode* _hoverCircle = nullptr; std::string _selectedBrowser = ""; // Currently selected browser // Fading diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 6cc71deddc..33c6306156 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -73,8 +73,7 @@ int setHoverCircle(lua_State* L) { SkyBrowserModule* module = global::moduleEngine->module(); std::string id = ghoul::lua::value(L, 1); - ScreenSpaceImageLocal* circle = dynamic_cast( - global::renderEngine->screenSpaceRenderable(id)); + SceneGraphNode* circle = global::renderEngine->scene()->sceneGraphNode(id); module->setHoverCircle(circle); return 0; From 220c1090d2745454342c295a80d9301409c78258 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 17 Mar 2022 10:54:45 -0400 Subject: [PATCH 220/251] Make copies of screenspacebrowser look at camera --- modules/skybrowser/src/screenspaceskybrowser.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 959b7472f2..840f3879e8 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -270,20 +270,30 @@ void ScreenSpaceSkyBrowser::render() { // Render a copy that is not interactive if (_renderCopy1) { glm::vec3 spherical = sphericalToCartesian(raeToSpherical(_copyPosition1)); + glm::mat4 localRotation = glm::inverse(glm::lookAt( + glm::vec3(0.f), + glm::normalize(spherical), + glm::vec3(0.f, 1.f, 0.f) + )); draw( globalRotationMatrix() * - glm::translate(glm::mat4(1.f), spherical)* - localRotationMatrix() * + glm::translate(glm::mat4(1.f), spherical) * + localRotation * scaleMatrix() ); } // Render a copy that is not interactive if (_renderCopy2) { glm::vec3 spherical = sphericalToCartesian(raeToSpherical(_copyPosition2)); + glm::mat4 localRotation = glm::inverse(glm::lookAt( + glm::vec3(0.f), + glm::normalize(spherical), + glm::vec3(0.f, 1.f, 0.f) + )); draw( globalRotationMatrix() * glm::translate(glm::mat4(1.f), spherical) * - localRotationMatrix() * + localRotation * scaleMatrix() ); } From ea77f74731257e219412dd29a8b5982878f42058 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 17 Mar 2022 11:53:12 -0400 Subject: [PATCH 221/251] Make it possible to add n number of additional rendered copies of the sky browser, that can be placed with RAE coordinates --- .../include/screenspaceskybrowser.h | 11 +-- modules/skybrowser/skybrowsermodule.cpp | 15 ++- modules/skybrowser/skybrowsermodule_lua.inl | 29 ++++++ .../skybrowser/src/screenspaceskybrowser.cpp | 98 +++++-------------- 4 files changed, 73 insertions(+), 80 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 596f66db34..1d796326b2 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -54,11 +54,9 @@ public: void startFovAnimation(float fov); void incrementallyAnimateToFov(float deltaTime); - // Getters float opacity() const; glm::vec2 size() const; - // Setters void setVerticalFovWithScroll(float scroll); void setOpacity(float opacity); void setScreenSpaceSize(const glm::vec2& newSize); @@ -69,13 +67,14 @@ public: void updateTextureResolution(); + // Copies rendered + void addRenderCopy(); + void removeRenderCopy(); + private: properties::DoubleProperty _animationSpeed; properties::FloatProperty _textureQuality; - properties::BoolProperty _renderCopy1; - properties::Vec3Property _copyPosition1; - properties::BoolProperty _renderCopy2; - properties::Vec3Property _copyPosition2; + std::vector> _renderCopies; void bindTexture() override; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 2905df7f48..2ee82eaf79 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -250,7 +250,20 @@ namespace openspace { "string, float, float, float, float", "Takes an identifier to a sky browser or sky target and the [x, y] " "starting position and the [x, y] translation vector." - }, + }, + { + "addRenderCopy", + &skybrowser::luascriptfunctions::addRenderCopy, + "string", + "Takes an identifier to a sky browser and adds a rendered copy to it." + }, + { + "removeRenderCopy", + &skybrowser::luascriptfunctions::removeRenderCopy, + "string", + "Takes an identifier to a sky browser and removes the latest added " + "rendered copy to it." + }, }; return res; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 33c6306156..4e0d1abcdf 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -596,5 +596,34 @@ int setScreenSpaceSize(lua_State* L) { } return 0; } + +int addRenderCopy(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addRenderCopy"); + auto [id] = ghoul::lua::values(L); + + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + TargetBrowserPair* pair = module->getPair(id); + if (pair) { + pair->browser()->addRenderCopy(); + } + return 0; +} + + +int removeRenderCopy(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeRenderCopy"); + auto [id] = ghoul::lua::values(L); + + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + TargetBrowserPair* pair = module->getPair(id); + if (pair) { + pair->browser()->removeRenderCopy(); + } + return 0; +} } // namespace openspace::skybrowser::luafunctions diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 840f3879e8..bc7f185ee6 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -54,30 +54,11 @@ namespace { "frame rate." }; - constexpr const openspace::properties::Property::PropertyInfo RenderCopy1Info = { - "RenderCopy1", - "Render A Copy Of The Sky Browser", + constexpr const openspace::properties::Property::PropertyInfo RenderCopyInfo = { + "RenderCopy", + "RAE Position Of A Copy Of The Sky Browser", "Render a copy of this sky browser at an additional position. This copy will not " - "be interactive." - }; - - constexpr const openspace::properties::Property::PropertyInfo CopyPosition1Info = { - "CopyPosition1", - "Position Of First Copy Of Sky Browser", - "The (radius, azimuth, elevation) position where the copy will be placed. " - }; - - constexpr const openspace::properties::Property::PropertyInfo RenderCopy2Info = { - "RenderCopy2", - "Render An Additional Copy Of The Sky Browser", - "Render a copy of this sky browser at an additional position. This copy will not " - "be interactive." - }; - - constexpr const openspace::properties::Property::PropertyInfo CopyPosition2Info = { - "CopyPosition2", - "Position Of Second Copy Of Sky Browser", - "The (radius, azimuth, elevation) position where the copy will be placed. " + "be interactive. The position is in RAE (Radius, Azimuth, Elevation) coordinates." }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { @@ -86,18 +67,6 @@ namespace { // [[codegen::verbatim(TextureQualityInfo.description)]] std::optional textureQuality; - - // [[codegen::verbatim(RenderCopy1Info.description)]] - std::optional renderCopy1; - - // [[codegen::verbatim(CopyPosition1Info.description)]] - std::optional copyPosition1; - - // [[codegen::verbatim(RenderCopy2Info.description)]] - std::optional renderCopy2; - - // [[codegen::verbatim(CopyPosition2Info.description)]] - std::optional copyPosition2; }; #include "screenspaceskybrowser_codegen.cpp" @@ -130,18 +99,6 @@ namespace openspace { , WwtCommunicator(dictionary) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) - , _renderCopy1(RenderCopy1Info) - , _copyPosition1(CopyPosition1Info, - glm::vec3(2.1f, 0.f, 0.f), - glm::vec3(-4.f, -4.f, 0.f), - glm::vec3(4.f, 4.f, 10.f) - ) - , _renderCopy2(RenderCopy2Info) - , _copyPosition2(CopyPosition2Info, - glm::vec3(2.1f, 0.f, 0.f), - glm::vec3(-4.f, -4.f, 0.f), - glm::vec3(4.f, 4.f, 10.f) - ) { _identifier = makeUniqueIdentifier(_identifier); @@ -149,19 +106,11 @@ namespace openspace { const Parameters p = codegen::bake(dictionary); _textureQuality = p.textureQuality.value_or(_textureQuality); _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - _renderCopy1 = p.renderCopy1.value_or(_renderCopy1); - _copyPosition1 = p.copyPosition1.value_or(_copyPosition1); - _renderCopy2 = p.renderCopy1.value_or(_renderCopy2); - _copyPosition2 = p.copyPosition1.value_or(_copyPosition2); addProperty(_url); addProperty(_browserPixeldimensions); addProperty(_reload); addProperty(_textureQuality); - addProperty(_renderCopy1); - addProperty(_copyPosition1); - addProperty(_renderCopy2); - addProperty(_copyPosition2); _textureQuality.onChange([this]() { _textureDimensionsIsDirty = true; @@ -227,6 +176,25 @@ void ScreenSpaceSkyBrowser::updateTextureResolution() { _objectSize = glm::ivec3(_texture->dimensions()); } +void ScreenSpaceSkyBrowser::addRenderCopy() { + openspace::properties::Property::PropertyInfo info = RenderCopyInfo; + info.identifier += _renderCopies.size(); + _renderCopies.push_back( + std::make_unique( + info, + glm::vec3(2.1f, 0.f, 0.f), + glm::vec3(0.f, -glm::pi(), -glm::half_pi()), + glm::vec3(10.f, glm::pi(), glm::half_pi()) + ) + ); + addProperty(_renderCopies.back().get()); +} + +void ScreenSpaceSkyBrowser::removeRenderCopy() { + removeProperty(_renderCopies.back().get()); + _renderCopies.pop_back(); +} + bool ScreenSpaceSkyBrowser::deinitializeGL() { ScreenSpaceRenderable::deinitializeGL(); WwtCommunicator::deinitializeGL(); @@ -268,8 +236,8 @@ void ScreenSpaceSkyBrowser::render() { ); // Render a copy that is not interactive - if (_renderCopy1) { - glm::vec3 spherical = sphericalToCartesian(raeToSpherical(_copyPosition1)); + for (const std::unique_ptr& copy : _renderCopies) { + glm::vec3 spherical = sphericalToCartesian(raeToSpherical(copy.get()->value())); glm::mat4 localRotation = glm::inverse(glm::lookAt( glm::vec3(0.f), glm::normalize(spherical), @@ -282,22 +250,6 @@ void ScreenSpaceSkyBrowser::render() { scaleMatrix() ); } - // Render a copy that is not interactive - if (_renderCopy2) { - glm::vec3 spherical = sphericalToCartesian(raeToSpherical(_copyPosition2)); - glm::mat4 localRotation = glm::inverse(glm::lookAt( - glm::vec3(0.f), - glm::normalize(spherical), - glm::vec3(0.f, 1.f, 0.f) - )); - draw( - globalRotationMatrix() * - glm::translate(glm::mat4(1.f), spherical) * - localRotation * - scaleMatrix() - ); - } - } void ScreenSpaceSkyBrowser::update() { From a34beec441198f5d241de79f2f248ae64f738c49 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 21 Mar 2022 11:54:58 -0400 Subject: [PATCH 222/251] Use the latest commit on the sky browser gui as default --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 3be431b3ef..2624f02aee 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require("./static_server") local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "aa9aa521ace55cc25f447d287d34624f2cb56832" +local frontendHash = "234ddc8975ff03fd45708f9668c92bd31f7e79e8" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From bf559c560503ce6f9bbc10a6c253b998815dee8a Mon Sep 17 00:00:00 2001 From: Micah Date: Mon, 21 Mar 2022 13:08:26 -0400 Subject: [PATCH 223/251] update cef and a few calls for it --- modules/webbrowser/CMakeLists.txt | 11 ++++++----- .../cmake/patch/cmake/cef_variables.cmake | 10 +++------- .../webbrowser/include/defaultbrowserlauncher.h | 16 +++++++++++----- modules/webbrowser/src/browserinstance.cpp | 3 ++- .../webbrowser/src/defaultbrowserlauncher.cpp | 1 + modules/webbrowser/src/screenspacebrowser.cpp | 8 +++++--- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/modules/webbrowser/CMakeLists.txt b/modules/webbrowser/CMakeLists.txt index 79592629a2..f311990365 100644 --- a/modules/webbrowser/CMakeLists.txt +++ b/modules/webbrowser/CMakeLists.txt @@ -55,14 +55,15 @@ cmake_policy(SET CMP0074 NEW) # Specify the CEF distribution version. -# Release from 04/24/2019 verified to work on Windows. -set(CEF_VERSION "73.1.13+g6e3c989+chromium-73.0.3683.75") +# Release from 03/21/2022 verified to work on Windows. +set(CEF_VERSION "99.2.12+g2977b3a+chromium-99.0.4844.74") +# Removing - micahnyc 03/21/2022 # 73.1.13 has an issue on MacOS: The GUI freezing upon interaction. # Therefore, we fall back to 3.3578.1867 from 01/29/2019 -if (APPLE) - set(CEF_VERSION "3.3578.1867.g0f6d65a") -endif () +#if (APPLE) +# set(CEF_VERSION "3.3578.1867.g0f6d65a") +#endif () # CEF Sandbox is not working with the latest Visual Studio, so we disable it for now. if (WIN32) diff --git a/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake b/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake index a1089c036e..82de3fb69c 100644 --- a/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake +++ b/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake @@ -456,12 +456,10 @@ if(OS_WINDOWS) # List of CEF binary files. set(CEF_BINARY_FILES chrome_elf.dll - d3dcompiler_43.dll d3dcompiler_47.dll libcef.dll libEGL.dll libGLESv2.dll - natives_blob.bin snapshot_blob.bin v8_context_snapshot.bin #swiftshader @@ -469,11 +467,9 @@ if(OS_WINDOWS) # List of CEF resource files. set(CEF_RESOURCE_FILES - cef.pak - cef_100_percent.pak - cef_200_percent.pak - cef_extensions.pak - devtools_resources.pak + chrome_100_percent.pak + chrome_200_percent.pak + resources.pak icudtl.dat locales ) diff --git a/modules/webbrowser/include/defaultbrowserlauncher.h b/modules/webbrowser/include/defaultbrowserlauncher.h index 1d5abc176d..86704ab033 100644 --- a/modules/webbrowser/include/defaultbrowserlauncher.h +++ b/modules/webbrowser/include/defaultbrowserlauncher.h @@ -41,11 +41,17 @@ namespace openspace { class DefaultBrowserLauncher : public CefLifeSpanHandler, public CefRequestHandler { public: - bool OnBeforePopup(CefRefPtr browser, CefRefPtr frame, - const CefString& targetUrl, const CefString& targetFrameName, - CefLifeSpanHandler::WindowOpenDisposition targetDisposition, bool userGesture, - const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, - CefRefPtr& client, CefBrowserSettings& settings, + bool OnBeforePopup(CefRefPtr browser, + CefRefPtr frame, + const CefString& targetUrl, + const CefString& targetFrameName, + CefLifeSpanHandler::WindowOpenDisposition targetDisposition, + bool userGesture, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + CefRefPtr& client, + CefBrowserSettings& settings, + CefRefPtr& extra_info, bool* noJavascriptAccess) override; //bool OnOpenURLFromTab(CefRefPtr browser, CefRefPtr frame, diff --git a/modules/webbrowser/src/browserinstance.cpp b/modules/webbrowser/src/browserinstance.cpp index f56997d391..2ecd5995e8 100644 --- a/modules/webbrowser/src/browserinstance.cpp +++ b/modules/webbrowser/src/browserinstance.cpp @@ -48,7 +48,7 @@ BrowserInstance::BrowserInstance(WebRenderHandler* renderer, : _renderHandler(renderer) , _keyboardHandler(keyboardHandler) { - _client = new BrowserClient(_renderHandler, _keyboardHandler); + _client = new BrowserClient(renderer, keyboardHandler); CefWindowInfo windowInfo; windowInfo.SetAsWindowless(nullptr); @@ -62,6 +62,7 @@ BrowserInstance::BrowserInstance(WebRenderHandler* renderer, _client.get(), url, browserSettings, + nullptr, nullptr ); diff --git a/modules/webbrowser/src/defaultbrowserlauncher.cpp b/modules/webbrowser/src/defaultbrowserlauncher.cpp index 6b3558d687..30c290f818 100644 --- a/modules/webbrowser/src/defaultbrowserlauncher.cpp +++ b/modules/webbrowser/src/defaultbrowserlauncher.cpp @@ -38,6 +38,7 @@ bool DefaultBrowserLauncher::OnBeforePopup(CefRefPtr, CefRefPtr&, CefBrowserSettings&, + CefRefPtr&, bool*) { // never permit CEF popups, always launch in default browser diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index d03292ed5f..9721690043 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -92,10 +92,12 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary& dictionary) _dimensions = windowDimensions; _renderHandler = new ScreenSpaceRenderHandler; - _keyboardHandler = new WebKeyboardHandler(); + WebRenderHandler* renderer = (WebRenderHandler*)(&_renderHandler); + WebKeyboardHandler* keyboardHandler = new WebKeyboardHandler(); + _keyboardHandler = keyboardHandler; _browserInstance = std::make_unique( - _renderHandler, - _keyboardHandler + renderer, + keyboardHandler ); _url.onChange([this]() { _isUrlDirty = true; }); From 440dfa32c709dbc69f05a1c9dafe7c67d7ed1646 Mon Sep 17 00:00:00 2001 From: Micah Date: Mon, 21 Mar 2022 16:14:49 -0400 Subject: [PATCH 224/251] fixing ref ptf for cef --- modules/webbrowser/src/browserinstance.cpp | 2 +- modules/webbrowser/src/screenspacebrowser.cpp | 8 +++----- modules/webbrowser/src/webbrowserapp.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/webbrowser/src/browserinstance.cpp b/modules/webbrowser/src/browserinstance.cpp index 2ecd5995e8..40299d98c4 100644 --- a/modules/webbrowser/src/browserinstance.cpp +++ b/modules/webbrowser/src/browserinstance.cpp @@ -48,7 +48,7 @@ BrowserInstance::BrowserInstance(WebRenderHandler* renderer, : _renderHandler(renderer) , _keyboardHandler(keyboardHandler) { - _client = new BrowserClient(renderer, keyboardHandler); + _client = new BrowserClient(_renderHandler.get(), _keyboardHandler.get()); CefWindowInfo windowInfo; windowInfo.SetAsWindowless(nullptr); diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 9721690043..d166b5e139 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -92,12 +92,10 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary& dictionary) _dimensions = windowDimensions; _renderHandler = new ScreenSpaceRenderHandler; - WebRenderHandler* renderer = (WebRenderHandler*)(&_renderHandler); - WebKeyboardHandler* keyboardHandler = new WebKeyboardHandler(); - _keyboardHandler = keyboardHandler; + _keyboardHandler = new WebKeyboardHandler(); _browserInstance = std::make_unique( - renderer, - keyboardHandler + _renderHandler.get(), + _keyboardHandler.get() ); _url.onChange([this]() { _isUrlDirty = true; }); diff --git a/modules/webbrowser/src/webbrowserapp.cpp b/modules/webbrowser/src/webbrowserapp.cpp index 05b2f93ccd..d0f7e7d044 100644 --- a/modules/webbrowser/src/webbrowserapp.cpp +++ b/modules/webbrowser/src/webbrowserapp.cpp @@ -42,8 +42,10 @@ void WebBrowserApp::OnContextCreated(CefRefPtr, CefRefPtr, void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&, CefRefPtr commandLine) { - commandLine->AppendSwitch("disable-gpu"); - commandLine->AppendSwitch("disable-gpu-compositing"); + commandLine->AppendSwitch("use-gl=desktop"); + commandLine->AppendSwitch("ignore-gpu-blacklist"); + commandLine->AppendSwitch("log-gpu-control-list-decisions"); + commandLine->AppendSwitch("enable-begin-frame-scheduling"); commandLine->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required"); } From 5bbf7d3d33a63c185c6b218e013820fab1ebc107 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 22 Mar 2022 16:01:34 -0400 Subject: [PATCH 225/251] Fixes after merging in new cef version and master --- modules/skybrowser/skybrowsermodule.cpp | 237 ++-------- modules/skybrowser/skybrowsermodule_lua.inl | 461 ++++++++++---------- modules/skybrowser/src/browser.cpp | 4 +- 3 files changed, 266 insertions(+), 436 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 2ee82eaf79..7983c9179f 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -24,17 +24,16 @@ #include +#include #include #include -#include #include -#include -#include -#include +#include #include #include #include -#include +#include +#include #include #include "skybrowsermodule_lua.inl" @@ -76,199 +75,6 @@ namespace { } // namespace namespace openspace { - scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "skybrowser"; - res.functions = { - { - "getListOfImages", - &skybrowser::luascriptfunctions::getListOfImages, - "", - "Returns a list of all the loaded AAS WorldWide Telescope images that " - "have been loaded. Each image has a name, thumbnail url, equatorial " - "spherical coordinates RA and Dec, equatorial Cartesian coordinates, " - "if the image has celestial coordinates, credits text, credits url " - "and the identifier of the image which is a unique number." - }, - { - "setHoverCircle", - &skybrowser::luascriptfunctions::setHoverCircle, - "string", - "Takes an identifier to a screen space renderable and adds it to the " - "module." - }, - { - "moveCircleToHoverImage", - &skybrowser::luascriptfunctions::moveCircleToHoverImage, - "int", - "Moves the hover circle to the coordinate specified by the image index." - }, - { - "disableHoverCircle", - &skybrowser::luascriptfunctions::disableHoverCircle, - "", - "Disables the hover circle, if there is one added to the sky browser " - "module." - }, - { - "loadImagesToWWT", - &skybrowser::luascriptfunctions::loadImagesToWWT, - "string", - "Takes an identifier to a sky browser or target and loads the WWT image " - "collection to that browser." - }, - { - "selectImage", - &skybrowser::luascriptfunctions::selectImage, - "int", - "Takes an index to an image and selects that image in the currently " - "selected sky browser." - }, - { - "removeSelectedImageInBrowser", - &skybrowser::luascriptfunctions::removeSelectedImageInBrowser, - "string, int", - "Takes an identifier to a sky browser or target and an index to an " - "image. Removes that image from that sky browser." - }, - { - "adjustCamera", - & skybrowser::luascriptfunctions::adjustCamera, - "string", - "Takes an identifier to a sky browser or sky target. Rotates the camera " - "so that the target is placed in the center of the view." - }, - { - "setSelectedBrowser", - & skybrowser::luascriptfunctions::setSelectedBrowser, - "string", - "Takes an identifier to a sky browser or target. Sets that sky browser " - "currently selected." - }, - { - "getTargetData", - &skybrowser::luascriptfunctions::getTargetData, - "", - "Returns a table of data regarding the current view and the sky browsers " - "and targets." - }, - { - "createTargetBrowserPair", - &skybrowser::luascriptfunctions::createTargetBrowserPair, - "", - "Creates a sky browser and a target." - }, - { - "removeTargetBrowserPair", - &skybrowser::luascriptfunctions::removeTargetBrowserPair, - "string", - "Takes in identifier to a sky browser or target and removes them." - }, - { - "setOpacityOfImageLayer", - &skybrowser::luascriptfunctions::setOpacityOfImageLayer, - "string, int, double", - "Takes an identifier to a sky browser or sky target, an index to an image" - "and a value for the opacity." - }, - { - "sendOutIdsToBrowsers", - &skybrowser::luascriptfunctions::sendOutIdsToBrowsers, - "", - "Sends all sky browsers' identifiers to their respective CEF browser. " - }, - { - "initializeBrowser", - &skybrowser::luascriptfunctions::initializeBrowser, - "string", - "Takes an identifier to a sky browser and starts the initialization " - "for that browser. That means that the browser starts to try to connect " - "to the AAS WorldWide Telescope application by sending it messages. And " - "that the target matches its appearance to its corresponding browser." - }, - { - "centerTargetOnScreen", - &skybrowser::luascriptfunctions::centerTargetOnScreen, - "string", - "Takes an identifier to a sky browser and animates its corresponding " - "target to the center of the current view." - }, - { - "setImageLayerOrder", - &skybrowser::luascriptfunctions::setImageLayerOrder, - "string, int, int", - "Takes an identifier to a sky browser or a sky target, an image index " - "and the order which it should have in the selected image list. The " - "image is then changed to have this order." - }, - { - "addPairToSkyBrowserModule", - &skybrowser::luascriptfunctions::addPairToSkyBrowserModule, - "string, string", - "Takes the identifier of the sky target and a sky browser and adds them " - "to the sky browser module." - }, - { - "setEquatorialAim", - &skybrowser::luascriptfunctions::setEquatorialAim, - "string, double, double", - "Takes the identifier of a sky browser or a sky target and equatorial " - "coordinates Right Ascension and Declination. The target will animate to " - "this coordinate and the browser will display the coordinate." - }, - { - "setVerticalFov", - &skybrowser::luascriptfunctions::setVerticalFov, - "string, float", - "Takes an identifier to a sky browser or a sky target and a vertical " - "field of view. Changes the field of view as specified by the input." - }, - { - "setBorderColor", - &skybrowser::luascriptfunctions::setBorderColor, - "string, int, int, int", - "Takes an identifier to a sky browser or a sky target and a rgb color " - "in the ranges [0, 255]." - }, - { - "setScreenSpaceSize", - &skybrowser::luascriptfunctions::setScreenSpaceSize, - "string, float, float", - "Sets the screen space size of the sky browser to the numbers specified " - "by the input [x, y]." - }, - { - "startSetup", - &skybrowser::luascriptfunctions::startSetup, - "", - "Starts the setup process of the sky browers. This function calls " - "the lua function 'sendOutIdsToBrowsers' in all nodes in the cluster." - }, - { - "translateScreenSpaceRenderable", - &skybrowser::luascriptfunctions::translateScreenSpaceRenderable, - "string, float, float, float, float", - "Takes an identifier to a sky browser or sky target and the [x, y] " - "starting position and the [x, y] translation vector." - }, - { - "addRenderCopy", - &skybrowser::luascriptfunctions::addRenderCopy, - "string", - "Takes an identifier to a sky browser and adds a rendered copy to it." - }, - { - "removeRenderCopy", - &skybrowser::luascriptfunctions::removeRenderCopy, - "string", - "Takes an identifier to a sky browser and removes the latest added " - "rendered copy to it." - }, - }; - - return res; - } - SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _allowMouseInteraction(AllowInteractionInfo, true) @@ -702,4 +508,39 @@ bool SkyBrowserModule::isSelectedPairFacingCamera() { return false; } } + +scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { + return { + "skybrowser", + { + codegen::lua::StartSetup, + codegen::lua::InitializeBrowser, + codegen::lua::SendOutIdsToBrowsers, + codegen::lua::GetListOfImages, + codegen::lua::SetHoverCircle, + codegen::lua::MoveCircleToHoverImage, + codegen::lua::DisableHoverCircle, + codegen::lua::LoadImagesToWWT, + codegen::lua::SelectImage, + codegen::lua::RemoveSelectedImageInBrowser, + codegen::lua::AdjustCamera, + codegen::lua::SetSelectedBrowser, + codegen::lua::GetTargetData, + codegen::lua::CreateTargetBrowserPair, + codegen::lua::RemoveTargetBrowserPair, + codegen::lua::SetOpacityOfImageLayer, + codegen::lua::CenterTargetOnScreen, + codegen::lua::SetImageLayerOrder, + codegen::lua::AddPairToSkyBrowserModule, + codegen::lua::SetEquatorialAim, + codegen::lua::SetVerticalFov, + codegen::lua::SetBorderColor, + codegen::lua::TranslateScreenSpaceRenderable, + codegen::lua::AddRenderCopy, + codegen::lua::SetScreenSpaceSize, + codegen::lua::RemoveRenderCopy + } + }; +} + } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4e0d1abcdf..5fc2d35bfb 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -25,8 +25,8 @@ #include #include -#include #include +#include #include #include #include @@ -35,14 +35,16 @@ namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; -} // namespace -namespace openspace::skybrowser::luascriptfunctions { + using namespace openspace; -int selectImage(lua_State* L) { +/** +* Takes an index to an image and selects that image in the currently +* selected sky browser. +* \param i Index of image +*/ +[[codegen::luawrap]] void selectImage(int i) { // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); - const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->isCameraInSolarSystem()) { @@ -53,66 +55,68 @@ int selectImage(lua_State* L) { LINFO("Loading image " + image.name); selected->selectImage(image, i); - bool isInView = isCoordinateInView(image.equatorialCartesian); + bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); // If the coordinate is not in view, rotate camera if (image.hasCelestialCoords && !isInView) { module->startRotatingCamera( - equatorialToGalactic( + skybrowser::equatorialToGalactic( image.equatorialCartesian * skybrowser::CelestialSphereRadius ) ); } } } - - return 0; } - -int setHoverCircle(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setHoverCircle"); +/** +* Takes an identifier to a screen space renderable and adds it to the module. +* \param id Identifier +*/ +[[codegen::luawrap]] void setHoverCircle(std::string id) { SkyBrowserModule* module = global::moduleEngine->module(); - std::string id = ghoul::lua::value(L, 1); SceneGraphNode* circle = global::renderEngine->scene()->sceneGraphNode(id); module->setHoverCircle(circle); - - return 0; } - -int moveCircleToHoverImage(lua_State* L) { +/** +* Moves the hover circle to the coordinate specified by the image index. +* \param i Index of image +*/ +[[codegen::luawrap]] void moveCircleToHoverImage(int i) { // Load image - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); - const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); module->moveHoverCircle(i); - - return 0; } - -int disableHoverCircle(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); +/** +* Disables the hover circle, if there is one added to the sky browser +* module. +*/ +[[codegen::luawrap]] void disableHoverCircle() { SkyBrowserModule* module = global::moduleEngine->module(); module->disableHoverCircle(); - - return 0; } - -int setImageLayerOrder(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder"); - auto [id, i, order] = ghoul::lua::values(L); +/** +* Takes an identifier to a sky browser or a sky target, an image index +* and the order which it should have in the selected image list. The +* image is then changed to have this order. +* \param id Identifier +* \param i Image index +* \param order Order of image +*/ +[[codegen::luawrap]] void setImageLayerOrder(std::string id, int i, int order) { SkyBrowserModule* module = global::moduleEngine->module(); if (module->getPair(id)) { module->getPair(id)->setImageOrder(i, order); } - return 0; } - -int loadImagesToWWT(lua_State* L) { +/** +* Takes an identifier to a sky browser or target and loads the WWT image +* collection to that browser. +* \param id Identifier +*/ +[[codegen::luawrap]] void loadImagesToWWT(std::string id) { // Load images from url - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT"); - const std::string id = ghoul::lua::value(L, 1); LINFO("Connection established to WorldWide Telescope application in " + id); LINFO("Loading image collections to " + id); @@ -127,14 +131,13 @@ int loadImagesToWWT(lua_State* L) { module->getPair(id)->hideChromeInterface(true); module->getPair(id)->loadImageCollection(root); } - - return 0; } - -int startSetup(lua_State* L) { +/** +* Starts the setup process of the sky browers. This function calls +* the lua function 'sendOutIdsToBrowsers' in all nodes in the cluster. +*/ +[[codegen::luawrap]] void startSetup() { // This is called when the sky_browser website is connected to OpenSpace - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::startSetup"); - // Set all border colors to the border color in the master node if (global::windowDelegate->isMaster()) { SkyBrowserModule* module = global::moduleEngine->module(); @@ -162,29 +165,28 @@ int startSetup(lua_State* L) { "openspace.skybrowser.sendOutIdsToBrowsers();", scripting::ScriptEngine::RemoteScripting::No ); - - return 0; } - -int sendOutIdsToBrowsers(lua_State* L) { +/** +* Sends all sky browsers' identifiers to their respective CEF browser. +*/ +[[codegen::luawrap]] void sendOutIdsToBrowsers() { // This is called when the sky_browser website is connected to OpenSpace - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers"); - // Send out identifiers to the browsers SkyBrowserModule* module = global::moduleEngine->module(); std::vector>& pairs = module->getPairs(); for (std::unique_ptr& pair : pairs) { pair->sendIdToBrowser(); } - - return 0; } - -int initializeBrowser(lua_State* L) { +/** +* Takes an identifier to a sky browser and starts the initialization +* for that browser. That means that the browser starts to try to connect +* to the AAS WorldWide Telescope application by sending it messages. And +* that the target matches its appearance to its corresponding browser. +* \param id Identifier +*/ +[[codegen::luawrap]] void initializeBrowser(std::string id) { // Initialize browser with ID and its corresponding target - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::initializeBrowser"); - const std::string id = ghoul::lua::value(L, 1); - LINFO("Initializing sky browser " + id); SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* found = module->getPair(id); @@ -192,30 +194,34 @@ int initializeBrowser(lua_State* L) { found->setIsSyncedWithWwt(true); found->initialize(); } - - return 0; } - -int addPairToSkyBrowserModule(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule"); - auto [targetId, browserId] = ghoul::lua::values(L); +/** +* Takes the identifier of the sky target and a sky browser and adds them +* to the sky browser module. +* \param targetId Identifier of target (either SceneGraphNode or Renderable) +* \param browserId Identifier of browser +*/ +[[codegen::luawrap]] void addPairToSkyBrowserModule(std::string targetId, std::string browserId) { SkyBrowserModule* module = global::moduleEngine->module(); LINFO("Add browser " + browserId + " to sky browser module"); LINFO("Add target " + targetId + " to sky browser module"); module->addTargetBrowserPair(targetId, browserId); - - return 0; } +/** +* Returns a list of all the loaded AAS WorldWide Telescope images that +* have been loaded. Each image has a name, thumbnail url, equatorial +* spherical coordinates RA and Dec, equatorial Cartesian coordinates, +* if the image has celestial coordinates, credits text, credits url +* and the identifier of the image which is a unique number. +*/ -int getListOfImages(lua_State* L) { +[[codegen::luawrap]] ghoul::Dictionary getListOfImages() { // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); SkyBrowserModule* module = global::moduleEngine->module(); // If no data has been loaded yet, download the data from the web! - if (module->nLoadedImages() == 0) { std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/" "wwt-web-client/master/assets/webclient-explore-root.wtml"; @@ -226,79 +232,64 @@ int getListOfImages(lua_State* L) { } // Create Lua table to send to the GUI - lua_newtable(L); + ghoul::Dictionary list; for (int i = 0; i < module->nLoadedImages(); i++) { const ImageData& img = module->getWwtDataHandler()->getImage(i); + using namespace std::string_literals; - // Index for current ImageData - ghoul::lua::push(L, i + 1); - lua_newtable(L); // Push ("Key", value) - ghoul::lua::push(L, "name", img.name); - lua_settable(L, -3); - ghoul::lua::push(L, "thumbnail", img.thumbnailUrl); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", img.equatorialSpherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", img.equatorialSpherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", img.equatorialCartesian); - lua_settable(L, -3); - ghoul::lua::push(L, "hasCelestialCoords", img.hasCelestialCoords); - lua_settable(L, -3); - ghoul::lua::push(L, "credits", img.credits); - lua_settable(L, -3); - ghoul::lua::push(L, "creditsUrl", img.creditsUrl); - lua_settable(L, -3); - ghoul::lua::push(L, "identifier", std::to_string(i)); - lua_settable(L, -3); + ghoul::Dictionary image; + image.setValue("name", img.name); + image.setValue("thumbnail", img.thumbnailUrl); + image.setValue("ra", img.equatorialSpherical.x); + image.setValue("dec", img.equatorialSpherical.y); + image.setValue("cartesianDirection", img.equatorialCartesian); + image.setValue("hasCelestialCoords", img.hasCelestialCoords); + image.setValue("credits", img.credits); + image.setValue("creditsUrl", img.creditsUrl); + image.setValue("identifier", std::to_string(i)); + // Index for current ImageData // Set table for the current ImageData - lua_settable(L, -3); + list.setValue(std::to_string(i + 1), image); } - return 1; + return list; } - -int getTargetData(lua_State* L) { - // Send image list to GUI - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getTargetData"); - +/** +* Returns a table of data regarding the current view and the sky browsers +* and targets. +* \return Dictionary of data regarding the current targets +*/ +[[codegen::luawrap]] ghoul::Dictionary getTargetData() { + using namespace std::string_literals; SkyBrowserModule* module = global::moduleEngine->module(); - - lua_newtable(L); + ghoul::Dictionary data; - // Add the window data for OpenSpace - ghoul::lua::push(L, "OpenSpace"); - lua_newtable(L); + // The current viewport data for OpenSpace + ghoul::Dictionary openSpace; + + // Camera directions glm::dvec3 cartesianCam = skybrowser::cameraDirectionEquatorial(); glm::dvec2 sphericalCam = skybrowser::cartesianToSpherical(cartesianCam); // Calculate the smallest FOV of vertical and horizontal glm::dvec2 fovs = skybrowser::fovWindow(); double FOV = std::min(fovs.x, fovs.y); - // Push window data - ghoul::lua::push(L, "windowHFOV", FOV); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", cartesianCam); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", sphericalCam.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", sphericalCam.y); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedBrowserId", module->selectedBrowserId()); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedTargetId", module->selectedTargetId()); - lua_settable(L, -3); - ghoul::lua::push(L, "isFacingCamera", module->isSelectedPairFacingCamera()); - lua_settable(L, -3); - ghoul::lua::push(L, "isUsingRadiusAzimuthElevation", module->isSelectedPairUsingRae()); - lua_settable(L, -3); - ghoul::lua::push(L, "cameraInSolarSystem", module->isCameraInSolarSystem()); - lua_settable(L, -3); + + // Set window data + openSpace.setValue("windowHFOV", FOV); + openSpace.setValue("cartesianDirection", cartesianCam); + openSpace.setValue("ra", sphericalCam.x); + openSpace.setValue("dec", sphericalCam.y); + openSpace.setValue("selectedBrowserId", module->selectedBrowserId()); + openSpace.setValue("selectedTargetId", module->selectedTargetId()); + openSpace.setValue("isFacingCamera", module->isSelectedPairFacingCamera()); + openSpace.setValue("isUsingRadiusAzimuthElevation", module->isSelectedPairUsingRae()); + openSpace.setValue("cameraInSolarSystem", module->isCameraInSolarSystem()); // Set table for the current ImageData - lua_settable(L, -3); + data.setValue("OpenSpace", openSpace); // Pass data for all the browsers and the corresponding targets if (module->isCameraInSolarSystem()) { @@ -320,85 +311,76 @@ int getTargetData(lua_State* L) { glm::dvec2 spherical = pair->targetDirectionEquatorial(); glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical); - ghoul::lua::push(L, id); - lua_newtable(L); - // Push ("Key", value) - ghoul::lua::push(L, "id", id); - lua_settable(L, -3); - ghoul::lua::push(L, "name", pair->browserGuiName()); - lua_settable(L, -3); - ghoul::lua::push(L, "FOV", pair->verticalFov()); - lua_settable(L, -3); - ghoul::lua::push(L, "selectedImages", selectedImagesVector); - lua_settable(L, -3); - ghoul::lua::push(L, "cartesianDirection", cartesian); - lua_settable(L, -3); - ghoul::lua::push(L, "ra", spherical.x); - lua_settable(L, -3); - ghoul::lua::push(L, "dec", spherical.y); - lua_settable(L, -3); - ghoul::lua::push(L, "color", pair->borderColor()); - lua_settable(L, -3); - ghoul::lua::push(L, "size", pair->size()); - lua_settable(L, -3); + ghoul::Dictionary target; + // Set ("Key", value) + target.setValue("id", id); + target.setValue("name", pair->browserGuiName()); + target.setValue("FOV", static_cast(pair->verticalFov())); + target.setValue("selectedImages", selectedImagesVector); + target.setValue("cartesianDirection", cartesian); + target.setValue("ra", spherical.x); + target.setValue("dec", spherical.y); + target.setValue("color", pair->borderColor()); + target.setValue("size", glm::dvec2(pair->size())); // Set table for the current target - lua_settable(L, -3); + data.setValue(id, target); } } - return 1; + return data; } - -int adjustCamera(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); - const std::string id = ghoul::lua::value(L, 1); +/** +* Takes an identifier to a sky browser or sky target. Rotates the camera +* so that the target is placed in the center of the view. +* \param id +*/ +[[codegen::luawrap]] void adjustCamera(std::string id) { SkyBrowserModule* module = global::moduleEngine->module(); if (module->isCameraInSolarSystem()) { module->lookAtTarget(id); } - - return 0; } - -int setOpacityOfImageLayer(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer"); - auto [id, i, opacity] = ghoul::lua::values(L); +/** +* Takes an identifier to a sky browser or sky target, an index to an image +* and a value for the opacity. +* \param id Identifier +* \param i Image index +* \param opacity +*/ +[[codegen::luawrap]] void setOpacityOfImageLayer(std::string id, int i, double opacity) { SkyBrowserModule* module = global::moduleEngine->module(); - TargetBrowserPair* found = module->getPair(id); if (found) { found->setImageOpacity(i, opacity); } - - return 0; } - -int centerTargetOnScreen(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::centerTargetOnScreen"); - const std::string id = ghoul::lua::value(L, 1); +/** +* Takes an identifier to a sky browser and animates its corresponding +* target to the center of the current view. +* \param id Identifier +*/ +[[codegen::luawrap]] void centerTargetOnScreen(std::string id) { SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* pair = module->getPair(id); if (pair) { pair->centerTargetOnScreen(); } - - return 0; } - -int setSelectedBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); - const std::string id = ghoul::lua::value(L, 1); +/** +* Takes an identifier to a sky browser or target. Sets that sky browser +* currently selected. +* \param id +*/ +[[codegen::luawrap]] void setSelectedBrowser(std::string id) { SkyBrowserModule* module = global::moduleEngine->module(); - module->setSelectedBrowser(id); - - return 0; } - -int createTargetBrowserPair(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::createTargetBrowserPair"); +/** +* Creates a sky browser and a target. +*/ +[[codegen::luawrap]] void createTargetBrowserPair() { SkyBrowserModule* module = global::moduleEngine->module(); int noOfPairs = module->nPairs(); @@ -477,13 +459,12 @@ int createTargetBrowserPair(lua_State* L) { "openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');", scripting::ScriptEngine::RemoteScripting::No ); - - return 0; } - -int removeTargetBrowserPair(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeTargetBrowserPair"); - std::string id = ghoul::lua::value(L, 1); +/** +* Takes in identifier to a sky browser or target and removes them. +* \param id Identifier +*/ +[[codegen::luawrap]] void removeTargetBrowserPair(std::string id) { SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* found = module->getPair(id); if (found) { @@ -503,28 +484,32 @@ int removeTargetBrowserPair(lua_State* L) { scripting::ScriptEngine::RemoteScripting::Yes ); } - - return 0; } - -int translateScreenSpaceRenderable(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 5, "lua::translateScreenSpaceRenderable"); - auto [id, startX, startY, transX, transY] = - ghoul::lua::values(L); - +/** +* Takes an identifier to a sky browser or sky target and the [x, y] +* starting position and the [x, y] translation vector. +* \param id Identifier +* \param startX Starting x-position +* \param startY Starting y-position +* \param transX Translation x-value +* \param transY Translation y-value +*/ +[[codegen::luawrap]] void translateScreenSpaceRenderable(std::string id, float startX, + float startY, float transX, + float transY) { ScreenSpaceRenderable* renderable = global::renderEngine->screenSpaceRenderable(id); if (renderable) { renderable->translate(glm::vec2(transX, transY), glm::vec2(startX, startY)); } - - return 0; } - -int removeSelectedImageInBrowser(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser"); - auto [id, i] = ghoul::lua::values(L); - +/** +* Takes an identifier to a sky browser or target and an index to an +* image. Removes that image from that sky browser. +* \param id Identifier +* \i Index of image +*/ +[[codegen::luawrap]] void removeSelectedImageInBrowser(std::string id, int i) { // Get browser SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& image = module->getWwtDataHandler()->getImage(i); @@ -533,14 +518,16 @@ int removeSelectedImageInBrowser(lua_State* L) { if (pair) { pair->removeSelectedImage(i); } - - return 0; } - -int setEquatorialAim(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setEquatorialAim"); - auto [id, ra, dec] = ghoul::lua::values(L); - +/** +* Takes the identifier of a sky browser or a sky target and equatorial +* coordinates Right Ascension and Declination. The target will animate to +* this coordinate and the browser will display the coordinate. +* \param id Identifier +* \param ra Right Ascension +* \param dec Declination +*/ +[[codegen::luawrap]] void setEquatorialAim(std::string id, double ra, double dec) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -548,14 +535,14 @@ int setEquatorialAim(lua_State* L) { if (pair) { pair->setEquatorialAim(glm::dvec2(ra, dec)); } - - return 0; } - -int setVerticalFov(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setVerticalFov"); - auto [id, vfov] = ghoul::lua::values(L); - +/** +* Takes an identifier to a sky browser or a sky target and a vertical +* field of view. Changes the field of view as specified by the input. +* \param id Identifier +* \param vfov Vertical Field of View +*/ +[[codegen::luawrap]] void setVerticalFov(std::string id, float vfov) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -563,14 +550,16 @@ int setVerticalFov(lua_State* L) { if (pair) { pair->setVerticalFov(vfov); } - - return 0; } - -int setBorderColor(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::setBorderColor"); - auto [id, r, g, b] = ghoul::lua::values(L); - +/** +* Takes an identifier to a sky browser or a sky target and a rgb color +* in the ranges [0, 255]. +* \param id Identifier +* \param r Red +* \param g Green +* \param b Blue +*/ +[[codegen::luawrap]] void setBorderColor(std::string id, int r, int g, int b) { glm::ivec3 color{ r, g, b }; // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -579,14 +568,15 @@ int setBorderColor(lua_State* L) { if (pair) { pair->setBorderColor(color); } - - return 0; } - -int setScreenSpaceSize(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setScreenSpaceSize"); - auto [id, sizeX, sizeY] = ghoul::lua::values(L); - +/** +* Sets the screen space size of the sky browser to the numbers specified +* by the input [x, y]. +* \param id +* \param sizeX Size on the x-axis +* \param sizeY Size on the y-axis +*/ +[[codegen::luawrap]] void setScreenSpaceSize(std::string id, float sizeX, float sizeY) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -594,13 +584,12 @@ int setScreenSpaceSize(lua_State* L) { if (pair) { pair->setScreenSpaceSize(glm::vec2(sizeX, sizeY)); } - return 0; } - -int addRenderCopy(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addRenderCopy"); - auto [id] = ghoul::lua::values(L); - +/** +* Takes an identifier to a sky browser and adds a rendered copy to it. +* \param id Identifier +*/ +[[codegen::luawrap]] void addRenderCopy(std::string id) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -608,14 +597,13 @@ int addRenderCopy(lua_State* L) { if (pair) { pair->browser()->addRenderCopy(); } - return 0; } - - -int removeRenderCopy(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeRenderCopy"); - auto [id] = ghoul::lua::values(L); - +/** +* Takes an identifier to a sky browser and removes the latest added +* rendered copy to it. +* \param id Identifier +*/ +[[codegen::luawrap]] void removeRenderCopy(std::string id) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); @@ -623,7 +611,8 @@ int removeRenderCopy(lua_State* L) { if (pair) { pair->browser()->removeRenderCopy(); } - return 0; } -} // namespace openspace::skybrowser::luafunctions +#include "skybrowsermodule_lua_codegen.cpp" + +} // namespace diff --git a/modules/skybrowser/src/browser.cpp b/modules/skybrowser/src/browser.cpp index e35c31ab0d..615f558ff4 100644 --- a/modules/skybrowser/src/browser.cpp +++ b/modules/skybrowser/src/browser.cpp @@ -103,8 +103,8 @@ Browser::Browser(const ghoul::Dictionary& dictionary) _renderHandler = new RenderHandler(); _keyboardHandler = new WebKeyboardHandler(); _browserInstance = std::make_unique( - _renderHandler, - _keyboardHandler + _renderHandler.get(), + _keyboardHandler.get() ); WebBrowserModule* webBrowser = global::moduleEngine->module(); From c3c453b45cf5c204ede8d9eb5ed8d0dd25e45bc8 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 09:21:18 -0400 Subject: [PATCH 226/251] Fix search of pairs to include scene graph node identifier as well --- modules/skybrowser/skybrowsermodule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 7983c9179f..dc5e1dd04b 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -376,7 +376,7 @@ TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) { bool foundBrowser = pair->browserId() == id; bool foundTarget = pair->targetRenderableId() == id; bool foundTargetNode = pair->targetNodeId() == id; - return foundBrowser || foundTarget; + return foundBrowser || foundTarget || foundTargetNode; } ); if (it == std::end(_targetsBrowsers)) { From ba0ce07181a2f48ab590061127bd50fbe5273194 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 09:21:56 -0400 Subject: [PATCH 227/251] Create setting to render the interactive sky browser only on master. This could be useful in a dome setting --- .../include/screenspaceskybrowser.h | 1 + .../skybrowser/src/screenspaceskybrowser.cpp | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 1d796326b2..21a30fad9a 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -74,6 +74,7 @@ public: private: properties::DoubleProperty _animationSpeed; properties::FloatProperty _textureQuality; + properties::BoolProperty _renderOnlyOnMaster; std::vector> _renderCopies; void bindTexture() override; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index bc7f185ee6..12f1092b7c 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -61,12 +61,22 @@ namespace { "be interactive. The position is in RAE (Radius, Azimuth, Elevation) coordinates." }; + constexpr const openspace::properties::Property::PropertyInfo RenderOnMasterInfo = { + "RenderOnlyOnMaster", + "Render Only On Master", + "Render the interactive sky browser only on the master node (this setting won't " + "affect the copies). This setting allows mouse interactions in a dome environment." + }; + struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { // [[codegen::verbatim(AnimationSpeedInfo.description)]] std::optional animationSpeed; // [[codegen::verbatim(TextureQualityInfo.description)]] std::optional textureQuality; + + // [[codegen::verbatim(RenderOnMasterInfo.description)]] + std::optional renderOnlyOnMaster; }; #include "screenspaceskybrowser_codegen.cpp" @@ -99,6 +109,7 @@ namespace openspace { , WwtCommunicator(dictionary) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) + , _renderOnlyOnMaster(RenderOnMasterInfo, false) { _identifier = makeUniqueIdentifier(_identifier); @@ -106,11 +117,13 @@ namespace openspace { const Parameters p = codegen::bake(dictionary); _textureQuality = p.textureQuality.value_or(_textureQuality); _animationSpeed = p.animationSpeed.value_or(_animationSpeed); + _renderOnlyOnMaster = p.renderOnlyOnMaster.value_or(_renderOnlyOnMaster); addProperty(_url); addProperty(_browserPixeldimensions); addProperty(_reload); addProperty(_textureQuality); + addProperty(_renderOnlyOnMaster); _textureQuality.onChange([this]() { _textureDimensionsIsDirty = true; @@ -228,12 +241,23 @@ void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { void ScreenSpaceSkyBrowser::render() { WwtCommunicator::render(); - draw( - globalRotationMatrix() * - translationMatrix() * - localRotationMatrix() * - scaleMatrix() - ); + // If the sky browser only should be rendered on master, don't use the + // global rotation + if (_renderOnlyOnMaster && global::windowDelegate->isMaster()) { + draw( + translationMatrix() * + localRotationMatrix() * + scaleMatrix() + ); + } + else if(!_renderOnlyOnMaster) { + draw( + globalRotationMatrix() * + translationMatrix() * + localRotationMatrix() * + scaleMatrix() + ); + } // Render a copy that is not interactive for (const std::unique_ptr& copy : _renderCopies) { From 3d117652c082890f9ee8fb6c0bad972d8581b96c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 09:30:10 -0400 Subject: [PATCH 228/251] Update hash to new version of gui --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 2624f02aee..a35ba7081c 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require("./static_server") local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "234ddc8975ff03fd45708f9668c92bd31f7e79e8" +local frontendHash = "1823d1b030e3e8ecc768f936e78496ad43adcf62" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From f34884e86b4d3fbc4d3e8e2823741c5e784e4ba4 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 13:27:01 -0400 Subject: [PATCH 229/251] Make apperance of target match the dimensions of the sky browser. Fixes issue #1926 --- .../skybrowser/include/renderableskytarget.h | 2 - .../skybrowser/include/targetbrowserpair.h | 6 +-- modules/skybrowser/shaders/target_fs.glsl | 39 ++++++++----------- modules/skybrowser/skybrowsermodule_lua.inl | 4 +- .../skybrowser/src/renderableskytarget.cpp | 20 +--------- .../skybrowser/src/screenspaceskybrowser.cpp | 2 +- modules/skybrowser/src/targetbrowserpair.cpp | 27 +++---------- 7 files changed, 28 insertions(+), 72 deletions(-) diff --git a/modules/skybrowser/include/renderableskytarget.h b/modules/skybrowser/include/renderableskytarget.h index 85859b8a86..0fa130ae27 100644 --- a/modules/skybrowser/include/renderableskytarget.h +++ b/modules/skybrowser/include/renderableskytarget.h @@ -53,7 +53,6 @@ public: float opacity() const; double animationSpeed() const; double stopAnimationThreshold() const; - double smallestFov() const; void setDimensions(glm::vec2 dimensions); void setColor(glm::ivec3 color); @@ -69,7 +68,6 @@ private: properties::FloatProperty _crossHairSize; properties::FloatProperty _showRectangleThreshold; properties::FloatProperty _lineWidth; - properties::DoubleProperty _smallestFov; properties::DoubleProperty _stopAnimationThreshold; properties::DoubleProperty _animationSpeed; diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 43106960ce..b70d2d104d 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -67,8 +67,6 @@ public: // Target void centerTargetOnScreen(); - void lock(); - void unlock(); void incrementallyAnimateTarget(float deltaTime); bool hasFinishedFading(float goalState) const; @@ -116,9 +114,7 @@ private: bool isTargetFadeFinished(float goalState) const; bool isBrowserFadeFinished(float goalState) const; - void aimTargetGalactic(glm::dvec3 position); - - void setFovTarget(double fov); + void aimTargetGalactic(glm::dvec3 direction); // Selection ScreenSpaceSkyBrowser* _selected = nullptr; diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 21784e923a..42143ed89c 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -42,7 +42,7 @@ uniform vec3 multiplyColor; // A factor which states how much thicker vertical lines are rendered than horizontal // This compensates for the optical illusion that vertical lines appear thinner -const float VerticalThickness = 1.15; +const float VerticalThickness = 1.1; float createLine(float lineCenter, float lineWidth, float coord) { // Calculate edges of line @@ -52,28 +52,13 @@ float createLine(float lineCenter, float lineWidth, float coord) { return step(startEdge, coord) - step(endEdge, coord); } -float createFilledRectangle(float width, vec2 coord) { - return createLine(0.5, width, coord.x) * createLine(0.5, width, coord.y); -} - -float createRectangle(float linewidthY, float ratio, vec2 coord) { - // Calculate the widths and centers for the lines - float linewidthX = linewidthY * ratio * VerticalThickness; - float linecenterX = linewidthX * 0.5; - float linecenterY = linewidthY * 0.5; - - // Create the four lines for the rectangle - float l = createLine(linecenterX, linewidthX, coord.x); - float r = createLine(1.0 - linecenterX, linewidthX, coord.x); - float b = createLine(linecenterY, linewidthY, coord.y); - float t = createLine(1.0 - linecenterY, linewidthY, coord.y); - - return l + r + b + t; +float createFilledRectangle(float width, float height, vec2 coord) { + return createLine(0.5, width, coord.x) * createLine(0.5, height, coord.y); } float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { const float Center = 0.5; - float crosshairVertical = createLine(Center, linewidth * ratio * VerticalThickness, coord.x); + float crosshairVertical = createLine(Center, linewidth * VerticalThickness, coord.x); float crosshairHorizontal = createLine(Center, linewidth, coord.y); return crosshairHorizontal + crosshairVertical; @@ -84,14 +69,22 @@ float createCrosshair(in float linewidth, in float ratio, in vec2 coord) { Fragment getFragment() { float ratio = dimensions.y / dimensions.x; float rectangle = 0.0; - float lineWidthUsed = (lineWidth * 0.01)/max(fov,2); + float maxWwtFov = 70; - float crosshair = createCrosshair(lineWidthUsed, ratio, vs_st); - float crossHairBox = createFilledRectangle(crossHairSize/max(fov,2), vs_st); + float crosshair = createCrosshair(lineWidth, ratio, vs_st); + float crossHairHeight = crossHairSize/maxWwtFov; + float crossHairWidth = crossHairHeight * ratio; + float crossHairBox = createFilledRectangle(crossHairHeight, crossHairWidth, vs_st); crosshair *= crossHairBox; if (showRectangle) { - rectangle = createRectangle(lineWidthUsed, ratio, vs_st); + float height = fov/maxWwtFov; + float width = height * ratio; + float outerEdge = createFilledRectangle(height, width, vs_st); + float lineWidthX = lineWidth * 2 * VerticalThickness; + float lineWidthY = lineWidth * 2; + float innerEdge = createFilledRectangle(height-lineWidthX, width-lineWidthY, vs_st); + rectangle = outerEdge - innerEdge; } float result = clamp(crosshair + rectangle, 0.0, 1.0); diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 5fc2d35bfb..223ee3f740 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -394,7 +396,7 @@ namespace { glm::dvec3 galacticTarget = skybrowser::localCameraToGalactic(positionTarget); std::string guiPath = "/SkyBrowser"; std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; - double fov = 5.0; + double fov = 70.0; double size = skybrowser::sizeFromFov(fov, galacticTarget); const std::string browser = "{" diff --git a/modules/skybrowser/src/renderableskytarget.cpp b/modules/skybrowser/src/renderableskytarget.cpp index 4f5a513057..86570065c4 100644 --- a/modules/skybrowser/src/renderableskytarget.cpp +++ b/modules/skybrowser/src/renderableskytarget.cpp @@ -53,7 +53,7 @@ namespace { { "CrosshairSize", "Crosshair Size", - "Determines the size of the crosshair." + "Determines the size of the crosshair. The size is determined in fov (degrees). " }; constexpr const openspace::properties::Property::PropertyInfo RectangleThresholdInfo = @@ -85,12 +85,6 @@ namespace { "The thickness of the line of the target. The larger number, the thicker line." }; - constexpr const openspace::properties::Property::PropertyInfo SmallestFovInfo = { - "SmallestFov", - "Smallest Vertical Field Of View", - "The smallest field of view that the target will display on screen." - }; - struct [[codegen::Dictionary(RenderableSkyTarget)]] Parameters { // [[codegen::verbatim(crossHairSizeInfo.description)]] std::optional crossHairSize; @@ -106,9 +100,6 @@ namespace { // [[codegen::verbatim(LineWidthInfo.description)]] std::optional lineWidth; - - // [[codegen::verbatim(SmallestFovInfo.description)]] - std::optional smallestFov; }; #include "renderableskytarget_codegen.cpp" @@ -122,7 +113,6 @@ namespace openspace { , _stopAnimationThreshold(AnimationThresholdInfo, 5.0f, 1.f, 10.f) , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _lineWidth(LineWidthInfo, 13.f, 1.f, 100.f) - , _smallestFov(SmallestFovInfo, 3.0, 0.5, 20.0) , _borderColor(220, 220, 220) { // Handle target dimension property @@ -131,14 +121,12 @@ namespace openspace { _showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold); _stopAnimationThreshold = p.crossHairSize.value_or(_stopAnimationThreshold); _animationSpeed = p.animationSpeed.value_or(_animationSpeed); - _smallestFov = p.smallestFov.value_or(_smallestFov); addProperty(_crossHairSize); addProperty(_showRectangleThreshold); addProperty(_stopAnimationThreshold); addProperty(_animationSpeed); addProperty(_lineWidth); - addProperty(_smallestFov); } void RenderableSkyTarget::bindTexture() {} @@ -186,7 +174,7 @@ void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) { _shader->setUniform("crossHairSize", _crossHairSize); _shader->setUniform("showRectangle", showRectangle); - _shader->setUniform("lineWidth", _lineWidth); + _shader->setUniform("lineWidth", _lineWidth * 0.0001f); _shader->setUniform("dimensions", _dimensions); _shader->setUniform("lineColor", color); _shader->setUniform("fov", static_cast(_verticalFov)); @@ -279,10 +267,6 @@ double RenderableSkyTarget::stopAnimationThreshold() const { return _stopAnimationThreshold * 0.0001; } -double RenderableSkyTarget::smallestFov() const { - return _smallestFov; -} - void RenderableSkyTarget::setOpacity(float opacity) { _opacity = opacity; } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 12f1092b7c..ce7d740dc0 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -164,7 +164,7 @@ glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) { glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV; // Convert to screen space coordinate system - glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f }; + glm::dvec2 convertToScreenSpace{ (2.f * skybrowser::windowRatio()), 2.f }; glm::dvec2 result = - convertToScreenSpace * resultRelativeOs; return result; } diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index fdefb3c683..c401e90f4d 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -92,24 +92,6 @@ void TargetBrowserPair::aimTargetGalactic(glm::dvec3 direction) { ); } -void TargetBrowserPair::setFovTarget(double fov) { - std::string id = _targetNode->identifier(); - std::string renderableId = _targetRenderable->identifier(); - // Uris for properties - std::string sizeUri = "Scene." + id + "." + renderableId + ".Size"; - - double renderedFov = std::max(fov, _targetRenderable->smallestFov()); - double size = skybrowser::sizeFromFov(renderedFov, _targetNode->worldPosition()); - - std::string setValue = "openspace.setPropertyValueSingle('"; - - openspace::global::scriptEngine->queueScript( - setValue + sizeUri + "', " + std::to_string(size) + ");", - scripting::ScriptEngine::RemoteScripting::Yes - ); - _targetRenderable->setVerticalFov(renderedFov); -} - bool TargetBrowserPair::checkMouseIntersection(const glm::vec2& mousePosition) { _selected = _browser->isIntersecting(mousePosition) ? _browser : nullptr; @@ -162,7 +144,7 @@ void TargetBrowserPair::synchronizeAim() { // target, send the locked coordinates to wwt glm::dvec2 aim = targetDirectionEquatorial(); _browser->setEquatorialAim(aim); - setFovTarget(_browser->verticalFov()); + _targetRenderable->setVerticalFov(_browser->verticalFov()); } } @@ -176,7 +158,7 @@ bool TargetBrowserPair::isEnabled() const { void TargetBrowserPair::initialize() { _targetRenderable->setColor(_browser->borderColor()); - _targetRenderable->setDimensions(_browser->browserPixelDimensions()); + _targetRenderable->setDimensions(_browser->screenSpaceDimensions()); _browser->updateBorderColor(); } @@ -271,7 +253,7 @@ void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { void TargetBrowserPair::setVerticalFov(float vfov) { _browser->setVerticalFov(vfov); - setFovTarget(vfov); + _targetRenderable->setVerticalFov(vfov); } void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) { @@ -290,6 +272,7 @@ void TargetBrowserPair::setBorderColor(const glm::ivec3& color) { void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) { _browser->setScreenSpaceSize(dimensions); + _targetRenderable->setDimensions(dimensions); } void TargetBrowserPair::setVerticalFovWithScroll(float scroll) { @@ -303,7 +286,7 @@ void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { } else if (_browser->isAnimated()) { _browser->incrementallyAnimateToFov(static_cast(deltaTime)); - setFovTarget(_browser->verticalFov()); + _targetRenderable->setVerticalFov(_browser->verticalFov()); } } From 5b4c3da91ee1184b64ccb9c3aa27f180153fbc31 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 14:06:40 -0400 Subject: [PATCH 230/251] Make the smallest fov possible a lot smaller --- modules/skybrowser/src/screenspaceskybrowser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index ce7d740dc0..99ffabe324 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -298,7 +298,7 @@ void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { float x = _verticalFov; float zoomFactor = atan(x / 50.f) + exp(x / 40.f) - 0.999999f; float zoom = scroll > 0.f ? -zoomFactor : zoomFactor; - _verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f); + _verticalFov = std::clamp(_verticalFov + zoom, 0.000001f, 70.0f); } void ScreenSpaceSkyBrowser::bindTexture() { From aed059a1478032bce6d697213f09f9cc6756b32f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 16:19:10 -0400 Subject: [PATCH 231/251] Fix precision issue that led to nan values. This fixes #1934 --- modules/skybrowser/src/utility.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 69275767f0..adb0290b9e 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -188,8 +188,9 @@ glm::dvec2 fovWindow() { double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { // Find smallest angle between the two vectors - double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end)); - return std::acos(cos); + double cos = glm::dot(glm::normalize(start), glm::normalize(end)); + // Ensure cos is within defined interval [-1,1] + return std::acos(std::clamp(cos, -1.0, 1.0)); } glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, From 33ddd944261d50501daf9bd996cc9550c04646fd Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 18:45:57 -0400 Subject: [PATCH 232/251] Fix issues with fading by using the system time instead of fps --- .../skybrowser/include/targetbrowserpair.h | 21 ++++-- modules/skybrowser/skybrowsermodule.cpp | 49 +++++++------ modules/skybrowser/src/targetbrowserpair.cpp | 73 +++++++++++-------- 3 files changed, 84 insertions(+), 59 deletions(-) diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index b70d2d104d..c159424f0d 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -27,6 +27,7 @@ #include #include +#include namespace openspace { @@ -38,7 +39,6 @@ class SceneGraphNode; class TargetBrowserPair { public: - constexpr static const float FadeThreshold = 0.01f; constexpr static const float DeltaTimeThreshold = 0.03f; TargetBrowserPair(SceneGraphNode* target, ScreenSpaceSkyBrowser* browser); @@ -52,7 +52,8 @@ public: // Animation void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(double deltaTime); - void incrementallyFade(float goalState, float fadeTime, float deltaTime); + void startFading(float goal, float fadeTime); + void incrementallyFade(float deltaTime); // Mouse interaction bool checkMouseIntersection(const glm::vec2& mousePosition); glm::vec2 selectedScreenSpacePosition() const; @@ -69,12 +70,13 @@ public: void centerTargetOnScreen(); void incrementallyAnimateTarget(float deltaTime); - bool hasFinishedFading(float goalState) const; + bool hasFinishedFading() const; bool isFacingCamera() const; bool isUsingRadiusAzimuthElevation() const; bool isEnabled() const; void setEnabled(bool enable); + void setOpacity(float opacity); void setIsSyncedWithWwt(bool isSynced); void setVerticalFov(float vfov); void setEquatorialAim(const glm::dvec2& aim); @@ -111,9 +113,6 @@ public: const TargetBrowserPair& rhs); private: - bool isTargetFadeFinished(float goalState) const; - bool isBrowserFadeFinished(float goalState) const; - void aimTargetGalactic(glm::dvec3 direction); // Selection @@ -123,10 +122,20 @@ private: RenderableSkyTarget* _targetRenderable = nullptr; ScreenSpaceSkyBrowser* _browser = nullptr; SceneGraphNode* _targetNode = nullptr; + + // Animation glm::dvec3 _animationStart = glm::dvec3(0); glm::dvec3 _animationEnd = glm::dvec3(0); bool _shouldLockAfterAnimation = false; bool _targetIsAnimated = false; + + // Fading + float _goal = 1.0f; + float _startTarget = 1.0f; + float _startBrowser = 1.0f; + std::chrono::milliseconds _fadeTime = std::chrono::milliseconds(2000); + std::chrono::system_clock::time_point _fadeStart; + bool _isFading = false; glm::dvec2 _equatorialAim = glm::dvec2(0.0); glm::ivec3 _borderColor = glm::ivec3(255); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index dc5e1dd04b..35af457c5e 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -167,15 +167,28 @@ SkyBrowserModule::SkyBrowserModule() bool vizModeChanged = _isCameraInSolarSystem != camWasInSolarSystem; // Visualization mode changed. Start fading - if (vizModeChanged) { - _isFading = true; + if (vizModeChanged && !_isCameraInSolarSystem) { // Camera moved into the solar system - if (!_isCameraInSolarSystem) { - _goal = Transparency::Transparent; - } - else { - _goal = Transparency::Opaque; - } + _isFading = true; + _goal = Transparency::Transparent; + + float transparency = [](Transparency goal) { + switch (goal) { + case Transparency::Transparent: + return 0.f; + + case Transparency::Opaque: + return 1.f; + } + }(_goal); + + std::for_each( + _targetsBrowsers.begin(), + _targetsBrowsers.end(), + [&](const std::unique_ptr& pair) { + pair->startFading(transparency, 2.f); + } + ); } double deltaTime = global::windowDelegate->deltaTime(); // Fade pairs if the camera moved in or out the solar system @@ -421,26 +434,18 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime, double animat void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float deltaTime) -{ - float transparency = [](Transparency goal) { - switch (goal) { - case Transparency::Transparent: - return 0.f; - - case Transparency::Opaque: - return 1.f; - } - }(goal); - - bool isAllFinished{ false }; +{ + bool isAllFinished = true; for (std::unique_ptr& pair : _targetsBrowsers) { if (pair->isEnabled()) { - bool isPairFinished = pair->hasFinishedFading(transparency); + bool isPairFinished = pair->hasFinishedFading(); if (!isPairFinished) { - pair->incrementallyFade(transparency, FadingTime, deltaTime); + pair->incrementallyFade(deltaTime); } else if (isPairFinished && goal == Transparency::Transparent) { pair->setEnabled(false); + pair->setOpacity(1.0); + } isAllFinished &= isPairFinished; } diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index c401e90f4d..180650f905 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -67,17 +68,6 @@ void TargetBrowserPair::highlight(const glm::ivec3& color) { _targetRenderable->highlight(color); } -bool TargetBrowserPair::isTargetFadeFinished(float goalState) const { - float targetDiff = abs(_targetRenderable->opacity() - goalState); - - return targetDiff < FadeThreshold; -} - -bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const { - float browserDiff = abs(_browser->opacity() - goalState); - return browserDiff < FadeThreshold; -} - void TargetBrowserPair::aimTargetGalactic(glm::dvec3 direction) { std::string id = _targetNode->identifier(); // Uris for properties @@ -150,10 +140,17 @@ void TargetBrowserPair::synchronizeAim() { void TargetBrowserPair::setEnabled(bool enable) { _browser->setEnabled(enable); + _targetRenderable->property("Enabled")->set(false); +} + +void TargetBrowserPair::setOpacity(float opacity) +{ + _browser->property("Opacity")->set(opacity); + _targetRenderable->property("Opacity")->set(opacity); } bool TargetBrowserPair::isEnabled() const { - return _targetRenderable->isEnabled() && _browser->isEnabled(); + return _targetRenderable->isEnabled() || _browser->isEnabled(); } void TargetBrowserPair::initialize() { @@ -290,6 +287,16 @@ void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { } } +void TargetBrowserPair::startFading(float goal, float fadeTime) +{ + _startTarget = _targetRenderable->opacity(); + _startBrowser = _browser->opacity(); + _goal = goal; + _fadeTime = std::chrono::milliseconds(static_cast(fadeTime * 1000)); + _fadeStart = std::chrono::system_clock::now(); + _isFading = true; +} + void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, float fovEnd, bool shouldLockAfter) { @@ -343,8 +350,8 @@ void TargetBrowserPair::centerTargetOnScreen() { startAnimation(viewDirection, currentFov, false); } -bool TargetBrowserPair::hasFinishedFading(float goalState) const { - return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState); +bool TargetBrowserPair::hasFinishedFading() const { + return !_isFading; } bool TargetBrowserPair::isFacingCamera() const { @@ -363,26 +370,30 @@ ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const { return _browser; } -void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, - float deltaTime) +void TargetBrowserPair::incrementallyFade(float deltaTime) { - float opacityDelta = static_cast(deltaTime / fadeTime); - if (_targetRenderable->opacity() > goalState) { - opacityDelta *= -1.f; - } - - if (!isTargetFadeFinished(goalState)) { - _targetRenderable->setOpacity(_targetRenderable->opacity() + opacityDelta); + using namespace std::chrono; + system_clock::time_point now = system_clock::now(); + std::chrono::duration timeSpent = now - _fadeStart; + + if (timeSpent.count() > _fadeTime.count()) { + _isFading = false; + _browser->setOpacity(_goal); + _targetRenderable->setOpacity(_goal); } else { - _targetRenderable->setOpacity(goalState); - } - - if (!isBrowserFadeFinished(goalState)) { - _browser->setOpacity(_browser->opacity() + opacityDelta); - } - else { - _browser->setOpacity(goalState); + float percentage = timeSpent / _fadeTime; + float newOpacityTarget; + float newOpacityBrowser; + if (_goal > _startTarget || _goal > _startBrowser) { + newOpacityTarget, newOpacityBrowser = _goal * percentage; + } + else { + newOpacityTarget = _startTarget * (1.f - percentage); + newOpacityBrowser = _startBrowser * (1.f - percentage); + } + _browser->setOpacity(newOpacityBrowser); + _targetRenderable->setOpacity(newOpacityTarget); } } From 680cdc4b8fbb95ba4a0e9e8c41d875c3dd3e935c Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 23 Mar 2022 18:46:19 -0400 Subject: [PATCH 233/251] Move the hover circle with lua script instead of C++ code to make it work in a dome environment --- modules/skybrowser/skybrowsermodule.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 35af457c5e..d727e433e5 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -330,7 +330,15 @@ void SkyBrowserModule::moveHoverCircle(int i) { // the target glm::dvec3 pos = skybrowser::equatorialToGalactic(image.equatorialCartesian); pos *= skybrowser::CelestialSphereRadius * 1.1; - _hoverCircle->property("Translation.Position")->set(pos); + // Uris for properties + std::string id = _hoverCircle->identifier(); + std::string positionUri = "Scene." + id + ".Translation.Position"; + std::string setValue = "openspace.setPropertyValueSingle('"; + + openspace::global::scriptEngine->queueScript( + setValue + positionUri + "', " + ghoul::to_string(pos) + ");", + scripting::ScriptEngine::RemoteScripting::Yes + ); } } From 3ec6d84b89cfde77415586718eecadf54b3de9c6 Mon Sep 17 00:00:00 2001 From: Micah Acinapura Date: Wed, 23 Mar 2022 22:31:54 -0400 Subject: [PATCH 234/251] fixes for macos cef update; fixes #1114 --- modules/webbrowser/CMakeLists.txt | 49 ++++++++++++------- .../cmake/patch/cmake/cef_variables.cmake | 4 +- .../webbrowser/cmake/webbrowser_helpers.cmake | 8 ++- modules/webbrowser/src/webbrowserapp.cpp | 2 +- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/modules/webbrowser/CMakeLists.txt b/modules/webbrowser/CMakeLists.txt index f311990365..2306cf462e 100644 --- a/modules/webbrowser/CMakeLists.txt +++ b/modules/webbrowser/CMakeLists.txt @@ -129,7 +129,9 @@ set(WEBBROWSER_SOURCES ${WEBBROWSER_SOURCES} ${WEBBROWSER_RESOURCES_SOURCES}) # CEF helper sources set(WEBBROWSER_HELPER_SOURCES src/webbrowserapp.cpp) -set(WEBBROWSER_HELPER_SOURCES_MACOSX src/processhelpermac.cpp) +if (OS_MACOSX) + list(APPEND WEBBROWSER_HELPER_SOURCES src/processhelpermac.cpp) +endif() set(WEBBROWSER_HELPER_SOURCES_WINDOWS src/processhelperwindows.cpp) APPEND_PLATFORM_SOURCES(WEBBROWSER_HELPER_SOURCES) @@ -152,30 +154,43 @@ set(WEBBROWSER_RESOURCES_SRCS # Place Helper in separate executable # The naming style " Helper" is required by Chromium. set(CEF_HELPER_TARGET "OpenSpace Helper" CACHE INTERNAL "CEF_HELPER_TARGET") +set(CEF_HELPER_TARGET_GPU "OpenSpace Helper (GPU)" CACHE INTERNAL "CEF_HELPER_TARGET_GPU") +set(CEF_HELPER_TARGET_RENDERER "OpenSpace Helper (Renderer)" CACHE INTERNAL "CEF_HELPER_TARGET_RENDERER") # # CEF platform-specific config # +list(APPEND Targets ${CEF_HELPER_TARGET} ${CEF_HELPER_TARGET_GPU} ${CEF_HELPER_TARGET_RENDERER}) + + if (OS_MACOSX) - # Helper executable target. - add_executable(${CEF_HELPER_TARGET} MACOSX_BUNDLE ${WEBBROWSER_HELPER_SOURCES}) - SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_HELPER_TARGET}) - # add_cef_logical_target("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}") - add_dependencies(${CEF_HELPER_TARGET} libcef_dll_wrapper) - target_link_libraries(${CEF_HELPER_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS}) - set_target_properties(${CEF_HELPER_TARGET} PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist - ) + ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}") + foreach(target IN LISTS Targets) + # Helper executable target. + message(STATUS "set tar : ${target}") - target_compile_options(${CEF_HELPER_TARGET} PRIVATE -Wno-deprecated-declarations) - target_compile_options(libcef_dll_wrapper PRIVATE -Wno-deprecated-declarations) + add_executable(${target} MACOSX_BUNDLE ${WEBBROWSER_HELPER_SOURCES}) + SET_EXECUTABLE_TARGET_PROPERTIES(${target}) + # add_cef_logical_target("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}") + add_dependencies(${target} libcef_dll_wrapper) + target_link_libraries(${target} libcef_dll_wrapper ${CEF_STANDARD_LIBS}) + set_target_properties(${target} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist + ) + + target_compile_options(${target} PRIVATE -Wno-deprecated-declarations) + target_compile_options(libcef_dll_wrapper PRIVATE -Wno-deprecated-declarations) + + if (USE_SANDBOX) + # Logical target used to link the cef_sandbox library. + target_link_libraries(${target} cef_sandbox_lib) + endif () + endforeach() + +set_property(TARGET ${CEF_HELPER_TARGET_GPU} PROPERTY FOLDER "Helper") +set_property(TARGET ${CEF_HELPER_TARGET_RENDERER} PROPERTY FOLDER "Helper") - if (USE_SANDBOX) - # Logical target used to link the cef_sandbox library. - ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}") - target_link_libraries(${CEF_HELPER_TARGET} cef_sandbox_lib) - endif () endif () if (OS_WINDOWS) diff --git a/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake b/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake index 82de3fb69c..449b226b5c 100644 --- a/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake +++ b/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake @@ -100,7 +100,7 @@ if(OS_LINUX) -fno-rtti # Disable real-time type information -fno-threadsafe-statics # Don't generate thread-safe statics -fvisibility-inlines-hidden # Give hidden visibility to inlined class member functions - -std=gnu++11 # Use the C++11 language standard including GNU extensions + -std=gnu++14 # Use the C++14 language standard including GNU extensions -Wsign-compare # Warn about mixed signed/unsigned type comparisons ) list(APPEND CEF_COMPILER_FLAGS_DEBUG @@ -259,7 +259,7 @@ if(OS_MACOSX) -fno-threadsafe-statics # Don't generate thread-safe statics -fobjc-call-cxx-cdtors # Call the constructor/destructor of C++ instance variables in ObjC objects -fvisibility-inlines-hidden # Give hidden visibility to inlined class member functions - -std=gnu++11 # Use the C++11 language standard including GNU extensions + -std=gnu++14 # Use the C++14 language standard including GNU extensions -Wno-narrowing # Don't warn about type narrowing -Wsign-compare # Warn about mixed signed/unsigned type comparisons ) diff --git a/modules/webbrowser/cmake/webbrowser_helpers.cmake b/modules/webbrowser/cmake/webbrowser_helpers.cmake index 8ae283eca1..e7bdf407ca 100644 --- a/modules/webbrowser/cmake/webbrowser_helpers.cmake +++ b/modules/webbrowser/cmake/webbrowser_helpers.cmake @@ -69,12 +69,16 @@ function(run_cef_macosx_config CEF_ROOT module_path) set(CEF_FINAL_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CEF_OUTPUT_PREFIX}${CEF_TARGET}.app") set(CEF_INTERMEDIATE_HELPER_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CEF_OUTPUT_PREFIX}${CEF_HELPER_TARGET}.app") + set(CEF_INTERMEDIATE_HELPER_APP_GPU "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CEF_OUTPUT_PREFIX}${CEF_HELPER_TARGET_GPU}.app") + set(CEF_INTERMEDIATE_HELPER_APP_RENDERER "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CEF_OUTPUT_PREFIX}${CEF_HELPER_TARGET_RENDERER}.app") set(CEF_FINAL_HELPER_APP "${CEF_FINAL_APP}/Contents/Frameworks/${CEF_HELPER_TARGET}.app") + set(CEF_FINAL_HELPER_APP_GPU "${CEF_FINAL_APP}/Contents/Frameworks/${CEF_HELPER_TARGET_GPU}.app") + set(CEF_FINAL_HELPER_APP_RENDERER "${CEF_FINAL_APP}/Contents/Frameworks/${CEF_HELPER_TARGET_RENDERER}.app") set(CEF_FRAMEWORK_LOCATION "${CEF_BINARY_DIR}/Chromium Embedded Framework.framework") set(CEF_FRAMEWORK_FINAL_LOCATION "${CEF_FINAL_APP}/Contents/Frameworks/Chromium Embedded Framework.framework") - add_dependencies(${CEF_TARGET} libcef_dll_wrapper "${CEF_HELPER_TARGET}") + add_dependencies(${CEF_TARGET} libcef_dll_wrapper "${CEF_HELPER_TARGET}" "${CEF_HELPER_TARGET_GPU}" "${CEF_HELPER_TARGET_RENDERER}") # target_link_libraries(${CEF_TARGET} PUBLIC libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS}) target_link_libraries(${CEF_TARGET} PUBLIC libcef_dll_wrapper ${CEF_STANDARD_LIBS}) @@ -89,6 +93,8 @@ function(run_cef_macosx_config CEF_ROOT module_path) POST_BUILD # Copy the helper app bundle into the Frameworks directory. COMMAND ${CMAKE_COMMAND} -E copy_directory "${CEF_INTERMEDIATE_HELPER_APP}" "${CEF_FINAL_HELPER_APP}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CEF_INTERMEDIATE_HELPER_APP_GPU}" "${CEF_FINAL_HELPER_APP_GPU}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CEF_INTERMEDIATE_HELPER_APP_RENDERER}" "${CEF_FINAL_HELPER_APP_RENDERER}" # Copy the CEF framework into the Frameworks directory. COMMAND ${CMAKE_COMMAND} -E copy_directory "${CEF_FRAMEWORK_LOCATION}" "${CEF_FRAMEWORK_FINAL_LOCATION}" VERBATIM diff --git a/modules/webbrowser/src/webbrowserapp.cpp b/modules/webbrowser/src/webbrowserapp.cpp index d0f7e7d044..af5dec9666 100644 --- a/modules/webbrowser/src/webbrowserapp.cpp +++ b/modules/webbrowser/src/webbrowserapp.cpp @@ -45,7 +45,7 @@ void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&, commandLine->AppendSwitch("use-gl=desktop"); commandLine->AppendSwitch("ignore-gpu-blacklist"); commandLine->AppendSwitch("log-gpu-control-list-decisions"); - + commandLine->AppendSwitch("use-mock-keychain"); commandLine->AppendSwitch("enable-begin-frame-scheduling"); commandLine->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required"); } From ecfc9975eb1f6cffad056a474a0447e379a7d34a Mon Sep 17 00:00:00 2001 From: Micah Date: Thu, 24 Mar 2022 11:00:48 -0400 Subject: [PATCH 235/251] roll back cef version to 91 --- modules/webbrowser/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/webbrowser/CMakeLists.txt b/modules/webbrowser/CMakeLists.txt index 2306cf462e..a7aabfaf0f 100644 --- a/modules/webbrowser/CMakeLists.txt +++ b/modules/webbrowser/CMakeLists.txt @@ -56,7 +56,7 @@ cmake_policy(SET CMP0074 NEW) # Specify the CEF distribution version. # Release from 03/21/2022 verified to work on Windows. -set(CEF_VERSION "99.2.12+g2977b3a+chromium-99.0.4844.74") +set(CEF_VERSION "91.1.23+g04c8d56+chromium-91.0.4472.164") # Removing - micahnyc 03/21/2022 # 73.1.13 has an issue on MacOS: The GUI freezing upon interaction. From 3c8aacaa4f1bef336c8f390480d0fdfad99273c5 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 25 Mar 2022 11:37:47 -0400 Subject: [PATCH 236/251] Update web gui hash to newest version of the gui --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index a35ba7081c..a2835cd596 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require("./static_server") local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "1823d1b030e3e8ecc768f936e78496ad43adcf62" +local frontendHash = "ea33990de2e1477ecafa89861cf6f65e4c2fd46d" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From 50d509b294ba4090a999bb3605e0494b749f5c5a Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 25 Mar 2022 16:52:21 -0400 Subject: [PATCH 237/251] Correct the rendering of the fov (was too large) --- modules/skybrowser/shaders/target_fs.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/shaders/target_fs.glsl b/modules/skybrowser/shaders/target_fs.glsl index 42143ed89c..3cf1d038e6 100644 --- a/modules/skybrowser/shaders/target_fs.glsl +++ b/modules/skybrowser/shaders/target_fs.glsl @@ -78,7 +78,7 @@ Fragment getFragment() { crosshair *= crossHairBox; if (showRectangle) { - float height = fov/maxWwtFov; + float height = (fov * 0.5)/maxWwtFov; float width = height * ratio; float outerEdge = createFilledRectangle(height, width, vs_st); float lineWidthX = lineWidth * 2 * VerticalThickness; From 0df6261fa0bd8f1acea0de00367458d6110f67ec Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 25 Mar 2022 16:54:44 -0400 Subject: [PATCH 238/251] Make fovs doubles instead of floats and use the target as for the roll calculation instead of the camera. This is however still not correct (need the up vector for the target) --- .../skybrowser/include/screenspaceskybrowser.h | 4 ++-- modules/skybrowser/include/targetbrowserpair.h | 6 +++--- modules/skybrowser/include/utility.h | 2 +- modules/skybrowser/include/wwtcommunicator.h | 8 +++++--- modules/skybrowser/src/screenspaceskybrowser.cpp | 16 ++++++++-------- modules/skybrowser/src/targetbrowserpair.cpp | 13 ++++++++++--- modules/skybrowser/src/utility.cpp | 16 ++++++---------- modules/skybrowser/src/wwtcommunicator.cpp | 12 ++++++++---- 8 files changed, 43 insertions(+), 34 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 21a30fad9a..a56bce98db 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -51,7 +51,7 @@ public: // Animation bool isAnimated() const; - void startFovAnimation(float fov); + void startFovAnimation(double fov); void incrementallyAnimateToFov(float deltaTime); float opacity() const; @@ -86,7 +86,7 @@ private: bool _sizeIsDirty = false; // Animation of fieldOfView - float _endVfov = 0.f; + double _endVfov = 0.0; glm::vec2 _size = glm::vec2(0.5f); }; } // namespace openspace diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index b70d2d104d..5a3cf718f4 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -50,7 +50,7 @@ public: void removeHighlight(const glm::ivec3& color); void highlight(const glm::ivec3& color); // Animation - void startAnimation(glm::dvec3 coordsEnd, float fovEnd, bool shouldLockAfter = true); + void startAnimation(glm::dvec3 coordsEnd, double fovEnd, bool shouldLockAfter = true); void incrementallyAnimateToCoordinate(double deltaTime); void incrementallyFade(float goalState, float fadeTime, float deltaTime); // Mouse interaction @@ -76,13 +76,13 @@ public: void setEnabled(bool enable); void setIsSyncedWithWwt(bool isSynced); - void setVerticalFov(float vfov); + void setVerticalFov(double vfov); void setEquatorialAim(const glm::dvec2& aim); void setBorderColor(const glm::ivec3& color); void setScreenSpaceSize(const glm::vec2& dimensions); void setVerticalFovWithScroll(float scroll); - float verticalFov() const; + double verticalFov() const; glm::ivec3 borderColor() const; glm::dvec2 targetDirectionEquatorial() const; glm::dvec3 targetDirectionGalactic() const; diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index cd81f72197..346a157a6b 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -124,7 +124,7 @@ glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords); * \return Angle in degrees between the OpenSpace camera's up direction vector and the * equatorial North Pole direction. */ -double cameraRoll(); +double targetRoll(const glm::dvec3& up, const glm::dvec3& forward); /** * Returns the view direction of the OpenSpace camera in galactic coordinates. * \return View direction of the OpenSpace camera in Cartesian galactic coordinates. diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 29a9ffed32..76b1f63c9e 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -55,17 +55,18 @@ public: void hideChromeInterface(bool shouldHide); bool hasLoadedImages() const; - float verticalFov() const; + double verticalFov() const; glm::ivec3 borderColor() const; glm::dvec2 equatorialAim() const; glm::dvec2 fieldsOfView() const; const std::deque& getSelectedImages() const; void setHasLoadedImages(bool isLoaded); - void setVerticalFov(float vfov); + void setVerticalFov(double vfov); void setIsSyncedWithWwt(bool isSynced); void setEquatorialAim(glm::dvec2 equatorial); void setBorderColor(glm::ivec3 color); + void setTargetRoll(double roll); void highlight(const glm::ivec3& addition); // The removal parameter decides what will be removed from the border color @@ -76,9 +77,10 @@ public: protected: void setIdInBrowser(const std::string& id); - float _verticalFov = 10.f; + double _verticalFov = 10.0f; glm::ivec3 _borderColor = glm::ivec3(70); glm::dvec2 _equatorialAim = glm::dvec2(0.0); + double _targetRoll = 0.0; bool _hasLoadedImages = false; std::deque _selectedImages; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 99ffabe324..d51d20b4d4 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -219,19 +219,19 @@ bool ScreenSpaceSkyBrowser::isAnimated() const{ return _isFovAnimated; } -void ScreenSpaceSkyBrowser::startFovAnimation(float fov) { +void ScreenSpaceSkyBrowser::startFovAnimation(double fov) { _isFovAnimated = true; _endVfov = fov; } void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { // If distance too large, keep animating. Else, stop animation - float diff = _endVfov - verticalFov(); + double diff = _endVfov - verticalFov(); bool shouldAnimate = abs(diff) > FovThreshold; if (shouldAnimate) { - float delta = _animationSpeed * (diff * deltaTime); - _verticalFov = std::clamp(_verticalFov + delta, 0.0001f, 70.0f); + double delta = _animationSpeed * (diff * static_cast(deltaTime)); + _verticalFov = std::clamp(_verticalFov + delta, 0.0, 70.0); } else { _isFovAnimated = false; @@ -295,10 +295,10 @@ void ScreenSpaceSkyBrowser::update() { void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) { // Make scroll more sensitive the smaller the FOV - float x = _verticalFov; - float zoomFactor = atan(x / 50.f) + exp(x / 40.f) - 0.999999f; - float zoom = scroll > 0.f ? -zoomFactor : zoomFactor; - _verticalFov = std::clamp(_verticalFov + zoom, 0.000001f, 70.0f); + double x = _verticalFov; + double zoomFactor = atan(x / 50.0) + exp(x / 40.0) - 0.99999999999999999999999999999; + double zoom = scroll > 0.0 ? -zoomFactor : zoomFactor; + _verticalFov = std::clamp(_verticalFov + zoom, 0.0, 70.0); } void ScreenSpaceSkyBrowser::bindTexture() { diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index c401e90f4d..d96c039db3 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -144,6 +146,11 @@ void TargetBrowserPair::synchronizeAim() { // target, send the locked coordinates to wwt glm::dvec2 aim = targetDirectionEquatorial(); _browser->setEquatorialAim(aim); + glm::dvec3 direction = _targetNode->worldPosition() - + global::navigationHandler->camera()->positionVec3(); + glm::dvec3 normalized = glm::normalize(direction); + glm::dvec3 up = global::navigationHandler->camera()->lookUpVectorWorldSpace(); + _browser->setTargetRoll(skybrowser::targetRoll(up, normalized)); _targetRenderable->setVerticalFov(_browser->verticalFov()); } } @@ -201,7 +208,7 @@ glm::vec2 TargetBrowserPair::size() const { return _browser->size(); } -float TargetBrowserPair::verticalFov() const { +double TargetBrowserPair::verticalFov() const { return _browser->verticalFov(); } @@ -251,7 +258,7 @@ void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { _browser->setIsSyncedWithWwt(isSynced); } -void TargetBrowserPair::setVerticalFov(float vfov) { +void TargetBrowserPair::setVerticalFov(double vfov) { _browser->setVerticalFov(vfov); _targetRenderable->setVerticalFov(vfov); } @@ -290,7 +297,7 @@ void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { } } -void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, float fovEnd, +void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd, bool shouldLockAfter) { _browser->startFovAnimation(fovEnd); diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index adb0290b9e..2b7f7ed23a 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -118,17 +118,13 @@ glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) { return glm::normalize(viewDirectionLocal); } -double cameraRoll() { - openspace::Camera* camera = global::navigationHandler->camera(); - glm::dvec3 upWorld = camera->lookUpVectorWorldSpace(); - glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace(); +double targetRoll(const glm::dvec3& up, const glm::dvec3& forward) { + glm::dvec3 upJ2000 = skybrowser::galacticToEquatorial(up); + glm::dvec3 forwardJ2000 = skybrowser::galacticToEquatorial(forward); - glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld); - glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld); - - glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole); - double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000); - double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000); + glm::dvec3 crossUpNorth = glm::cross(upJ2000, NorthPole); + double dotNorthUp = glm::dot(NorthPole, upJ2000); + double dotCrossUpNorthForward = glm::dot(upJ2000, forwardJ2000); return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); } diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 6237f7e63b..afd4f9fba8 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -72,7 +72,12 @@ const std::deque& WwtCommunicator::getSelectedImages() const { return _selectedImages; } -void WwtCommunicator::setVerticalFov(float vfov) { +void WwtCommunicator::setTargetRoll(double roll) +{ + _targetRoll = roll; +} + +void WwtCommunicator::setVerticalFov(double vfov) { _verticalFov = vfov; _equatorialAimIsDirty = true; } @@ -112,12 +117,11 @@ void WwtCommunicator::updateBorderColor() { } void WwtCommunicator::updateAim() { - double roll = _isSyncedWithWwt ? skybrowser::cameraRoll() : 0.0; // Message WorldWide Telescope current view ghoul::Dictionary message = moveCameraMessage( _equatorialAim, _verticalFov, - roll + _targetRoll ); sendMessageToWwt(message); } @@ -215,7 +219,7 @@ glm::ivec3 WwtCommunicator::borderColor() const { return _borderColor; } -float WwtCommunicator::verticalFov() const { +double WwtCommunicator::verticalFov() const { return _verticalFov; } From 82ae56ee882a0f2589064eb186738ebf86cb33f2 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 25 Mar 2022 17:11:16 -0400 Subject: [PATCH 239/251] Fix the "hideChromeInterface" call (will work as soon as the server wwt dist is updated) --- modules/skybrowser/include/wwtcommunicator.h | 1 - modules/skybrowser/src/wwtcommunicator.cpp | 15 +++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index 76b1f63c9e..c0e76c3185 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -97,7 +97,6 @@ private: ghoul::Dictionary removeImageMessage(const std::string& id); ghoul::Dictionary setImageOpacityMessage(const std::string& id, double opacity); ghoul::Dictionary setLayerOrderMessage(const std::string& id, int version); - ghoul::Dictionary hideChromeGuiMessage(bool isHidden); // Requires a newer CEF version bool _isSyncedWithWwt = false; bool _borderColorIsDirty = false; diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index afd4f9fba8..2aaef0e890 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -171,8 +171,9 @@ void WwtCommunicator::setImageOpacity(int i, float opacity) { } void WwtCommunicator::hideChromeInterface(bool shouldHide) { - ghoul::Dictionary msg = hideChromeGuiMessage(shouldHide); - sendMessageToWwt(msg); + std::string script = "sendMessageToWWT({event : \"modify_settings\", " + "settings : [[\"hideAllChrome\", true]], target: \"app\"});"; + executeJavascript(script); } void WwtCommunicator::update() { @@ -310,14 +311,4 @@ ghoul::Dictionary WwtCommunicator::setLayerOrderMessage(const std::string& id, i return msg; } - -ghoul::Dictionary WwtCommunicator::hideChromeGuiMessage(bool isHidden) { - using namespace std::string_literals; - ghoul::Dictionary msg; - msg.setValue("event", "modify_settings"s); - msg.setValue("settings", "[[\"hideAllChrome\", true]]"s); - msg.setValue("target", "app"s); - - return msg; -} } // namespace openspace From 7781c7c10de55cd5a826e8488c7e5053c8f90c15 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 29 Mar 2022 16:18:01 -0400 Subject: [PATCH 240/251] Fix issue with roll and right-click drag. This fixes issue #1932 --- modules/skybrowser/src/targetbrowserpair.cpp | 17 ++++++++++++----- modules/skybrowser/src/utility.cpp | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 0ab37677e5..076018e708 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -136,11 +136,18 @@ void TargetBrowserPair::synchronizeAim() { // target, send the locked coordinates to wwt glm::dvec2 aim = targetDirectionEquatorial(); _browser->setEquatorialAim(aim); - glm::dvec3 direction = _targetNode->worldPosition() - - global::navigationHandler->camera()->positionVec3(); - glm::dvec3 normalized = glm::normalize(direction); - glm::dvec3 up = global::navigationHandler->camera()->lookUpVectorWorldSpace(); - _browser->setTargetRoll(skybrowser::targetRoll(up, normalized)); + glm::dvec3 normal = glm::normalize( + _targetNode->worldPosition() - + global::navigationHandler->camera()->positionVec3() + ); + glm::dvec3 right = glm::normalize( + glm::cross( + global::navigationHandler->camera()->lookUpVectorWorldSpace(), + normal + ) + ); + glm::dvec3 up = glm::normalize(glm::cross(normal, right)); + _browser->setTargetRoll(skybrowser::targetRoll(up, normal)); _targetRenderable->setVerticalFov(_browser->verticalFov()); } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 2b7f7ed23a..69d3492257 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -124,7 +124,7 @@ double targetRoll(const glm::dvec3& up, const glm::dvec3& forward) { glm::dvec3 crossUpNorth = glm::cross(upJ2000, NorthPole); double dotNorthUp = glm::dot(NorthPole, upJ2000); - double dotCrossUpNorthForward = glm::dot(upJ2000, forwardJ2000); + double dotCrossUpNorthForward = glm::dot(crossUpNorth, forwardJ2000); return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp)); } From 85f3ac4bd902b9de153ab097eec87ca955ec867d Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 29 Mar 2022 18:03:06 -0400 Subject: [PATCH 241/251] Add check for if image data folder is empty. This fixes issue #1933 --- modules/skybrowser/src/wwtdatahandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 4fd343fe3e..dc0281f462 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -229,7 +229,7 @@ void WwtDataHandler::loadImages(const std::string& root, const std::filesystem::path& directory) { // Collect the wtml files, either by reading from disc or from a url - if (directoryExists(directory)) { + if (directoryExists(directory) && !std::filesystem::is_empty(directory)) { parseWtmlsFromDisc(_xmls, directory); LINFO("Loading images from directory"); } From 0f81a738db4e8d69b42504a5f5b8be2ffca742a1 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 30 Mar 2022 11:17:13 -0400 Subject: [PATCH 242/251] Pass the image fov to the GUI --- modules/skybrowser/skybrowsermodule_lua.inl | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 223ee3f740..ecb13b8736 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -246,6 +246,7 @@ namespace { image.setValue("thumbnail", img.thumbnailUrl); image.setValue("ra", img.equatorialSpherical.x); image.setValue("dec", img.equatorialSpherical.y); + image.setValue("fov", static_cast(img.fov)); image.setValue("cartesianDirection", img.equatorialCartesian); image.setValue("hasCelestialCoords", img.hasCelestialCoords); image.setValue("credits", img.credits); From 4063a49297cbcb34ce3f895367f91cb962d2d59f Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 30 Mar 2022 14:48:36 -0400 Subject: [PATCH 243/251] Change browser and targets starting position. Make browser larger than target by default --- modules/skybrowser/include/screenspaceskybrowser.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 6 +++--- modules/skybrowser/src/screenspaceskybrowser.cpp | 1 + modules/skybrowser/src/targetbrowserpair.cpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index a56bce98db..8599f3355e 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -85,9 +85,9 @@ private: bool _textureDimensionsIsDirty = false; bool _sizeIsDirty = false; + glm::vec2 _size = glm::vec2(1.f, 0.8f); // Animation of fieldOfView double _endVfov = 0.0; - glm::vec2 _size = glm::vec2(0.5f); }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index ecb13b8736..2064279aec 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -392,10 +392,10 @@ namespace { std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); // Determine starting point on screen for the target - glm::vec3 positionBrowser = { -1.0f, -0.5f, -2.1f }; - glm::vec3 positionTarget = { 1.0f, 0.5f, -2.1f }; + glm::vec3 positionBrowser = { -1.f, -0.5f, -2.1f }; + glm::vec3 positionTarget = { 0.9f, 0.4f, -2.1f }; glm::dvec3 galacticTarget = skybrowser::localCameraToGalactic(positionTarget); - std::string guiPath = "/SkyBrowser"; + std::string guiPath = "/Sky Browser"; std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/"; double fov = 70.0; double size = skybrowser::sizeFromFov(fov, galacticTarget); diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index d51d20b4d4..c3af9c7111 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -137,6 +137,7 @@ namespace openspace { SkyBrowserModule* module = global::moduleEngine->module(); _borderColor = randomBorderColor(module->highlight()); } + _scale = _size.y * 0.5; } ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() { diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 076018e708..d211c5f26f 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -45,7 +45,7 @@ TargetBrowserPair::TargetBrowserPair(SceneGraphNode* targetNode, : _targetNode(targetNode), _browser(browser) { ghoul_assert(browser != nullptr, "Sky browser is null pointer!"); - ghoul_assert(target != nullptr, "Sky target is null pointer!"); + ghoul_assert(targetNode != nullptr, "Sky target is null pointer!"); _targetRenderable = dynamic_cast(_targetNode->renderable()); } From badd2e2ff23363fa39c49254a3a7ae34dc437aa8 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Wed, 30 Mar 2022 16:05:26 -0400 Subject: [PATCH 244/251] Create animation class to clean up animation code --- .../skybrowser/include/targetbrowserpair.h | 10 ++--- modules/skybrowser/include/utility.h | 16 ++++++++ modules/skybrowser/src/targetbrowserpair.cpp | 37 +++++-------------- modules/skybrowser/src/utility.cpp | 31 ++++++++++++++++ 4 files changed, 59 insertions(+), 35 deletions(-) diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 60c0fd48c4..763f3b6d1b 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___TARGETBROWSERPAIR___H__ #define __OPENSPACE_MODULE_SKYBROWSER___TARGETBROWSERPAIR___H__ +#include #include #include #include @@ -129,13 +130,8 @@ private: bool _shouldLockAfterAnimation = false; bool _targetIsAnimated = false; - // Fading - float _goal = 1.0f; - float _startTarget = 1.0f; - float _startBrowser = 1.0f; - std::chrono::milliseconds _fadeTime = std::chrono::milliseconds(2000); - std::chrono::system_clock::time_point _fadeStart; - bool _isFading = false; + skybrowser::Animation _fadeBrowser = skybrowser::Animation(0.f, 0.f, 0.0); + skybrowser::Animation _fadeTarget = skybrowser::Animation(0.f, 0.f, 0.0); glm::dvec2 _equatorialAim = glm::dvec2(0.0); glm::ivec3 _borderColor = glm::ivec3(255); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 346a157a6b..77286a3597 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -27,6 +27,7 @@ #include #include +#include namespace openspace::skybrowser { // Constants @@ -184,6 +185,21 @@ glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& * \return Field of view */ double sizeFromFov(double fov, glm::dvec3 worldPosition); + +class Animation { +public: + Animation(float start, float goal, double time); + void start(); + bool isFinished() const; + float getNewValue(); +private: + // Animation + bool _isAnimating = false; + float _goal = 1.0f; + float _start = 1.0f; + std::chrono::milliseconds _animationTime = std::chrono::milliseconds(2000); + std::chrono::system_clock::time_point _startTime; +}; } // namespace openspace::skybrowser diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index d211c5f26f..0effa416d5 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -303,12 +303,10 @@ void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { void TargetBrowserPair::startFading(float goal, float fadeTime) { - _startTarget = _targetRenderable->opacity(); - _startBrowser = _browser->opacity(); - _goal = goal; - _fadeTime = std::chrono::milliseconds(static_cast(fadeTime * 1000)); - _fadeStart = std::chrono::system_clock::now(); - _isFading = true; + _fadeTarget = skybrowser::Animation(_targetRenderable->opacity(), goal, fadeTime); + _fadeBrowser = skybrowser::Animation(_browser->opacity(), goal, fadeTime); + _fadeTarget.start(); + _fadeBrowser.start(); } void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd, @@ -367,7 +365,7 @@ void TargetBrowserPair::centerTargetOnScreen() { } bool TargetBrowserPair::hasFinishedFading() const { - return !_isFading; + return _fadeBrowser.isFinished() && _fadeTarget.isFinished(); } bool TargetBrowserPair::isFacingCamera() const { @@ -388,28 +386,11 @@ ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const { void TargetBrowserPair::incrementallyFade(float deltaTime) { - using namespace std::chrono; - system_clock::time_point now = system_clock::now(); - std::chrono::duration timeSpent = now - _fadeStart; - - if (timeSpent.count() > _fadeTime.count()) { - _isFading = false; - _browser->setOpacity(_goal); - _targetRenderable->setOpacity(_goal); + if (!_fadeBrowser.isFinished()) { + _browser->setOpacity(_fadeBrowser.getNewValue()); } - else { - float percentage = timeSpent / _fadeTime; - float newOpacityTarget; - float newOpacityBrowser; - if (_goal > _startTarget || _goal > _startBrowser) { - newOpacityTarget, newOpacityBrowser = _goal * percentage; - } - else { - newOpacityTarget = _startTarget * (1.f - percentage); - newOpacityBrowser = _startBrowser * (1.f - percentage); - } - _browser->setOpacity(newOpacityBrowser); - _targetRenderable->setOpacity(newOpacityTarget); + if (!_fadeTarget.isFinished()) { + _targetRenderable->setOpacity(_fadeTarget.getNewValue()); } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index 69d3492257..d710622d00 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -211,6 +211,37 @@ double sizeFromFov(double fov, glm::dvec3 worldPosition) { double opposite = 2 * adjacent * glm::tan(glm::radians(fov * 0.5)); return opposite; } + +Animation::Animation(float start, float goal, double time) + : _start(start), _goal(goal) +{ + _animationTime = std::chrono::milliseconds(static_cast(time * 1000)); +} + +void Animation::start() +{ + _isAnimating = true; + _startTime = std::chrono::system_clock::now(); +} + +bool Animation::isFinished() const +{ + return !_isAnimating; +} + +float Animation::getNewValue() { + using namespace std::chrono; + system_clock::time_point now = system_clock::now(); + std::chrono::duration timeSpent = now - _startTime; + if (timeSpent.count() > _animationTime.count()) { + _isAnimating = false; + return _goal; + } + else { + float percentage = timeSpent / _animationTime; + return _goal > _start ? _goal * percentage : _start * (1.f - percentage); + } +} } // namespace openspace From 233d000aea2551fe20753308245f35e72d4e9a89 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 31 Mar 2022 15:58:38 -0400 Subject: [PATCH 245/251] Make all animations depend on system time instead of fps. This will make the animations robust with low fps. Add easing functions. --- .../skybrowser/include/renderableskytarget.h | 2 - .../include/screenspaceskybrowser.h | 11 --- .../skybrowser/include/targetbrowserpair.h | 22 ++--- modules/skybrowser/include/utility.h | 56 +++++++++--- modules/skybrowser/skybrowsermodule.cpp | 85 ++++++++++-------- modules/skybrowser/skybrowsermodule.h | 24 ++--- .../skybrowser/src/screenspaceskybrowser.cpp | 35 -------- modules/skybrowser/src/targetbrowserpair.cpp | 89 +++++++------------ modules/skybrowser/src/utility.cpp | 76 ++++++++++------ 9 files changed, 198 insertions(+), 202 deletions(-) diff --git a/modules/skybrowser/include/renderableskytarget.h b/modules/skybrowser/include/renderableskytarget.h index 0fa130ae27..64e04da304 100644 --- a/modules/skybrowser/include/renderableskytarget.h +++ b/modules/skybrowser/include/renderableskytarget.h @@ -39,8 +39,6 @@ class ScreenSpaceSkyBrowser; class RenderableSkyTarget : public RenderablePlane { public: - constexpr static const float DeltaTimeThreshold = 0.03f; - explicit RenderableSkyTarget(const ghoul::Dictionary& dictionary); void initializeGL() override; diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 8599f3355e..4d26d9d3b9 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -38,8 +38,6 @@ namespace openspace { class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator { public: - constexpr static const double FovThreshold = 0.001; - explicit ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary); ~ScreenSpaceSkyBrowser(); @@ -49,11 +47,6 @@ public: void render() override; void update() override; - // Animation - bool isAnimated() const; - void startFovAnimation(double fov); - void incrementallyAnimateToFov(float deltaTime); - float opacity() const; glm::vec2 size() const; @@ -72,7 +65,6 @@ public: void removeRenderCopy(); private: - properties::DoubleProperty _animationSpeed; properties::FloatProperty _textureQuality; properties::BoolProperty _renderOnlyOnMaster; std::vector> _renderCopies; @@ -81,13 +73,10 @@ private: // Flags bool _isSyncedWithWwt = false; - bool _isFovAnimated = false; bool _textureDimensionsIsDirty = false; bool _sizeIsDirty = false; glm::vec2 _size = glm::vec2(1.f, 0.8f); - // Animation of fieldOfView - double _endVfov = 0.0; }; } // namespace openspace diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 763f3b6d1b..f9a613133e 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -40,8 +40,6 @@ class SceneGraphNode; class TargetBrowserPair { public: - constexpr static const float DeltaTimeThreshold = 0.03f; - TargetBrowserPair(SceneGraphNode* target, ScreenSpaceSkyBrowser* browser); TargetBrowserPair& operator=(TargetBrowserPair other); @@ -51,10 +49,10 @@ public: void removeHighlight(const glm::ivec3& color); void highlight(const glm::ivec3& color); // Animation - void startAnimation(glm::dvec3 coordsEnd, double fovEnd, bool shouldLockAfter = true); - void incrementallyAnimateToCoordinate(double deltaTime); + void startAnimation(glm::dvec3 coordsEnd, double fovEnd); + void incrementallyAnimateToCoordinate(); void startFading(float goal, float fadeTime); - void incrementallyFade(float deltaTime); + void incrementallyFade(); // Mouse interaction bool checkMouseIntersection(const glm::vec2& mousePosition); glm::vec2 selectedScreenSpacePosition() const; @@ -69,7 +67,6 @@ public: // Target void centerTargetOnScreen(); - void incrementallyAnimateTarget(float deltaTime); bool hasFinishedFading() const; bool isFacingCamera() const; @@ -125,13 +122,12 @@ private: SceneGraphNode* _targetNode = nullptr; // Animation - glm::dvec3 _animationStart = glm::dvec3(0); - glm::dvec3 _animationEnd = glm::dvec3(0); - bool _shouldLockAfterAnimation = false; - bool _targetIsAnimated = false; - - skybrowser::Animation _fadeBrowser = skybrowser::Animation(0.f, 0.f, 0.0); - skybrowser::Animation _fadeTarget = skybrowser::Animation(0.f, 0.f, 0.0); + skybrowser::Animation _fadeBrowser = skybrowser::Animation(0.f, 0.f, 0.0); + skybrowser::Animation _fadeTarget = skybrowser::Animation(0.f, 0.f, 0.0); + skybrowser::Animation _fovAnimation = skybrowser::Animation(0.0, 0.0, 0.0); + skybrowser::Animation _moveTarget = + skybrowser::Animation(glm::dvec3(0.0), glm::dvec3(0.0), 0.0); + bool _targetIsAnimating = false; glm::dvec2 _equatorialAim = glm::dvec2(0.0); glm::ivec3 _borderColor = glm::ivec3(255); diff --git a/modules/skybrowser/include/utility.h b/modules/skybrowser/include/utility.h index 77286a3597..432793be4c 100644 --- a/modules/skybrowser/include/utility.h +++ b/modules/skybrowser/include/utility.h @@ -171,12 +171,12 @@ double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end); * multiple times in order to animate. * \param start Cartesian vector * \param end Cartesian vector - * \param deltaTime The time between the current frame and the last - * \param speedFactor Factor that determines how fast the animation will be + * \param percentage Percentage of the angle between the vectors that the matrix should + * rotate * \return 4x4 matrix for incremental rotation animation of a vector */ glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, - double deltaTime, double speedFactor = 1.0); + double percentage); /** * Returns the size in meters that for example a plane would need to have in order to * display a specified field of view. @@ -186,17 +186,53 @@ glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& */ double sizeFromFov(double fov, glm::dvec3 worldPosition); +template class Animation { public: - Animation(float start, float goal, double time); - void start(); - bool isFinished() const; - float getNewValue(); + Animation(T start, T goal, double time) + : _start(start), _goal(goal) + { + _animationTime = std::chrono::milliseconds(static_cast(time * 1000)); + } + void start() { + _isStarted = true; + _startTime = std::chrono::system_clock::now(); + } + void stop() { + _isStarted = false; + } + bool isAnimating() const { + bool timeLeft = timeSpent().count() < _animationTime.count() ? true : false; + return timeLeft && _isStarted; + } + T getNewValue(); + glm::dmat4 getRotationMatrix(); + private: + std::chrono::duration timeSpent() const { + using namespace std::chrono; + system_clock::time_point now = system_clock::now(); + std::chrono::duration timeSpent = now - _startTime; + return timeSpent; + } + double percentageSpent() const { + return timeSpent().count() / _animationTime.count(); + } + + double easeOutExpo(double x) { + double epsilon = std::numeric_limits::epsilon(); + return std::abs(x - 1.0) < epsilon ? 1.0 : 1.0 - pow(2.0, -10.0 * x); + } + + double easeInOutSine(double x) { + return -(cos(glm::pi() * x) - 1.0) / 2.0; + } + // Animation - bool _isAnimating = false; - float _goal = 1.0f; - float _start = 1.0f; + bool _isStarted = false; + double _lastPercentage = 0; + T _goal; + T _start; std::chrono::milliseconds _animationTime = std::chrono::milliseconds(2000); std::chrono::system_clock::time_point _startTime; }; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index d727e433e5..0198396229 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -60,6 +60,18 @@ namespace { "coordinate which is outside of the field of view." }; + constexpr const openspace::properties::Property::PropertyInfo TargetSpeedInfo = { + "TargetAnimationSpeed", + "Target Animation Speed", + "This determines the speed of the animation of the sky target." + }; + + constexpr const openspace::properties::Property::PropertyInfo BrowserSpeedInfo = { + "BrowserAnimationSpeed", + "Field Of View Animation Speed", + "This determines the speed of the animation of the field of view in the browser." + }; + struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { // [[codegen::verbatim(AllowInteractionInfo.description)]] std::optional allowMouseInteraction; @@ -69,6 +81,12 @@ namespace { // [[codegen::verbatim(CameraRotSpeedInfo.description)]] std::optional cameraRotSpeed; + + // [[codegen::verbatim(TargetSpeedInfo.description)]] + std::optional targetSpeed; + + // [[codegen::verbatim(BrowserSpeedInfo.description)]] + std::optional browserSpeed; }; #include "skybrowsermodule_codegen.cpp" @@ -79,11 +97,15 @@ SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _allowMouseInteraction(AllowInteractionInfo, true) , _allowCameraRotation(AllowRotationInfo, true) - , _cameraRotationSpeed(CameraRotSpeedInfo, 1.f, 0.1f, 10.f) + , _cameraRotationSpeed(CameraRotSpeedInfo, 0.5, 0.0, 1.0) + , _targetAnimationSpeed(TargetSpeedInfo, 0.2, 0.0, 1.0) + , _browserAnimationSpeed(BrowserSpeedInfo, 5.0, 0.0, 10.0) { addProperty(_allowMouseInteraction); addProperty(_allowCameraRotation); addProperty(_cameraRotationSpeed); + addProperty(_targetAnimationSpeed); + addProperty(_browserAnimationSpeed); // Set callback functions global::callback::mouseButton->emplace_back( @@ -93,7 +115,7 @@ SkyBrowserModule::SkyBrowserModule() } if (action == MouseAction::Press) { - _isCameraRotating = false; + _cameraRotation.stop(); if (_mouseOnPair) { handleMouseClick(button); return true; @@ -190,10 +212,9 @@ SkyBrowserModule::SkyBrowserModule() } ); } - double deltaTime = global::windowDelegate->deltaTime(); // Fade pairs if the camera moved in or out the solar system if (_isFading) { - incrementallyFadeBrowserTargets(_goal, deltaTime); + incrementallyFadeBrowserTargets(_goal); } if (_isCameraInSolarSystem) { std::for_each( @@ -203,10 +224,10 @@ SkyBrowserModule::SkyBrowserModule() pair->synchronizeAim(); } ); - incrementallyAnimateTargets(deltaTime); + incrementallyAnimateTargets(); } - if (_isCameraRotating && _allowCameraRotation) { - incrementallyRotateCamera(deltaTime, _cameraRotationSpeed); + if (_cameraRotation.isAnimating() && _allowCameraRotation) { + incrementallyRotateCamera(); } }); } @@ -410,45 +431,29 @@ TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) { void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) { // Save coordinates to rotate to in galactic world coordinates - _endAnimation = endAnimation; - _startAnimation = skybrowser::cameraDirectionGalactic(); - _isCameraRotating = true; -} - -void SkyBrowserModule::incrementallyRotateCamera(double deltaTime, double animationSpeed) { - - // Find smallest angle between the two vectors - double angle = skybrowser::angleBetweenVectors(_startAnimation, _endAnimation); - - if(angle > StopAnimationThreshold) { - - glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( - _startAnimation, - _endAnimation, - deltaTime, - animationSpeed - ); + glm::dvec3 start = skybrowser::cameraDirectionGalactic(); + double angle = skybrowser::angleBetweenVectors(start, endAnimation); + double time = angle / _cameraRotationSpeed; + _cameraRotation = skybrowser::Animation(start, endAnimation, time); + _cameraRotation.start(); +} +void SkyBrowserModule::incrementallyRotateCamera() { + if(_cameraRotation.isAnimating()) { + glm::dmat4 rotMat = _cameraRotation.getRotationMatrix(); // Rotate global::navigationHandler->camera()->rotate(glm::quat_cast(rotMat)); - - // Update camera direction - _startAnimation = skybrowser::cameraDirectionGalactic(); - } - else { - _isCameraRotating = false; } } -void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, - float deltaTime) +void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal) { bool isAllFinished = true; for (std::unique_ptr& pair : _targetsBrowsers) { if (pair->isEnabled()) { bool isPairFinished = pair->hasFinishedFading(); if (!isPairFinished) { - pair->incrementallyFade(deltaTime); + pair->incrementallyFade(); } else if (isPairFinished && goal == Transparency::Transparent) { pair->setEnabled(false); @@ -465,14 +470,22 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, } } -void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) { +void SkyBrowserModule::incrementallyAnimateTargets() { for (std::unique_ptr& pair : _targetsBrowsers) { if (pair->isEnabled()) { - pair->incrementallyAnimateToCoordinate(deltaTime); + pair->incrementallyAnimateToCoordinate(); } } } +double SkyBrowserModule::targetAnimationSpeed() const { + return _targetAnimationSpeed; +} + +double SkyBrowserModule::browserAnimationSpeed() const { + return _browserAnimationSpeed; +} + void SkyBrowserModule::setSelectedBrowser(const std::string& id) { TargetBrowserPair* found = getPair(id); if (found) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index f754e7f567..bbc629046a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -25,8 +25,9 @@ #ifndef __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ #define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__ -#include +#include +#include #include #include #include @@ -56,8 +57,6 @@ enum class MouseInteraction { class SkyBrowserModule : public OpenSpaceModule { public: constexpr static const char* Name = "SkyBrowser"; - constexpr static const double StopAnimationThreshold = 0.0005; - constexpr static const double FadingTime = 2.0; const double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit; SkyBrowserModule(); @@ -77,9 +76,11 @@ public: // Rotation, animation, placement void lookAtTarget(const std::string& id); void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate - void incrementallyRotateCamera(double deltaTime, double animationSpeed); - void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime); - void incrementallyAnimateTargets(double deltaTime); + void incrementallyRotateCamera(); + void incrementallyFadeBrowserTargets(Transparency goal); + void incrementallyAnimateTargets(); + double targetAnimationSpeed() const; + double browserAnimationSpeed() const; bool isCameraInSolarSystem() const; bool isSelectedPairFacingCamera(); @@ -110,6 +111,8 @@ private: properties::BoolProperty _allowMouseInteraction; properties::BoolProperty _allowCameraRotation; properties::DoubleProperty _cameraRotationSpeed; + properties::DoubleProperty _targetAnimationSpeed; + properties::DoubleProperty _browserAnimationSpeed; glm::ivec3 _highlightAddition = glm::ivec3(35); // Highlight object when mouse hovers // The browsers and targets @@ -122,9 +125,8 @@ private: Transparency _goal = Transparency::Opaque; // Flags - bool _isCameraInSolarSystem{ true }; // Visualization modes - bool _isFading{ false }; - bool _isCameraRotating = false; + bool _isCameraInSolarSystem = true; // Visualization modes + bool _isFading = false; // Mouse interaction MouseInteraction _interactionMode; @@ -134,8 +136,8 @@ private: glm::dvec3 _startTargetPosition; // Animation of rotation of camera to look at coordinate galactic coordinates - glm::dvec3 _startAnimation; - glm::dvec3 _endAnimation; + skybrowser::Animation _cameraRotation = + skybrowser::Animation(glm::dvec3(0.0), glm::dvec3(0.0), 0.0); // Data handler for the image collections std::unique_ptr _dataHandler; diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index c3af9c7111..99dadbd468 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -39,13 +39,6 @@ namespace { constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser"; - constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = { - "AnimationSpeed", - "Field Of View Animation Speed", - "A factor that determines the speed of the animation of the field of view. A " - "higher number for the factor means a faster speed." - }; - constexpr const openspace::properties::Property::PropertyInfo TextureQualityInfo = { "TextureQuality", "Quality of Texture", @@ -69,9 +62,6 @@ namespace { }; struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { - // [[codegen::verbatim(AnimationSpeedInfo.description)]] - std::optional animationSpeed; - // [[codegen::verbatim(TextureQualityInfo.description)]] std::optional textureQuality; @@ -107,7 +97,6 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) , WwtCommunicator(dictionary) - , _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0) , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) , _renderOnlyOnMaster(RenderOnMasterInfo, false) { @@ -116,7 +105,6 @@ namespace openspace { // Handle target dimension property const Parameters p = codegen::bake(dictionary); _textureQuality = p.textureQuality.value_or(_textureQuality); - _animationSpeed = p.animationSpeed.value_or(_animationSpeed); _renderOnlyOnMaster = p.renderOnlyOnMaster.value_or(_renderOnlyOnMaster); addProperty(_url); @@ -216,29 +204,6 @@ bool ScreenSpaceSkyBrowser::deinitializeGL() { return true; } -bool ScreenSpaceSkyBrowser::isAnimated() const{ - return _isFovAnimated; -} - -void ScreenSpaceSkyBrowser::startFovAnimation(double fov) { - _isFovAnimated = true; - _endVfov = fov; -} - -void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) { - // If distance too large, keep animating. Else, stop animation - double diff = _endVfov - verticalFov(); - bool shouldAnimate = abs(diff) > FovThreshold; - - if (shouldAnimate) { - double delta = _animationSpeed * (diff * static_cast(deltaTime)); - _verticalFov = std::clamp(_verticalFov + delta, 0.0, 70.0); - } - else { - _isFovAnimated = false; - } -} - void ScreenSpaceSkyBrowser::render() { WwtCommunicator::render(); diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 0effa416d5..6825f7daf0 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -131,7 +132,7 @@ void TargetBrowserPair::translateSelected(const glm::vec2& start, } void TargetBrowserPair::synchronizeAim() { - if (!_targetIsAnimated) { + if (!_moveTarget.isAnimating()) { // To remove the lag effect when moving the camera while having a locked // target, send the locked coordinates to wwt glm::dvec2 aim = targetDirectionEquatorial(); @@ -230,7 +231,7 @@ void TargetBrowserPair::selectImage(const ImageData& image, int i) { // Animate the target to the image coordinate position // unlock(); glm::dvec3 galactic = skybrowser::equatorialToGalactic(image.equatorialCartesian); - startAnimation(galactic * skybrowser::CelestialSphereRadius, image.fov, true); + startAnimation(galactic * skybrowser::CelestialSphereRadius, image.fov); } } @@ -290,70 +291,46 @@ void TargetBrowserPair::setVerticalFovWithScroll(float scroll) { _browser->setVerticalFovWithScroll(scroll); } -void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) { +void TargetBrowserPair::incrementallyAnimateToCoordinate() { // Animate the target before the field of view starts to animate - if (_targetIsAnimated) { - incrementallyAnimateTarget(static_cast(deltaTime)); + if (_moveTarget.isAnimating()) { + aimTargetGalactic(_moveTarget.getNewValue()); } - else if (_browser->isAnimated()) { - _browser->incrementallyAnimateToFov(static_cast(deltaTime)); + else if (!_moveTarget.isAnimating() && _targetIsAnimating) { + // Set the finished position + aimTargetGalactic(_moveTarget.getNewValue()); + _fovAnimation.start(); + _targetIsAnimating = false; + } + if (_fovAnimation.isAnimating()) { + _browser->setVerticalFov(_fovAnimation.getNewValue()); _targetRenderable->setVerticalFov(_browser->verticalFov()); } } -void TargetBrowserPair::startFading(float goal, float fadeTime) -{ +void TargetBrowserPair::startFading(float goal, float fadeTime) { _fadeTarget = skybrowser::Animation(_targetRenderable->opacity(), goal, fadeTime); _fadeBrowser = skybrowser::Animation(_browser->opacity(), goal, fadeTime); _fadeTarget.start(); _fadeBrowser.start(); } -void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd, - bool shouldLockAfter) -{ - _browser->startFovAnimation(fovEnd); +void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd) { + SkyBrowserModule* module = global::moduleEngine->module(); + double fovSpeed = module->browserAnimationSpeed(); + // The speed is given degrees /sec + double fovTime = abs(_browser->verticalFov() - fovEnd) / fovSpeed; + // Fov animation + _fovAnimation = skybrowser::Animation(_browser->verticalFov(), fovEnd, fovTime); // Target animation - _animationStart = glm::normalize(_targetNode->worldPosition()) * + glm::dvec3 start = glm::normalize(_targetNode->worldPosition()) * skybrowser::CelestialSphereRadius; - _animationEnd = galacticCoords; - _shouldLockAfterAnimation = shouldLockAfter; - _targetIsAnimated = true; -} - -void TargetBrowserPair::incrementallyAnimateTarget(float deltaTime) { - // At fps that are too low, the animation stops working. Just place target instead - bool fpsTooLow = deltaTime > DeltaTimeThreshold; - // Find smallest angle between the two vectors - double smallestAngle = skybrowser::angleBetweenVectors( - glm::normalize(_animationStart), - glm::normalize(_animationEnd) - ); - bool hasArrived = smallestAngle < _targetRenderable->stopAnimationThreshold(); - - // Only keep animating when target is not at goal position - if (!hasArrived && !fpsTooLow) { - glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( - glm::normalize(_animationStart), - glm::normalize(_animationEnd), - deltaTime, - _targetRenderable->animationSpeed() - ); - - // Rotate target direction - glm::dvec3 newPos = glm::dvec3(rotMat * glm::dvec4(_animationStart, 1.0)); - - aimTargetGalactic(newPos); - - // Update position - _animationStart = newPos; - } - else { - // Set the exact target position - aimTargetGalactic(_animationEnd); - _targetIsAnimated = false; - } + double targetSpeed = module->targetAnimationSpeed(); + double angle = skybrowser::angleBetweenVectors(start, galacticCoords); + _moveTarget = skybrowser::Animation(start, galacticCoords, angle / targetSpeed); + _moveTarget.start(); + _targetIsAnimating = true; } void TargetBrowserPair::centerTargetOnScreen() { @@ -361,11 +338,11 @@ void TargetBrowserPair::centerTargetOnScreen() { glm::dvec3 viewDirection = skybrowser::cameraDirectionGalactic(); // Keep the current fov float currentFov = verticalFov(); - startAnimation(viewDirection, currentFov, false); + startAnimation(viewDirection, currentFov); } bool TargetBrowserPair::hasFinishedFading() const { - return _fadeBrowser.isFinished() && _fadeTarget.isFinished(); + return !_fadeBrowser.isAnimating() && !_fadeTarget.isAnimating(); } bool TargetBrowserPair::isFacingCamera() const { @@ -384,12 +361,12 @@ ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const { return _browser; } -void TargetBrowserPair::incrementallyFade(float deltaTime) +void TargetBrowserPair::incrementallyFade() { - if (!_fadeBrowser.isFinished()) { + if (_fadeBrowser.isAnimating()) { _browser->setOpacity(_fadeBrowser.getNewValue()); } - if (!_fadeTarget.isFinished()) { + if (_fadeTarget.isAnimating()) { _targetRenderable->setOpacity(_fadeTarget.getNewValue()); } } diff --git a/modules/skybrowser/src/utility.cpp b/modules/skybrowser/src/utility.cpp index d710622d00..b0f381e758 100644 --- a/modules/skybrowser/src/utility.cpp +++ b/modules/skybrowser/src/utility.cpp @@ -190,13 +190,13 @@ double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) { } glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end, - double deltaTime, double speedFactor) + double percentage) { double smallestAngle = angleBetweenVectors(start, end); // Calculate rotation this frame - double rotationAngle = smallestAngle * deltaTime * speedFactor; + double rotationAngle = smallestAngle * percentage; - // Create the rotation matrix for local camera space + // Create the rotation matrix glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end)); return glm::rotate(rotationAngle, rotationAxis); } @@ -212,36 +212,56 @@ double sizeFromFov(double fov, glm::dvec3 worldPosition) { return opposite; } -Animation::Animation(float start, float goal, double time) - : _start(start), _goal(goal) -{ - _animationTime = std::chrono::milliseconds(static_cast(time * 1000)); -} - -void Animation::start() -{ - _isAnimating = true; - _startTime = std::chrono::system_clock::now(); -} - -bool Animation::isFinished() const -{ - return !_isAnimating; -} - -float Animation::getNewValue() { - using namespace std::chrono; - system_clock::time_point now = system_clock::now(); - std::chrono::duration timeSpent = now - _startTime; - if (timeSpent.count() > _animationTime.count()) { - _isAnimating = false; +float Animation::getNewValue() { + if (!isAnimating()) { return _goal; } else { - float percentage = timeSpent / _animationTime; - return _goal > _start ? _goal * percentage : _start * (1.f - percentage); + float percentage = static_cast(percentageSpent()); + float diff = (_goal - _start) * easeOutExpo(percentage); + return _start + diff; } } + +double Animation::getNewValue() { + if (!isAnimating()) { + return _goal; + } + else { + double percentage = percentageSpent(); + double diff = (_goal - _start) * easeOutExpo(percentage); + return _start + diff; + } +} + +glm::dmat4 Animation::getRotationMatrix() { + if (!isAnimating()) { + return glm::dmat4(1.0); + } + double percentage = easeInOutSine(percentageSpent()); + double increment = percentage - _lastPercentage; + _lastPercentage = percentage; + + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( + glm::normalize(_start), + glm::normalize(_goal), + increment + ); + return rotMat; +} + +glm::dvec3 Animation::getNewValue() { + if (!isAnimating()) { + return _goal; + } + glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix( + glm::normalize(_start), + glm::normalize(_goal), + easeOutExpo(percentageSpent()) + ); + // Rotate direction + return glm::dvec3(rotMat * glm::dvec4(_start, 1.0));; +} } // namespace openspace From bd5f4119b773ea9cc42525811c4e0f02f6e15833 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 31 Mar 2022 17:36:48 -0400 Subject: [PATCH 246/251] Make it possible to create multiple render copies at once and spread them out evenly on the azimuth coordinate --- .../include/screenspaceskybrowser.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 7 +++-- .../skybrowser/src/screenspaceskybrowser.cpp | 30 +++++++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 4d26d9d3b9..a91216e8a6 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -61,7 +61,7 @@ public: void updateTextureResolution(); // Copies rendered - void addRenderCopy(); + void addRenderCopy(const glm::vec3& raePosition, int nCopies); void removeRenderCopy(); private: diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 2064279aec..815e3e668a 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -591,14 +591,17 @@ namespace { /** * Takes an identifier to a sky browser and adds a rendered copy to it. * \param id Identifier +* \param raePosition Position in radius, azimuth, elevation coordinates +* \param nCopies Number of copies */ -[[codegen::luawrap]] void addRenderCopy(std::string id) { +[[codegen::luawrap]] void addRenderCopy(std::string id, + int nCopies = 1, glm::vec3 raePosition = glm::vec3(2.1f, 0.f, 0.f)) { // Get module SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* pair = module->getPair(id); if (pair) { - pair->browser()->addRenderCopy(); + pair->browser()->addRenderCopy(raePosition, nCopies); } } /** diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index 99dadbd468..ad3d8e4996 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -178,18 +178,24 @@ void ScreenSpaceSkyBrowser::updateTextureResolution() { _objectSize = glm::ivec3(_texture->dimensions()); } -void ScreenSpaceSkyBrowser::addRenderCopy() { - openspace::properties::Property::PropertyInfo info = RenderCopyInfo; - info.identifier += _renderCopies.size(); - _renderCopies.push_back( - std::make_unique( - info, - glm::vec3(2.1f, 0.f, 0.f), - glm::vec3(0.f, -glm::pi(), -glm::half_pi()), - glm::vec3(10.f, glm::pi(), glm::half_pi()) - ) - ); - addProperty(_renderCopies.back().get()); +void ScreenSpaceSkyBrowser::addRenderCopy(const glm::vec3& raePosition, int nCopies) { + int start = _renderCopies.size(); + for (int i = 0; i < nCopies; i++) { + openspace::properties::Property::PropertyInfo info = RenderCopyInfo; + float azimuth = i * glm::two_pi() / nCopies; + glm::vec3 position = raePosition + glm::vec3(0.f, azimuth, 0.f); + std::string id = "Rendercopy" + std::to_string(start + i); + info.identifier = id.c_str(); + _renderCopies.push_back( + std::make_unique( + info, + position, + glm::vec3(0.f, -glm::pi(), -glm::half_pi()), + glm::vec3(10.f, glm::pi(), glm::half_pi()) + ) + ); + addProperty(_renderCopies.back().get()); + } } void ScreenSpaceSkyBrowser::removeRenderCopy() { From f14e482ff1863e5b49892798b20f5857da3fafbc Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 1 Apr 2022 17:06:51 -0400 Subject: [PATCH 247/251] Create lua function to move render copies --- .../include/screenspaceskybrowser.h | 2 ++ .../skybrowser/include/targetbrowserpair.h | 1 + modules/skybrowser/skybrowsermodule.cpp | 3 ++- modules/skybrowser/skybrowsermodule_lua.inl | 23 +++++++++++++++++- .../skybrowser/src/screenspaceskybrowser.cpp | 24 +++++++++++++++++-- modules/skybrowser/src/targetbrowserpair.cpp | 5 ++++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index a91216e8a6..9f612d6a07 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -63,6 +63,8 @@ public: // Copies rendered void addRenderCopy(const glm::vec3& raePosition, int nCopies); void removeRenderCopy(); + std::vector renderCopies(); + void moveRenderCopy(int i, glm::vec3 raePosition); private: properties::FloatProperty _textureQuality; diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index f9a613133e..cc22254764 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -64,6 +64,7 @@ public: // Browser void sendIdToBrowser(); void updateBrowserSize(); + std::vector renderCopies(); // Target void centerTargetOnScreen(); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 0198396229..a5dbbf83d9 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -564,7 +564,8 @@ scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { codegen::lua::TranslateScreenSpaceRenderable, codegen::lua::AddRenderCopy, codegen::lua::SetScreenSpaceSize, - codegen::lua::RemoveRenderCopy + codegen::lua::RemoveRenderCopy, + codegen::lua::MoveRenderCopy } }; } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 815e3e668a..32776f098c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -325,8 +325,13 @@ namespace { target.setValue("dec", spherical.y); target.setValue("color", pair->borderColor()); target.setValue("size", glm::dvec2(pair->size())); - + std::vector copies = pair->renderCopies(); + ghoul::Dictionary copiesData; + for (int i = 0; i < copies.size(); i++) { + copiesData.setValue("Copy" + std::to_string(i), copies[i]); + } // Set table for the current target + target.setValue("renderCopies", copiesData); data.setValue(id, target); } } @@ -618,6 +623,22 @@ namespace { pair->browser()->removeRenderCopy(); } } +/** +* Takes an identifier to a sky browser and the index to a render copy, and sets its RAE +* position. +* \param id Identifier +* \param i Index to the render copy +* \param raePosition Position in [Radius, Azimuth, Elevation] to move the render copy to +*/ +[[codegen::luawrap]] void moveRenderCopy(std::string id, int i, glm::vec3 raePosition) { + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + TargetBrowserPair* pair = module->getPair(id); + if (pair) { + pair->browser()->moveRenderCopy(i, raePosition); + } +} #include "skybrowsermodule_lua_codegen.cpp" } // namespace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index ad3d8e4996..f593a7c890 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -199,8 +199,28 @@ void ScreenSpaceSkyBrowser::addRenderCopy(const glm::vec3& raePosition, int nCop } void ScreenSpaceSkyBrowser::removeRenderCopy() { - removeProperty(_renderCopies.back().get()); - _renderCopies.pop_back(); + if (_renderCopies.size() > 0) { + removeProperty(_renderCopies.back().get()); + _renderCopies.pop_back(); + } +} + +std::vector ScreenSpaceSkyBrowser::renderCopies() +{ + std::vector vec; + std::for_each( + _renderCopies.begin(), + _renderCopies.end(), + [&](const std::unique_ptr& copy) { + vec.push_back(glm::dvec3(copy.get()->value())); + }); + return vec; +} + +void ScreenSpaceSkyBrowser::moveRenderCopy(int i, glm::vec3 raePosition) { + if (i < _renderCopies.size() && i >= 0) { + _renderCopies[i].get()->set(raePosition); + } } bool ScreenSpaceSkyBrowser::deinitializeGL() { diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 6825f7daf0..786ef7c6d4 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -259,6 +259,11 @@ void TargetBrowserPair::updateBrowserSize() { _browser->updateBrowserSize(); } +std::vector TargetBrowserPair::renderCopies() +{ + return _browser->renderCopies(); +} + void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) { _browser->setIsSyncedWithWwt(isSynced); } From 1eb4fc58793e07e96009d7a8e5083eb29bcd8261 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Mon, 4 Apr 2022 10:16:51 -0400 Subject: [PATCH 248/251] Change lua function to be set with "setPropertyValueSingle" instead --- .../include/screenspaceskybrowser.h | 2 +- .../skybrowser/include/targetbrowserpair.h | 2 +- modules/skybrowser/skybrowsermodule.cpp | 1 - modules/skybrowser/skybrowsermodule_lua.inl | 19 ++----------------- .../skybrowser/src/screenspaceskybrowser.cpp | 12 ++++++++---- modules/skybrowser/src/targetbrowserpair.cpp | 2 +- 6 files changed, 13 insertions(+), 25 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index 9f612d6a07..a91d970492 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -63,7 +63,7 @@ public: // Copies rendered void addRenderCopy(const glm::vec3& raePosition, int nCopies); void removeRenderCopy(); - std::vector renderCopies(); + std::vector> renderCopies(); void moveRenderCopy(int i, glm::vec3 raePosition); private: diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index cc22254764..77be4f6491 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -64,7 +64,7 @@ public: // Browser void sendIdToBrowser(); void updateBrowserSize(); - std::vector renderCopies(); + std::vector> renderCopies(); // Target void centerTargetOnScreen(); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index a5dbbf83d9..a287073bc2 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -565,7 +565,6 @@ scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { codegen::lua::AddRenderCopy, codegen::lua::SetScreenSpaceSize, codegen::lua::RemoveRenderCopy, - codegen::lua::MoveRenderCopy } }; } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 32776f098c..883c18f78b 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -325,10 +325,10 @@ namespace { target.setValue("dec", spherical.y); target.setValue("color", pair->borderColor()); target.setValue("size", glm::dvec2(pair->size())); - std::vector copies = pair->renderCopies(); + std::vector> copies = pair->renderCopies(); ghoul::Dictionary copiesData; for (int i = 0; i < copies.size(); i++) { - copiesData.setValue("Copy" + std::to_string(i), copies[i]); + copiesData.setValue(copies[i].first, copies[i].second); } // Set table for the current target target.setValue("renderCopies", copiesData); @@ -623,22 +623,7 @@ namespace { pair->browser()->removeRenderCopy(); } } -/** -* Takes an identifier to a sky browser and the index to a render copy, and sets its RAE -* position. -* \param id Identifier -* \param i Index to the render copy -* \param raePosition Position in [Radius, Azimuth, Elevation] to move the render copy to -*/ -[[codegen::luawrap]] void moveRenderCopy(std::string id, int i, glm::vec3 raePosition) { - // Get module - SkyBrowserModule* module = global::moduleEngine->module(); - TargetBrowserPair* pair = module->getPair(id); - if (pair) { - pair->browser()->moveRenderCopy(i, raePosition); - } -} #include "skybrowsermodule_lua_codegen.cpp" } // namespace diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index f593a7c890..f7d5bf9ac0 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -184,7 +184,7 @@ void ScreenSpaceSkyBrowser::addRenderCopy(const glm::vec3& raePosition, int nCop openspace::properties::Property::PropertyInfo info = RenderCopyInfo; float azimuth = i * glm::two_pi() / nCopies; glm::vec3 position = raePosition + glm::vec3(0.f, azimuth, 0.f); - std::string id = "Rendercopy" + std::to_string(start + i); + std::string id = "RenderCopy" + std::to_string(start + i); info.identifier = id.c_str(); _renderCopies.push_back( std::make_unique( @@ -205,14 +205,18 @@ void ScreenSpaceSkyBrowser::removeRenderCopy() { } } -std::vector ScreenSpaceSkyBrowser::renderCopies() +std::vector> ScreenSpaceSkyBrowser::renderCopies() { - std::vector vec; + std::vector> vec; std::for_each( _renderCopies.begin(), _renderCopies.end(), [&](const std::unique_ptr& copy) { - vec.push_back(glm::dvec3(copy.get()->value())); + std::pair pair = { + copy.get()->identifier(), + glm::dvec3(copy.get()->value()) + }; + vec.push_back(pair); }); return vec; } diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 786ef7c6d4..6568140717 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -259,7 +259,7 @@ void TargetBrowserPair::updateBrowserSize() { _browser->updateBrowserSize(); } -std::vector TargetBrowserPair::renderCopies() +std::vector> TargetBrowserPair::renderCopies() { return _browser->renderCopies(); } From 68b19ba703966056b1a69a8c87d4823d2422062b Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Tue, 5 Apr 2022 15:56:08 -0400 Subject: [PATCH 249/251] Remove non ascii characters before printing info message. Fix issue #1917 --- modules/skybrowser/skybrowsermodule_lua.inl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 883c18f78b..eda769481d 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -54,7 +54,13 @@ namespace { if (selected) { const ImageData& image = module->getWwtDataHandler()->getImage(i); // Load image into browser - LINFO("Loading image " + image.name); + std::string str = image.name; + str.erase(std::remove_if(str.begin(), str.end(), [](char c) { + // Check if character is ASCII - if it isn't, remove + return !(c >= 0 && c < 128); + }), + str.end()); + LINFO("Loading image " + str); selected->selectImage(image, i); bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); From 1f8b31bab3912177c71281cc636719bdbd11eafb Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 7 Apr 2022 16:28:17 -0400 Subject: [PATCH 250/251] Update so that WWT is loaded in the gui --- .../skybrowser/include/targetbrowserpair.h | 8 ++- modules/skybrowser/skybrowsermodule.cpp | 8 ++- modules/skybrowser/skybrowsermodule_lua.inl | 57 +++++++++++++++++++ modules/skybrowser/src/targetbrowserpair.cpp | 45 ++++++++------- 4 files changed, 94 insertions(+), 24 deletions(-) diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 77be4f6491..306779f5c0 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -56,8 +56,8 @@ public: // Mouse interaction bool checkMouseIntersection(const glm::vec2& mousePosition); glm::vec2 selectedScreenSpacePosition() const; - void fineTuneTarget(const glm::dvec3& startWorld, const glm::vec2& startMouse, - const glm::vec2& translation); + void startFinetuningTarget(); + void fineTuneTarget(const glm::vec2& startMouse, const glm::vec2& translation); void translateSelected(const glm::vec2& start, const glm::vec2& translation); void synchronizeAim(); @@ -68,6 +68,7 @@ public: // Target void centerTargetOnScreen(); + double targetRoll(); bool hasFinishedFading() const; bool isFacingCamera() const; @@ -129,6 +130,9 @@ private: skybrowser::Animation _moveTarget = skybrowser::Animation(glm::dvec3(0.0), glm::dvec3(0.0), 0.0); bool _targetIsAnimating = false; + + // Dragging + glm::dvec3 _startTargetPosition = glm::dvec3(0.0); glm::dvec2 _equatorialAim = glm::dvec2(0.0); glm::ivec3 _borderColor = glm::ivec3(255); diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index a287073bc2..4998b87102 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -108,7 +108,7 @@ SkyBrowserModule::SkyBrowserModule() addProperty(_browserAnimationSpeed); // Set callback functions - global::callback::mouseButton->emplace_back( + global::callback::mouseButton->emplace(global::callback::mouseButton->begin(), [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { if (!_isCameraInSolarSystem || !_allowMouseInteraction) { return false; @@ -135,7 +135,7 @@ SkyBrowserModule::SkyBrowserModule() ); if (global::windowDelegate->isMaster()) { - global::callback::mousePosition->emplace_back( + global::callback::mousePosition->emplace(global::callback::mousePosition->begin(), [&](double x, double y) { if (!_isCameraInSolarSystem || !_allowMouseInteraction) { return false; @@ -154,7 +154,6 @@ SkyBrowserModule::SkyBrowserModule() break; case MouseInteraction::FineTune: _mouseOnPair->fineTuneTarget( - _startTargetPosition, _startDragPosition, translation ); @@ -565,6 +564,9 @@ scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { codegen::lua::AddRenderCopy, codegen::lua::SetScreenSpaceSize, codegen::lua::RemoveRenderCopy, + codegen::lua::StartFinetuningTarget, + codegen::lua::FinetuneTargetPosition, + codegen::lua::ScrollOverBrowser } }; } diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index eda769481d..c9eb2bf1f2 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -34,6 +34,8 @@ #include #include #include +#include + namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; @@ -250,6 +252,7 @@ namespace { ghoul::Dictionary image; image.setValue("name", img.name); image.setValue("thumbnail", img.thumbnailUrl); + image.setValue("url", img.imageUrl); image.setValue("ra", img.equatorialSpherical.x); image.setValue("dec", img.equatorialSpherical.y); image.setValue("fov", static_cast(img.fov)); @@ -329,6 +332,7 @@ namespace { target.setValue("cartesianDirection", cartesian); target.setValue("ra", spherical.x); target.setValue("dec", spherical.y); + target.setValue("roll", pair->targetRoll()); target.setValue("color", pair->borderColor()); target.setValue("size", glm::dvec2(pair->size())); std::vector> copies = pair->renderCopies(); @@ -565,6 +569,22 @@ namespace { pair->setVerticalFov(vfov); } } + +/** +* Takes an identifier to a sky browser or a sky target and a vertical +* field of view. Changes the field of view as specified by the input. +* \param id Identifier +* \param vfov Vertical Field of View +*/ +[[codegen::luawrap]] void scrollOverBrowser(std::string id, float scroll) { + // Get module + SkyBrowserModule* module = global::moduleEngine->module(); + + TargetBrowserPair* pair = module->getPair(id); + if (pair) { + pair->setVerticalFovWithScroll(scroll); + } +} /** * Takes an identifier to a sky browser or a sky target and a rgb color * in the ranges [0, 255]. @@ -630,6 +650,43 @@ namespace { } } +/** +* Starts the finetuning of the target +* rendered copy to it. +* \param id Identifier to browser +*/ +[[codegen::luawrap]] void startFinetuningTarget(std::string id) { + // Get module + + SkyBrowserModule* module = global::moduleEngine->module(); + TargetBrowserPair* pair = module->getPair(id); + if (pair) { + pair->startFinetuningTarget(); + } +} + +/** +* Finetunes the target depending on a mouse drag. +* rendered copy to it. +* \param id Identifier to browser +* \param start Start pixel position of drag +* \param end Current pixel position of mouse during drag +*/ +[[codegen::luawrap]] void finetuneTargetPosition(std::string id, glm::vec2 start, + glm::vec2 end) { + // Get module + + SkyBrowserModule* module = global::moduleEngine->module(); + TargetBrowserPair* pair = module->getPair(id); + if (pair) { + glm::vec2 startScreenSpace = skybrowser::pixelToScreenSpace2d(start); + glm::vec2 endScreenSpace = skybrowser::pixelToScreenSpace2d(end); + glm::vec2 translation = endScreenSpace - startScreenSpace; + LINFO(glm::to_string(translation)); + pair->fineTuneTarget(startScreenSpace, translation); + } +} + #include "skybrowsermodule_lua_codegen.cpp" } // namespace diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 6568140717..72d8a33f9a 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -95,11 +95,14 @@ glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() const { return _selected->screenSpacePosition(); } +void TargetBrowserPair::startFinetuningTarget() { + _startTargetPosition = _targetNode->worldPosition(); +} + // The fine tune of the target is a way to "drag and drop" the target with right click // drag on the sky browser window. This is to be able to drag the target around when it // has a very small field of view -void TargetBrowserPair::fineTuneTarget(const glm::dvec3& startWorldPosition, - const glm::vec2& startMouse, +void TargetBrowserPair::fineTuneTarget(const glm::vec2& startMouse, const glm::vec2& translation) { glm::vec2 fineTune = _browser->fineTuneVector(translation); @@ -114,7 +117,7 @@ void TargetBrowserPair::fineTuneTarget(const glm::dvec3& startWorldPosition, ); glm::dvec3 translationWorld = endWorld - startWorld; - aimTargetGalactic(startWorldPosition + translationWorld); + aimTargetGalactic(_startTargetPosition + translationWorld); } void TargetBrowserPair::translateSelected(const glm::vec2& start, @@ -133,22 +136,8 @@ void TargetBrowserPair::translateSelected(const glm::vec2& start, void TargetBrowserPair::synchronizeAim() { if (!_moveTarget.isAnimating()) { - // To remove the lag effect when moving the camera while having a locked - // target, send the locked coordinates to wwt - glm::dvec2 aim = targetDirectionEquatorial(); - _browser->setEquatorialAim(aim); - glm::dvec3 normal = glm::normalize( - _targetNode->worldPosition() - - global::navigationHandler->camera()->positionVec3() - ); - glm::dvec3 right = glm::normalize( - glm::cross( - global::navigationHandler->camera()->lookUpVectorWorldSpace(), - normal - ) - ); - glm::dvec3 up = glm::normalize(glm::cross(normal, right)); - _browser->setTargetRoll(skybrowser::targetRoll(up, normal)); + _browser->setEquatorialAim(targetDirectionEquatorial()); + _browser->setTargetRoll(targetRoll()); _targetRenderable->setVerticalFov(_browser->verticalFov()); } } @@ -346,6 +335,24 @@ void TargetBrowserPair::centerTargetOnScreen() { startAnimation(viewDirection, currentFov); } +double TargetBrowserPair::targetRoll() +{ + // To remove the lag effect when moving the camera while having a locked + // target, send the locked coordinates to wwt + glm::dvec3 normal = glm::normalize( + _targetNode->worldPosition() - + global::navigationHandler->camera()->positionVec3() + ); + glm::dvec3 right = glm::normalize( + glm::cross( + global::navigationHandler->camera()->lookUpVectorWorldSpace(), + normal + ) + ); + glm::dvec3 up = glm::normalize(glm::cross(normal, right)); + return skybrowser::targetRoll(up, normal); +} + bool TargetBrowserPair::hasFinishedFading() const { return !_fadeBrowser.isAnimating() && !_fadeTarget.isAnimating(); } From 9e86447b8589e9857892d03b5b0d4e7696174d93 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 8 Apr 2022 11:43:32 -0400 Subject: [PATCH 251/251] Remove mouse interaction for skybrowser and make default position of the skybrowser to be outside of the normal field of view --- .../include/screenspaceskybrowser.h | 2 +- .../skybrowser/include/targetbrowserpair.h | 6 - modules/skybrowser/skybrowsermodule.cpp | 127 ------------------ modules/skybrowser/skybrowsermodule.h | 1 - modules/skybrowser/skybrowsermodule_lua.inl | 5 +- .../skybrowser/src/screenspaceskybrowser.cpp | 2 +- modules/skybrowser/src/targetbrowserpair.cpp | 28 ---- 7 files changed, 3 insertions(+), 168 deletions(-) diff --git a/modules/skybrowser/include/screenspaceskybrowser.h b/modules/skybrowser/include/screenspaceskybrowser.h index a91d970492..a63a04ce3f 100644 --- a/modules/skybrowser/include/screenspaceskybrowser.h +++ b/modules/skybrowser/include/screenspaceskybrowser.h @@ -78,7 +78,7 @@ private: bool _textureDimensionsIsDirty = false; bool _sizeIsDirty = false; - glm::vec2 _size = glm::vec2(1.f, 0.8f); + glm::vec2 _size = glm::vec2(1.f, 1.f); }; } // namespace openspace diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index 306779f5c0..b0f467f7f5 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -54,11 +54,8 @@ public: void startFading(float goal, float fadeTime); void incrementallyFade(); // Mouse interaction - bool checkMouseIntersection(const glm::vec2& mousePosition); - glm::vec2 selectedScreenSpacePosition() const; void startFinetuningTarget(); void fineTuneTarget(const glm::vec2& startMouse, const glm::vec2& translation); - void translateSelected(const glm::vec2& start, const glm::vec2& translation); void synchronizeAim(); // Browser @@ -115,9 +112,6 @@ public: private: void aimTargetGalactic(glm::dvec3 direction); - // Selection - ScreenSpaceSkyBrowser* _selected = nullptr; - // Target and browser RenderableSkyTarget* _targetRenderable = nullptr; ScreenSpaceSkyBrowser* _browser = nullptr; diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 4998b87102..225856ea9a 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -39,13 +39,6 @@ #include "skybrowsermodule_lua.inl" namespace { - constexpr const openspace::properties::Property::PropertyInfo AllowInteractionInfo = { - "AllowMouseInteraction", - "Allow Mouse Interaction", - "Toggles if it is possible to interact with the sky browser and sky targets with " - "the mouse or not." - }; - constexpr const openspace::properties::Property::PropertyInfo AllowRotationInfo = { "AllowCameraRotation", "Allow Camera Rotation", @@ -73,8 +66,6 @@ namespace { }; struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters { - // [[codegen::verbatim(AllowInteractionInfo.description)]] - std::optional allowMouseInteraction; // [[codegen::verbatim(AllowRotationInfo.description)]] std::optional allowCameraRotation; @@ -95,13 +86,11 @@ namespace { namespace openspace { SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) - , _allowMouseInteraction(AllowInteractionInfo, true) , _allowCameraRotation(AllowRotationInfo, true) , _cameraRotationSpeed(CameraRotSpeedInfo, 0.5, 0.0, 1.0) , _targetAnimationSpeed(TargetSpeedInfo, 0.2, 0.0, 1.0) , _browserAnimationSpeed(BrowserSpeedInfo, 5.0, 0.0, 10.0) { - addProperty(_allowMouseInteraction); addProperty(_allowCameraRotation); addProperty(_cameraRotationSpeed); addProperty(_targetAnimationSpeed); @@ -110,76 +99,16 @@ SkyBrowserModule::SkyBrowserModule() // Set callback functions global::callback::mouseButton->emplace(global::callback::mouseButton->begin(), [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { - if (!_isCameraInSolarSystem || !_allowMouseInteraction) { - return false; - } - if (action == MouseAction::Press) { _cameraRotation.stop(); - if (_mouseOnPair) { - handleMouseClick(button); - return true; - } return false; } - else if (_interactionMode != MouseInteraction::Hover && - action == MouseAction::Release) { - - _interactionMode = MouseInteraction::Hover; - return true; - } else { return false; } } ); - if (global::windowDelegate->isMaster()) { - global::callback::mousePosition->emplace(global::callback::mousePosition->begin(), - [&](double x, double y) { - if (!_isCameraInSolarSystem || !_allowMouseInteraction) { - return false; - } - - glm::vec2 pixel{ static_cast(x), static_cast(y) }; - _mousePosition = skybrowser::pixelToScreenSpace2d(pixel); - glm::vec2 translation = _mousePosition - _startMousePosition; - - switch (_interactionMode) { - case MouseInteraction::Hover: - setSelectedObject(); - break; - case MouseInteraction::Drag: - _mouseOnPair->translateSelected(_startDragPosition, translation); - break; - case MouseInteraction::FineTune: - _mouseOnPair->fineTuneTarget( - _startDragPosition, - translation - ); - break; - default: - setSelectedObject(); - break; - } - return false; - } - ); - - global::callback::mouseScrollWheel->emplace_back( - [&](double, double scroll) -> bool { - if (!_isCameraInSolarSystem || !_mouseOnPair || !_allowMouseInteraction) { - return false; - } - // If mouse is on browser or target, apply zoom - _mouseOnPair->setVerticalFovWithScroll( - static_cast(scroll) - ); - return true; - } - ); - } - global::callback::preSync->emplace_back([this]() { // Disable browser and targets when camera is outside of solar system bool camWasInSolarSystem = _isCameraInSolarSystem; @@ -256,42 +185,6 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { _dataHandler = std::make_unique(); } -void SkyBrowserModule::setSelectedObject() { - if (_interactionMode != MouseInteraction::Hover) { - return; - } - // Save old selection for removing highlight - TargetBrowserPair* previousPair = _mouseOnPair; - - // Find and save what mouse is currently hovering on - auto it = std::find_if( - _targetsBrowsers.begin(), - _targetsBrowsers.end(), - [&] (const std::unique_ptr &pair) { - return pair->checkMouseIntersection(_mousePosition) && - !pair->isUsingRadiusAzimuthElevation(); - }); - - if (it == _targetsBrowsers.end()) { - _mouseOnPair = nullptr; - } - else { - _mouseOnPair = it->get(); - } - - // Selection has changed - if (previousPair != _mouseOnPair) { - // Remove highlight - if (previousPair) { - previousPair->removeHighlight(_highlightAddition); - } - // Add highlight to new selection - if (_mouseOnPair) { - _mouseOnPair->highlight(_highlightAddition); - } - } -} - void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const std::string& browserId) { if (!global::renderEngine->scene()) { return; @@ -377,26 +270,6 @@ int SkyBrowserModule::nLoadedImages() { return _dataHandler->nLoadedImages(); } -void SkyBrowserModule::handleMouseClick(const MouseButton& button) { - setSelectedBrowser(_mouseOnPair->browserId()); - - if (button == MouseButton::Left) { - _startMousePosition = _mousePosition; - _startDragPosition = _mouseOnPair->selectedScreenSpacePosition(); - - // If it's not resize mode, it's drag mode - _interactionMode = MouseInteraction::Drag; - } - // Fine tuning mode of target - else if (button == MouseButton::Right) { - // Change view (by moving target) within browser if right mouse - // click on browser - _startMousePosition = _mousePosition; - _startTargetPosition = _mouseOnPair->targetNode()->worldPosition(); - _interactionMode = MouseInteraction::FineTune; - } -} - const std::unique_ptr& SkyBrowserModule::getWwtDataHandler() const { return _dataHandler; } diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index bbc629046a..486b73c9be 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -108,7 +108,6 @@ protected: void internalInitialize(const ghoul::Dictionary& dict) override; private: - properties::BoolProperty _allowMouseInteraction; properties::BoolProperty _allowCameraRotation; properties::DoubleProperty _cameraRotationSpeed; properties::DoubleProperty _targetAnimationSpeed; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index c9eb2bf1f2..03d08c7e2e 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -34,8 +34,6 @@ #include #include #include -#include - namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; @@ -407,7 +405,7 @@ namespace { std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs); std::string idTarget = "SkyTarget" + std::to_string(noOfPairs); // Determine starting point on screen for the target - glm::vec3 positionBrowser = { -1.f, -0.5f, -2.1f }; + glm::vec3 positionBrowser = { -3.f, -3.f, -2.1f }; glm::vec3 positionTarget = { 0.9f, 0.4f, -2.1f }; glm::dvec3 galacticTarget = skybrowser::localCameraToGalactic(positionTarget); std::string guiPath = "/Sky Browser"; @@ -682,7 +680,6 @@ namespace { glm::vec2 startScreenSpace = skybrowser::pixelToScreenSpace2d(start); glm::vec2 endScreenSpace = skybrowser::pixelToScreenSpace2d(end); glm::vec2 translation = endScreenSpace - startScreenSpace; - LINFO(glm::to_string(translation)); pair->fineTuneTarget(startScreenSpace, translation); } } diff --git a/modules/skybrowser/src/screenspaceskybrowser.cpp b/modules/skybrowser/src/screenspaceskybrowser.cpp index f7d5bf9ac0..488d2cf8a3 100644 --- a/modules/skybrowser/src/screenspaceskybrowser.cpp +++ b/modules/skybrowser/src/screenspaceskybrowser.cpp @@ -97,7 +97,7 @@ namespace openspace { ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) , WwtCommunicator(dictionary) - , _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f) + , _textureQuality(TextureQualityInfo, 0.5f, 0.25f, 1.f) , _renderOnlyOnMaster(RenderOnMasterInfo, false) { _identifier = makeUniqueIdentifier(_identifier); diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index 72d8a33f9a..f0589918a1 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -85,16 +85,6 @@ void TargetBrowserPair::aimTargetGalactic(glm::dvec3 direction) { ); } -bool TargetBrowserPair::checkMouseIntersection(const glm::vec2& mousePosition) { - _selected = _browser->isIntersecting(mousePosition) ? _browser : nullptr; - - return _selected; -} - -glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() const { - return _selected->screenSpacePosition(); -} - void TargetBrowserPair::startFinetuningTarget() { _startTargetPosition = _targetNode->worldPosition(); } @@ -120,20 +110,6 @@ void TargetBrowserPair::fineTuneTarget(const glm::vec2& startMouse, aimTargetGalactic(_startTargetPosition + translationWorld); } -void TargetBrowserPair::translateSelected(const glm::vec2& start, - const glm::vec2& trans) -{ - if (this && _selected) { - std::string id = _selected->identifier(); - openspace::global::scriptEngine->queueScript( - "openspace.skybrowser.translateScreenSpaceRenderable(\"" + id + "\"," - + std::to_string(start.x) + "," + std::to_string(start.y) + "," - + std::to_string(trans.x) + "," + std::to_string(trans.y) + ")", - scripting::ScriptEngine::RemoteScripting::Yes - ); - } -} - void TargetBrowserPair::synchronizeAim() { if (!_moveTarget.isAnimating()) { _browser->setEquatorialAim(targetDirectionEquatorial()); @@ -194,10 +170,6 @@ std::string TargetBrowserPair::targetNodeId() const { return _targetNode->identifier(); } -std::string TargetBrowserPair::selectedId() { - return _selected->identifier(); -} - glm::vec2 TargetBrowserPair::size() const { return _browser->size(); }