From 6c98adec310b0fd8bb94e96c4e88f678dd68e35c Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 26 Jun 2019 16:49:41 -0600 Subject: [PATCH 01/32] Updated sample interval in assets using HorizonsTranslation --- data/assets/scene/solarsystem/interstellar/oumuamua.asset | 3 ++- data/assets/scene/solarsystem/sssb/tesla_roadster.asset | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/data/assets/scene/solarsystem/interstellar/oumuamua.asset b/data/assets/scene/solarsystem/interstellar/oumuamua.asset index 33758e6224..2b972b5c3a 100644 --- a/data/assets/scene/solarsystem/interstellar/oumuamua.asset +++ b/data/assets/scene/solarsystem/interstellar/oumuamua.asset @@ -20,7 +20,8 @@ local OumuamuaTrail = { Color = { 0.9, 0.9, 0.0 }, StartTime = "2014 JAN 01 00:00:00", EndTime = "2023 JAN 01 00:00:00", - SampleInterval = 60 + SampleInterval = 7000, + TimeStampSubsampleFactor = 1 }, GUI = { Name = "'Oumuamua Trail", diff --git a/data/assets/scene/solarsystem/sssb/tesla_roadster.asset b/data/assets/scene/solarsystem/sssb/tesla_roadster.asset index 5fd6308fdc..ca2a577dff 100644 --- a/data/assets/scene/solarsystem/sssb/tesla_roadster.asset +++ b/data/assets/scene/solarsystem/sssb/tesla_roadster.asset @@ -20,7 +20,8 @@ local TeslaRoadsterTrail = { Color = { 0.9, 0.9, 0.0 }, StartTime = "2018 FEB 8 00:00:00", EndTime = "2022 FEB 7 00:00:00", - SampleInterval = 60 + SampleInterval = 3000, + TimeStampSubsampleFactor = 1 }, GUI = { Name = "Tesla Roadster Trail", From e9fdd31c56a41ddffb35463e629d26f8bb7ce9b4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 4 Jul 2019 09:28:42 +0200 Subject: [PATCH 02/32] Feature/flying fixes (#924) * Removing various warnings * Fix the rendering of the touchbar on Mac * More warnings * Add ghoul deinitialize * Update SGCT repository --- apps/OpenSpace/ext/sgct | 2 +- apps/OpenSpace/main.cpp | 88 +++++++-------- .../openspace/interaction/sessionrecording.h | 1 - .../rendering/atmospheredeferredcaster.cpp | 8 +- .../base/dashboard/dashboarditemframerate.cpp | 2 +- .../rendering/renderablebillboardscloud.cpp | 1 - .../rendering/renderabledumeshes.cpp | 17 +-- .../rendering/renderableplanescloud.cpp | 2 +- .../src/globelabelscomponent.cpp | 18 +-- .../globebrowsing/src/globetranslation.cpp | 6 +- modules/globebrowsing/src/tileprovider.cpp | 4 +- modules/server/src/topics/timetopic.cpp | 1 - modules/space/rendering/renderablestars.cpp | 2 - modules/space/rendering/renderablestars.h | 1 - .../volume/tasks/generaterawvolumetask.cpp | 3 - modules/volume/transferfunctionhandler.cpp | 6 - src/interaction/touchbar.mm | 103 +++++++----------- src/performance/performancemanager.cpp | 3 +- src/rendering/renderengine.cpp | 2 +- src/util/timemanager.cpp | 8 +- 20 files changed, 110 insertions(+), 168 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 99e5595539..8f2ed18481 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 99e5595539225ee0067b17b370f09a2d8aae3dd0 +Subproject commit 8f2ed184813a04d635c3ecfcf2efc6174594da23 diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index ff713b447a..e77ce29331 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -76,6 +76,8 @@ constexpr const bool EnableDetailedVtune = false; #include "nvToolsExt.h" #endif // OPENSPACE_HAS_NVTOOLS +using namespace openspace; + namespace { constexpr const char* _loggerCat = "main"; @@ -157,9 +159,9 @@ LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) { std::string dumpFile = fmt::format( "OpenSpace_{}_{}_{}-{}-{}-{}-{}-{}-{}--{}--{}.dmp", - openspace::OPENSPACE_VERSION_MAJOR, - openspace::OPENSPACE_VERSION_MINOR, - openspace::OPENSPACE_VERSION_PATCH, + OPENSPACE_VERSION_MAJOR, + OPENSPACE_VERSION_MINOR, + OPENSPACE_VERSION_PATCH, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, @@ -260,7 +262,7 @@ void mainInitFunc() { LTRACE("main::mainInitFunc(begin)"); LDEBUG("Initializing OpenSpace Engine started"); - openspace::global::openSpaceEngine.initialize(); + global::openSpaceEngine.initialize(); LDEBUG("Initializing OpenSpace Engine finished"); { @@ -287,7 +289,7 @@ void mainInitFunc() { LDEBUG("Initializing OpenGL in OpenSpace Engine started"); - openspace::global::openSpaceEngine.initializeGL(); + global::openSpaceEngine.initializeGL(); LDEBUG("Initializing OpenGL in OpenSpace Engine finished"); @@ -366,7 +368,7 @@ void mainInitFunc() { // std::string screenshotPath = "${SCREENSHOTS}"; - if (openspace::global::configuration.shouldUseScreenshotDate) { + if (global::configuration.shouldUseScreenshotDate) { std::time_t now = std::time(nullptr); std::tm* nowTime = std::localtime(&now); char mbstr[128]; @@ -412,13 +414,13 @@ void mainPreSyncFunc() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainPreSyncFunc(begin)"); - openspace::global::openSpaceEngine.preSynchronization(); + global::openSpaceEngine.preSynchronization(); // Query joystick status - using namespace openspace::interaction; + using namespace interaction; for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) { - JoystickInputState& state = openspace::global::joystickInputStates[i]; + JoystickInputState& state = global::joystickInputStates[i]; int present = glfwJoystickPresent(i); if (present == GLFW_FALSE) { @@ -511,7 +513,7 @@ void mainPostSyncPreDrawFunc() { #endif // OPENSPACE_HAS_NVTOOLS LTRACE("main::postSynchronizationPreDraw(begin)"); - openspace::global::openSpaceEngine.postSynchronizationPreDraw(); + global::openSpaceEngine.postSynchronizationPreDraw(); #ifdef OPENVR_SUPPORT if (FirstOpenVRWindow) { @@ -559,7 +561,7 @@ void mainRenderFunc() { #endif try { - openspace::global::openSpaceEngine.render( + global::openSpaceEngine.render( SgctEngine->getModelMatrix(), viewMatrix, projectionMatrix @@ -591,7 +593,7 @@ void mainDraw2DFunc() { LTRACE("main::mainDraw2DFunc(begin)"); try { - openspace::global::openSpaceEngine.drawOverlays(); + global::openSpaceEngine.drawOverlays(); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); @@ -627,7 +629,7 @@ void mainPostDrawFunc() { } #endif // OPENVR_SUPPORT - openspace::global::openSpaceEngine.postDraw(); + global::openSpaceEngine.postDraw(); #ifdef OPENSPACE_HAS_SPOUT for (const SpoutWindow& w : SpoutWindows) { @@ -667,7 +669,7 @@ void mainPostDrawFunc() { -void mainKeyboardCallback(int key, int, int action, int mods) { +void mainKeyboardCallback(int key, int, int action, int modifiers) { #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { __itt_frame_begin_v3(_vTune.keyboard, nullptr); @@ -675,11 +677,10 @@ void mainKeyboardCallback(int key, int, int action, int mods) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainKeyboardCallback(begin)"); - openspace::global::openSpaceEngine.keyboardCallback( - openspace::Key(key), - openspace::KeyModifier(mods), - openspace::KeyAction(action) - ); + const Key k = Key(key); + const KeyModifier m = KeyModifier(modifiers); + const KeyAction a = KeyAction(action); + global::openSpaceEngine.keyboardCallback(k, m, a); LTRACE("main::mainKeyboardCallback(begin)"); #ifdef OPENSPACE_HAS_VTUNE @@ -699,11 +700,10 @@ void mainMouseButtonCallback(int key, int action, int modifiers) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainMouseButtonCallback(begin)"); - openspace::global::openSpaceEngine.mouseButtonCallback( - openspace::MouseButton(key), - openspace::MouseAction(action), - openspace::KeyModifier(modifiers) - ); + const MouseButton k = MouseButton(key); + const MouseAction a = MouseAction(action); + const KeyModifier m = KeyModifier(modifiers); + global::openSpaceEngine.mouseButtonCallback(k, a, m); LTRACE("main::mainMouseButtonCallback(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -722,7 +722,7 @@ void mainMousePosCallback(double x, double y) { } #endif // OPENSPACE_HAS_VTUNE - openspace::global::openSpaceEngine.mousePositionCallback(x, y); + global::openSpaceEngine.mousePositionCallback(x, y); #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { @@ -741,7 +741,7 @@ void mainMouseScrollCallback(double posX, double posY) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainMouseScrollCallback(begin"); - openspace::global::openSpaceEngine.mouseScrollWheelCallback(posX, posY); + global::openSpaceEngine.mouseScrollWheelCallback(posX, posY); LTRACE("main::mainMouseScrollCallback(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -753,17 +753,15 @@ void mainMouseScrollCallback(double posX, double posY) { -void mainCharCallback(unsigned int codepoint, int mods) { +void mainCharCallback(unsigned int codepoint, int modifiers) { #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { __itt_frame_begin_v3(_vTune.character, nullptr); } #endif // OPENSPACE_HAS_VTUNE - openspace::global::openSpaceEngine.charCallback( - codepoint, - openspace::KeyModifier(mods) - ); + const KeyModifier m = KeyModifier(modifiers); + global::openSpaceEngine.charCallback(codepoint, m); #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { @@ -782,7 +780,7 @@ void mainEncodeFun() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainEncodeFun(begin)"); - std::vector data = openspace::global::openSpaceEngine.encode(); + std::vector data = global::openSpaceEngine.encode(); _synchronizationBuffer.setVal(std::move(data)); sgct::SharedData::instance()->writeVector(&_synchronizationBuffer); @@ -806,7 +804,7 @@ void mainDecodeFun() { sgct::SharedData::instance()->readVector(&_synchronizationBuffer); std::vector data = _synchronizationBuffer.getVal(); - openspace::global::openSpaceEngine.decode(std::move(data)); + global::openSpaceEngine.decode(std::move(data)); LTRACE("main::mainDecodeFun(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -833,7 +831,7 @@ void mainLogCallback(const char* msg) { void setSgctDelegateFunctions() { - openspace::WindowDelegate& sgctDelegate = openspace::global::windowDelegate; + WindowDelegate& sgctDelegate = global::windowDelegate; sgctDelegate.terminate = []() { sgct::Engine::instance()->terminate(); }; sgctDelegate.setBarrier = [](bool enabled) { sgct::SGCTWindow::setBarrier(enabled); @@ -1101,7 +1099,7 @@ int main(int argc, char** argv) { ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes ); - openspace::CommandlineArguments commandlineArguments; + CommandlineArguments commandlineArguments; parser.addCommand(std::make_unique>( commandlineArguments.configurationName, "--file", "-f", "Provides the path to the OpenSpace configuration file. Only the '${TEMPORARY}' " @@ -1141,8 +1139,6 @@ int main(int argc, char** argv) { // Create the OpenSpace engine and get arguments for the SGCT engine std::string windowConfiguration; try { - using namespace openspace; - // Find configuration std::string configurationFilePath = commandlineArguments.configurationName; if (commandlineArguments.configurationName.empty()) { @@ -1178,16 +1174,17 @@ int main(int argc, char** argv) { // Determining SGCT configuration file LDEBUG("SGCT Configuration file: " + global::configuration.windowConfiguration); - windowConfiguration = openspace::global::configuration.windowConfiguration; + windowConfiguration = global::configuration.windowConfiguration; } - catch (const openspace::documentation::SpecificationError& e) { + catch (const documentation::SpecificationError& e) { LFATALC("main", "Loading of configuration file failed"); - for (const openspace::documentation::TestResult::Offense& o : e.result.offenses) { + for (const documentation::TestResult::Offense& o : e.result.offenses) { LERRORC(o.offender, ghoul::to_string(o.reason)); } - for (const openspace::documentation::TestResult::Warning& w : e.result.warnings) { + for (const documentation::TestResult::Warning& w : e.result.warnings) { LWARNINGC(w.offender, ghoul::to_string(w.reason)); } + ghoul::deinitialize(); exit(EXIT_FAILURE); } catch (const ghoul::RuntimeError& e) { @@ -1196,10 +1193,11 @@ int main(int argc, char** argv) { if (ghoul::logging::LogManager::isInitialized()) { LogMgr.flushLogs(); } + ghoul::deinitialize(); return EXIT_FAILURE; } - openspace::global::openSpaceEngine.registerPathTokens(); + global::openSpaceEngine.registerPathTokens(); // Prepend the outgoing sgctArguments with the program name // as well as the configuration file that sgct is supposed to use @@ -1293,8 +1291,8 @@ int main(int argc, char** argv) { auto cleanup = [&](bool isInitialized) { if (isInitialized) { - openspace::global::openSpaceEngine.deinitializeGL(); - openspace::global::openSpaceEngine.deinitialize(); + global::openSpaceEngine.deinitializeGL(); + global::openSpaceEngine.deinitialize(); } // Clear function bindings to avoid crash after destroying the OpenSpace Engine @@ -1321,6 +1319,8 @@ int main(int argc, char** argv) { } } #endif // OPENSPACE_HAS_SPOUT + + ghoul::deinitialize(); }; if (!initSuccess) { diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 470f018fcb..26c5f5a094 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -221,7 +221,6 @@ private: double timestamp; }; ExternInteraction _externInteract; - bool _isRecording = false; double _timestampRecordStarted = 0.0; double _timestampPlaybackStarted_application = 0.0; double _timestampPlaybackStarted_simulation = 0.0; diff --git a/modules/atmosphere/rendering/atmospheredeferredcaster.cpp b/modules/atmosphere/rendering/atmospheredeferredcaster.cpp index 4836e32ead..9a7802b815 100644 --- a/modules/atmosphere/rendering/atmospheredeferredcaster.cpp +++ b/modules/atmosphere/rendering/atmospheredeferredcaster.cpp @@ -261,8 +261,8 @@ void AtmosphereDeferredcaster::preRaycast(const RenderData& renderData, program.setUniform(_uniformCache2.dModelTransformMatrix, _modelTransform); // Eye Space in SGCT to Eye Space in OS (SGCT View to OS Camera Rig) - glm::dmat4 dSgctEye2OSEye = glm::inverse( - glm::dmat4(renderData.camera.viewMatrix())); +// glm::dmat4 dSgctEye2OSEye = glm::inverse( +// glm::dmat4(renderData.camera.viewMatrix())); glm::dmat4 dSGCTViewToWorldMatrix = glm::inverse( renderData.camera.combinedViewMatrix() @@ -1508,7 +1508,7 @@ bool AtmosphereDeferredcaster::isAtmosphereInFrustum(const glm::dmat4& MVMatrix, double bottomDistance = MVMatrix[3][3] + MVMatrix[3][1]; double topDistance = MVMatrix[3][3] - MVMatrix[3][1]; double nearDistance = MVMatrix[3][3] + MVMatrix[3][2]; - double farDistance = MVMatrix[3][3] - MVMatrix[3][2]; +// double farDistance = MVMatrix[3][3] - MVMatrix[3][2]; // Normalize Planes double invMag = 1.0 / glm::length(leftNormal); @@ -1533,7 +1533,7 @@ bool AtmosphereDeferredcaster::isAtmosphereInFrustum(const glm::dmat4& MVMatrix, invMag = 1.0 / glm::length(farNormal); farNormal *= invMag; - farDistance *= invMag; +// farDistance *= invMag; if ((glm::dot(leftNormal, position) + leftDistance) < -radius) { return false; diff --git a/modules/base/dashboard/dashboarditemframerate.cpp b/modules/base/dashboard/dashboarditemframerate.cpp index 006667a6f2..bdc10a49a0 100644 --- a/modules/base/dashboard/dashboarditemframerate.cpp +++ b/modules/base/dashboard/dashboarditemframerate.cpp @@ -289,7 +289,7 @@ void DashboardItemFramerate::render(glm::vec2& penPosition) { ); int nLines = output.empty() ? 0 : - (std::count(output.begin(), output.end(), '\n') + 1); + static_cast((std::count(output.begin(), output.end(), '\n') + 1)); penPosition.y -= _font->height() * static_cast(nLines); diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index 171625c4e3..c29d1608a9 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -750,7 +750,6 @@ void RenderableBillboardsCloud::renderBillboards(const RenderData& data, _program->activate(); - const glm::dmat4 projMatrix = glm::dmat4(data.camera.projectionMatrix()); _program->setUniform( "screenSize", glm::vec2(global::renderEngine.renderingResolution()) diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.cpp b/modules/digitaluniverse/rendering/renderabledumeshes.cpp index 8c4c84e4f3..ccaa706c03 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.cpp +++ b/modules/digitaluniverse/rendering/renderabledumeshes.cpp @@ -77,19 +77,6 @@ namespace { "all point." }; - //constexpr openspace::properties::Property::PropertyInfo ScaleFactorInfo = { - // "ScaleFactor", - // "Scale Factor", - // "This value is used as a multiplicative factor that is applied to the apparent " - // "size of each point." - //}; - - constexpr openspace::properties::Property::PropertyInfo ColorInfo = { - "Color", - "Color", - "This value is used to define the color of the astronomical object." - }; - constexpr openspace::properties::Property::PropertyInfo TextColorInfo = { "TextColor", "Text Color", @@ -427,7 +414,7 @@ void RenderableDUMeshes::initializeGL() { } void RenderableDUMeshes::deinitializeGL() { - for (const std::pair& pair : _renderingMeshesMap) { + for (const std::pair& pair : _renderingMeshesMap) { for (int i = 0; i < pair.second.numU; ++i) { glDeleteVertexArrays(1, &pair.second.vaoArray[i]); glDeleteBuffers(1, &pair.second.vboArray[i]); @@ -483,7 +470,7 @@ void RenderableDUMeshes::renderMeshes(const RenderData&, _program->setUniform(_uniformCache.alphaValue, _alphaValue); //_program->setUniform(_uniformCache.scaleFactor, _scaleFactor); - for (const std::pair& pair : _renderingMeshesMap) { + for (const std::pair& pair : _renderingMeshesMap) { _program->setUniform(_uniformCache.color, _meshColorMap[pair.second.colorIndex]); for (size_t i = 0; i < pair.second.vaoArray.size(); ++i) { glBindVertexArray(pair.second.vaoArray[i]); diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index 7581b01f17..b06176406e 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -844,7 +844,7 @@ bool RenderablePlanesCloud::loadData() { bool RenderablePlanesCloud::loadTextures() { if (!_textureFileMap.empty()) { - for (const std::pair& pair : _textureFileMap) { + for (const std::pair& pair : _textureFileMap) { const auto& p = _textureMap.insert(std::make_pair( pair.first, ghoul::io::TextureReader::ref().loadTexture(pair.second) diff --git a/modules/globebrowsing/src/globelabelscomponent.cpp b/modules/globebrowsing/src/globelabelscomponent.cpp index 864b85d6c7..9cea901ce7 100644 --- a/modules/globebrowsing/src/globelabelscomponent.cpp +++ b/modules/globebrowsing/src/globelabelscomponent.cpp @@ -45,11 +45,10 @@ #include namespace { - constexpr const char* KeyLabels = "Labels"; - constexpr const char* KeyLabelsFileName = "FileName"; - constexpr const char* _loggerCat = "GlobeLabels"; + constexpr const char* KeyLabelsFileName = "FileName"; + constexpr const double LabelFadeRangeConst = 1500.0; constexpr const double RangeAngularCoefConst = 0.8; constexpr const float MinTransparencyValueConst = 0.009f; @@ -671,19 +670,10 @@ void GlobeLabelsComponent::renderLabels(const RenderData& data, float distToCamera, float fadeInVariable ) { - constexpr double DIST_EPS = 6000.0; - constexpr double SIN_EPS = 0.001; - glm::vec4 textColor = _labelsColor; textColor.a *= fadeInVariable; - glm::dmat4 invMP = glm::inverse(_globe->modelTransform()); - glm::dmat4 invCombinedView = glm::inverse(data.camera.combinedViewMatrix()); - - glm::dvec4 cameraPosWorld = invCombinedView * glm::dvec4(0.0, 0.0, 0.0, 1.0); - glm::dvec3 cameraPosObj = glm::dvec3(invMP * cameraPosWorld); glm::dvec4 cameraUpVecWorld = glm::dvec4(data.camera.lookUpVectorWorldSpace(), 0.0); - glm::dvec3 cameraLookUpObj = glm::dvec3(invMP * cameraUpVecWorld); glm::dmat4 VP = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) * data.camera.combinedViewMatrix(); @@ -799,7 +789,7 @@ bool GlobeLabelsComponent::isLabelInFrustum(const glm::dmat4& MVMatrix, double bottomDistance = MVMatrix[3][3] + MVMatrix[3][1]; double topDistance = MVMatrix[3][3] - MVMatrix[3][1]; double nearDistance = MVMatrix[3][3] + MVMatrix[3][2]; - double farDistance = MVMatrix[3][3] - MVMatrix[3][2]; + // double farDistance = MVMatrix[3][3] - MVMatrix[3][2]; // Normalize Planes const double invMagLeft = 1.0 / glm::length(leftNormal); @@ -824,7 +814,7 @@ bool GlobeLabelsComponent::isLabelInFrustum(const glm::dmat4& MVMatrix, const double invMagFar = 1.0 / glm::length(farNormal); farNormal *= invMagFar; - farDistance *= invMagFar; + // farDistance *= invMagFar; constexpr const float Radius = 1.0; diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index 6c4a5ea2c9..d1ffd5d624 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -173,8 +173,10 @@ void GlobeTranslation::fillAttachedNode() { "GlobeTranslation", "Could not set attached node as it does not have a RenderableGlobe" ); - // Reset the globe name to it's previous name - _globe = _attachedNode->identifier(); + if (_attachedNode) { + // Reset the globe name to it's previous name + _globe = _attachedNode->identifier(); + } } } diff --git a/modules/globebrowsing/src/tileprovider.cpp b/modules/globebrowsing/src/tileprovider.cpp index 0fe168fd78..addef1e23a 100644 --- a/modules/globebrowsing/src/tileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider.cpp @@ -1123,7 +1123,9 @@ void update(TileProvider& tp) { if (newCurrent) { t.currentTileProvider = newCurrent; } - update(*t.currentTileProvider); + if (t.currentTileProvider) { + update(*t.currentTileProvider); + } } break; } diff --git a/modules/server/src/topics/timetopic.cpp b/modules/server/src/topics/timetopic.cpp index 4710d13c4f..60512f4516 100644 --- a/modules/server/src/topics/timetopic.cpp +++ b/modules/server/src/topics/timetopic.cpp @@ -32,7 +32,6 @@ #include namespace { - constexpr const char* _loggerCat = "TimeTopic"; constexpr const char* EventKey = "event"; constexpr const char* SubscribeEvent = "start_subscription"; constexpr const char* UnsubscribeEvent = "stop_subscription"; diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 891ee0efb8..474e7158b3 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -773,7 +773,6 @@ void RenderableStars::renderPSFToTexture() { GLenum blendDestRGB; GLenum blendSrcAlpha; GLenum blendSrcRGB; - GLboolean depthMask; glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRGB); glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha); @@ -927,7 +926,6 @@ void RenderableStars::render(const RenderData& data, RendererTasks&) { glm::dmat4(data.modelTransform.rotation) * glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); - glm::dmat4 modelViewMatrix = data.camera.combinedViewMatrix() * modelMatrix; glm::dmat4 projectionMatrix = glm::dmat4(data.camera.projectionMatrix()); glm::dmat4 cameraViewProjectionMatrix = projectionMatrix * diff --git a/modules/space/rendering/renderablestars.h b/modules/space/rendering/renderablestars.h index 986fd5682f..272b6b9242 100644 --- a/modules/space/rendering/renderablestars.h +++ b/modules/space/rendering/renderablestars.h @@ -165,7 +165,6 @@ private: GLuint _psfVao = 0; GLuint _psfVbo = 0; GLuint _psfTexture = 0; - GLuint _discTexture = 0; GLuint _convolvedTexture = 0; }; diff --git a/modules/volume/tasks/generaterawvolumetask.cpp b/modules/volume/tasks/generaterawvolumetask.cpp index ea64003e33..e5942215ff 100644 --- a/modules/volume/tasks/generaterawvolumetask.cpp +++ b/modules/volume/tasks/generaterawvolumetask.cpp @@ -50,9 +50,6 @@ namespace { constexpr const char* KeyValueFunction = "ValueFunction"; constexpr const char* KeyLowerDomainBound = "LowerDomainBound"; constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; - - constexpr const char* KeyMinValue = "MinValue"; - constexpr const char* KeyMaxValue = "MaxValue"; } // namespace namespace openspace { diff --git a/modules/volume/transferfunctionhandler.cpp b/modules/volume/transferfunctionhandler.cpp index 1bee321f4a..e3d01f1e8d 100644 --- a/modules/volume/transferfunctionhandler.cpp +++ b/modules/volume/transferfunctionhandler.cpp @@ -35,12 +35,6 @@ namespace { "All the envelopes used in the transfer function" }; - constexpr openspace::properties::Property::PropertyInfo HistogramInfo = { - "Histogram", - "Histogram", - "All the data" - }; - constexpr openspace::properties::Property::PropertyInfo DataUnitInfo = { "DataUnit", "DataUnit", diff --git a/src/interaction/touchbar.mm b/src/interaction/touchbar.mm index de51a9fee7..f1762ced24 100644 --- a/src/interaction/touchbar.mm +++ b/src/interaction/touchbar.mm @@ -31,6 +31,7 @@ #include #include #include +#include using namespace openspace; @@ -44,8 +45,8 @@ using namespace openspace; #import static NSString* pauseResultId = @"com.openspaceproject.pause_resume"; -static NSString* showFullGuiId = @"com.openspaceproject.show_full_gui"; -static NSString* showSimpleGuiId = @"com.openspaceproject.show_simple_gui"; +static NSString* hideGuiId = @"com.openspaceproject.hide_gui"; +static NSString* hideOnScreenTextId = @"com.openspaceproject.hide_onscreen"; NSArray* focusIdentifiers; @@ -55,8 +56,8 @@ NSArray* focusIdentifiers; makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier; - (void)pauseResumeButtonAction:(id)sender; - (void)focusObjectAction:(id)sender; - - (void)fullGuiButtonAction:(id)sender; - - (void)simpleGuiButtonAction:(id)sender; + - (void)hideTextAction:(id)sender; + - (void)hideGuiAction:(id)sender; @end @implementation TouchBarDelegate @@ -66,7 +67,7 @@ NSArray* focusIdentifiers; touchBar.customizationIdentifier = @"com.openspaceproject.main_touch_bar"; - NSArray* objs = [@[showSimpleGuiId, showFullGuiId, + NSArray* objs = [@[hideGuiId, hideOnScreenTextId, NSTouchBarItemIdentifierFixedSpaceSmall, pauseResultId, NSTouchBarItemIdentifierFlexibleSpace] arrayByAddingObjectsFromArray: focusIdentifiers]; @@ -85,8 +86,6 @@ NSArray* focusIdentifiers; - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { - // @TODO(abock): Potential memory leak here by returning an alloc? - // Remove the unused variable warning (void)touchBar; @@ -112,38 +111,38 @@ NSArray* focusIdentifiers; return [touchBarItem autorelease]; } - if ([identifier isEqualToString:showFullGuiId]) { + if ([identifier isEqualToString:hideOnScreenTextId]) { NSButton* button = [NSButton - buttonWithTitle:@"Full GUI" - target:self action:@selector(fullGuiButtonAction:) + buttonWithTitle:@"Toggle Text" + target:self action:@selector(hideTextAction:) ]; NSCustomTouchBarItem* touchBarItem = [ [NSCustomTouchBarItem alloc] - initWithIdentifier:showFullGuiId + initWithIdentifier:hideOnScreenTextId ]; touchBarItem.view = button; touchBarItem.customizationLabel = NSLocalizedString( - @"Toggles the full GUI", + @"Toogles on-screen text", @"" ); return [touchBarItem autorelease]; } - if ([identifier isEqualToString:showSimpleGuiId]) { + if ([identifier isEqualToString:hideGuiId]) { NSButton* button = [NSButton - buttonWithTitle:@"Simple GUI" - target:self action:@selector(simpleGuiButtonAction:) + buttonWithTitle:@"Toggle GUI" + target:self action:@selector(hideGuiAction:) ]; NSCustomTouchBarItem* touchBarItem = [ [NSCustomTouchBarItem alloc] - initWithIdentifier:showSimpleGuiId + initWithIdentifier:hideGuiId ]; touchBarItem.view = button; touchBarItem.customizationLabel = NSLocalizedString( - @"Toggles the simple GUI", + @"Toggles the main GUI", @"" ); @@ -188,63 +187,40 @@ NSArray* focusIdentifiers; NSString* title = [button title]; + std::string str = fmt::format( + "openspace.setPropertyValueSingle('{}', '{}');\ + openspace.setPropertyValueSingle('{}', '');\ + openspace.setPropertyValueSingle('{}', '');", + "NavigationHandler.OrbitalNavigator.Anchor", std::string([title UTF8String]), + "NavigationHandler.OrbitalNavigator.Aim", + "NavigationHandler.OrbitalNavigator.RetargetAnchor" + ); global::scriptEngine.queueScript( - "openspace.setPropertyValue('NavigationHandler.Origin', '" + - std::string([title UTF8String]) + "');", + str, scripting::ScriptEngine::RemoteScripting::Yes ); } - - (void)fullGuiButtonAction:(id)sender { + - (void)hideTextAction:(id)sender { // Remove unused variable warning (void)sender; + global::scriptEngine.queueScript( - "local b = openspace.getPropertyValue(\ - 'Modules.ImGUI.Main.Enabled'\ - );\ - openspace.setPropertyValueSingle(\ - 'Modules.ImGUI.Main.Enabled',\ - not b\ - );\ - openspace.setPropertyValueSingle(\ - 'Modules.ImGUI.Main.IsHidden',\ - b\ - );", + "local isEnabled = openspace.getPropertyValue('Dashboard.IsEnabled');\ + openspace.setPropertyValueSingle('Dashboard.IsEnabled', not isEnabled);\ + openspace.setPropertyValueSingle('RenderEngine.ShowLog', not isEnabled);\ + openspace.setPropertyValueSingle('RenderEngine.ShowVersion', not isEnabled);\ + openspace.setPropertyValueSingle('RenderEngine.ShowCamera', not isEnabled)", scripting::ScriptEngine::RemoteScripting::No ); } - - (void)simpleGuiButtonAction:(id)sender { + - (void)hideGuiAction:(id)sender { // Remove unused variable warning (void)sender; global::scriptEngine.queueScript( -"local b = openspace.getPropertyValue('Modules.ImGUI.Main.FeaturedProperties.Enabled');\n\ -local c = openspace.getPropertyValue('Modules.ImGUI.Main.IsHidden');\n\ -openspace.setPropertyValue('Modules.ImGUI.*.Enabled', false);\n\ -if b and c then\n\ - -- This can happen if the main properties window is enabled, the main gui\n\ - -- is enabled and then closed again. So the main properties window is\n\ - -- enabled, but also all windows are hidden\n\ - openspace.setPropertyValueSingle('Modules.ImGUI.Main.IsHidden', false);\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.FeaturedProperties.Enabled',\n\ - true\n\ - );\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.SpaceTime.Enabled',\n\ - true\n\ - );\n\ -else\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.FeaturedProperties.Enabled',\n\ - not b\n\ - );\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.SpaceTime.Enabled',\n\ - not b\n\ - );\n\ - openspace.setPropertyValueSingle('Modules.ImGUI.Main.IsHidden', b);\n\ -end", + "local isEnabled = openspace.getPropertyValue('Modules.CefWebGui.Visible');\ + openspace.setPropertyValueSingle('Modules.CefWebGui.Visible', not isEnabled);", scripting::ScriptEngine::RemoteScripting::No ); } @@ -266,19 +242,18 @@ void showTouchbar() { [NSApplication sharedApplication].automaticCustomizeTouchBarMenuItemEnabled = YES; } - std::vector nodes = - global::renderEngine.scene()->allSceneGraphNodes(); + std::vector ns = global::renderEngine.scene()->allSceneGraphNodes(); std::sort( - nodes.begin(), - nodes.end(), + ns.begin(), + ns.end(), [](SceneGraphNode* lhs, SceneGraphNode* rhs) { return lhs->guiName() < rhs->guiName(); } ); NSMutableArray* ids = [[NSMutableArray alloc] init]; - for (SceneGraphNode* n : nodes) { + for (SceneGraphNode* n : ns) { const std::vector& tags = n->tags(); auto it = std::find(tags.begin(), tags.end(), "GUI.Interesting"); if (it != tags.end()) { diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index e4075bf055..6694af0fca 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -62,7 +62,6 @@ namespace openspace::performance { // The ghoul::SharedData block addressed by OpenSpacePerformanceMeasurementSharedData // will only get allocated once and contains the total number of allocated shared memory // blocks alongside a list of names of these blocks -// void PerformanceManager::CreateGlobalSharedMemory() { static_assert( @@ -70,6 +69,8 @@ void PerformanceManager::CreateGlobalSharedMemory() { "The global memory struct does not fit the allocated global memory space" ); + ghoul::SharedMemory::remove(GlobalSharedMemoryName); + if (ghoul::SharedMemory::exists(GlobalSharedMemoryName)) { ghoul::SharedMemory sharedMemory(GlobalSharedMemoryName); sharedMemory.acquireLock(); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index c2b9505bc1..4498e1f9cf 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -246,6 +246,7 @@ RenderEngine::RenderEngine() , _hdrExposure(HDRExposureInfo, 0.4f, 0.01f, 10.0f) , _hdrBackground(BackgroundExposureInfo, 2.8f, 0.01f, 10.0f) , _gamma(GammaInfo, 2.2f, 0.01f, 10.0f) + , _horizFieldOfView(HorizFieldOfViewInfo, 80.f, 1.f, 179.0f) , _globalRotation( GlobalRotationInfo, glm::vec3(0.f), @@ -264,7 +265,6 @@ RenderEngine::RenderEngine() glm::vec3(-glm::pi()), glm::vec3(glm::pi()) ) - , _horizFieldOfView(HorizFieldOfViewInfo, 80.f, 1.f, 179.0f) { _doPerformanceMeasurements.onChange([this](){ global::performanceManager.setEnabled(_doPerformanceMeasurements); diff --git a/src/util/timemanager.cpp b/src/util/timemanager.cpp index 4f31a86f23..4127db2012 100644 --- a/src/util/timemanager.cpp +++ b/src/util/timemanager.cpp @@ -138,7 +138,7 @@ void TimeManager::preSynchronization(double dt) { if (newTime != _lastTime) { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _timeChangeCallbacks) { + for (const std::pair& it : _timeChangeCallbacks) { it.second(); } } @@ -148,14 +148,14 @@ void TimeManager::preSynchronization(double dt) { { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _deltaTimeChangeCallbacks) { + for (const std::pair& it : _deltaTimeChangeCallbacks) { it.second(); } } if (_timelineChanged) { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _timelineChangeCallbacks) { + for (const std::pair& it : _timelineChangeCallbacks) { it.second(); } } @@ -230,7 +230,7 @@ void TimeManager::progressTime(double dt) { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _timeJumpCallbacks) { + for (const std::pair& it : _timeJumpCallbacks) { it.second(); } return; From 0293eda1e817567e6d225bbb96e13a02e16fda74 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 5 Jul 2019 16:38:43 +0200 Subject: [PATCH 03/32] Add support for arrays in luascript topic (#913) --- modules/server/src/topics/luascripttopic.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/server/src/topics/luascripttopic.cpp b/modules/server/src/topics/luascripttopic.cpp index f883410764..018159f0ba 100644 --- a/modules/server/src/topics/luascripttopic.cpp +++ b/modules/server/src/topics/luascripttopic.cpp @@ -69,7 +69,7 @@ namespace { return "[" + formatLuaString(it.key()) + "] = " + formatLua(it); } - std::string formatLuaTable(const nlohmann::json& json) { + std::string formatObjectAsLuaTable(const nlohmann::json& json) { std::string output = "{"; auto it = json.begin(); for (size_t i = 0; i < json.size(); ++i, ++it) { @@ -81,9 +81,24 @@ namespace { return output + "}"; } + std::string formatArrayAsLuaTable(const nlohmann::json& json) { + std::string output = "{"; + auto it = json.begin(); + for (size_t i = 0; i < json.size(); ++i, ++it) { + output += formatLua(it); + if (i < json.size() - 1) { + output += ","; + } + } + return output + "}"; + } + std::string formatLua(const nlohmann::json::const_iterator& it) { if (it->is_object()) { - return formatLuaTable(it->get()); + return formatObjectAsLuaTable(it->get()); + } + if (it->is_array()) { + return formatArrayAsLuaTable(it->get()); } if (it->is_number()) { return fmt::format("{:E}", it->get()); From b25b205e99bd5772e0164626fc29ca0bebee4dcd Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 12 Jul 2019 11:17:15 +0200 Subject: [PATCH 04/32] Fixes for the Gaia data sync --- .../milkyway/gaia/gaia_dr2_download_stars.asset | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset b/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset index 4dac2821f8..d80419ac78 100644 --- a/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset +++ b/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset @@ -1,19 +1,30 @@ -- Download a dataset of 618 million stars (28 GB), already preprocessed and stored in a binary octree. -- The octree was generated from the full DR2 by filtering away all stars with a parallax error higher than 0.5 -- Max Star Per Node = 50,000 and max distance = 500kpc -asset.syncedResource({ +local gaia618Destination = asset.syncedResource({ Name = "Gaia DR2 618M Octree", Type = "HttpSynchronization", Identifier = "gaia_stars_618M_octree", Version = 1 }) +local gaia618DestinationExtracted = gaia618Destination + '/data'; -- Download the full DR2 dataset with 24 values per star (preprocessed with theReadFitsTask (gaia_read.task) into 8 binary files). -- From these files new subsets can be created with the ConstructOctreeTask (gaia_octree.task). -- Total size of download is 151 GB. -asset.syncedResource({ +local gaiaFull = asset.syncedResource({ Name = "Gaia DR2 Full Raw", Type = "HttpSynchronization", Identifier = "gaia_stars_dr2_raw", Version = 1 }) + +asset.onInitialize(function() + if not openspace.directoryExists(gaia618DestinationExtracted) then + openspace.printInfo("Extracted Gaia dataset") + openspace.unzipFile(gaia618Destination .. '/DR2_full_Octree[50kSPN,500dist]_50,50.zip', gaia618DestinationExtracted, true) + end +end) + +asset.export('GaiaDR2_618M', gaia618DestinationExtracted) +asset.export('GaiaFullDataset', gaiaFull) From f43bcadee3873abb9410f8c43897c890fbc81fbd Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Tue, 16 Jul 2019 13:13:33 +0200 Subject: [PATCH 05/32] Feature/navigation state (#930) * Replace setCameraState with setNavigationState + equivalents * Add documentation and verification of NavigationState-related interfaces * Documentation and verification fixes * Change reference frame behavior * Scene fixes * Replace earthrise recording with navigation state and time --- data/assets/apollo8.scene | 21 +- data/assets/apollo_sites.scene | 7 +- data/assets/dawn.scene | 3 +- data/assets/default.scene | 13 +- data/assets/examples/basic.scene | 16 +- data/assets/gaia.scene | 3 +- data/assets/insight.scene | 7 +- data/assets/juno.scene | 7 +- data/assets/messenger.scene | 7 +- data/assets/newhorizons.scene | 9 +- data/assets/osirisrex.scene | 5 +- data/assets/rosetta.scene | 7 +- .../apollo/apollo_globebrowsing.asset | 16 +- .../planets/jupiter/minor/carpo_group.asset | 2 +- data/assets/voyager.scene | 6 +- include/openspace/interaction/interpolator.h | 2 +- .../openspace/interaction/navigationhandler.h | 51 +- .../openspace/interaction/orbitalnavigator.h | 11 +- modules/globebrowsing/globebrowsingmodule.cpp | 172 +++---- modules/globebrowsing/globebrowsingmodule.h | 27 +- .../globebrowsing/globebrowsingmodule_lua.inl | 82 ++- .../globebrowsing/src/globetranslation.cpp | 5 + recordings/apollo8 | Bin 5994 -> 0 bytes src/documentation/core_registration.cpp | 3 + src/engine/openspaceengine.cpp | 2 - src/interaction/navigationhandler.cpp | 486 +++++++++++++----- src/interaction/navigationhandler_lua.inl | 50 +- src/interaction/orbitalnavigator.cpp | 36 +- src/scene/scenegraphnode.cpp | 16 +- 29 files changed, 698 insertions(+), 374 deletions(-) delete mode 100644 recordings/apollo8 diff --git a/data/assets/apollo8.scene b/data/assets/apollo8.scene index 3301a6720a..6ec4a8b9d5 100644 --- a/data/assets/apollo8.scene +++ b/data/assets/apollo8.scene @@ -12,14 +12,19 @@ local Keybindings = { { Key = "E", Command = "openspace.time.setPause(true);" .. - "openspace.setPropertyValue('*Trail.Renderable.Enabled', false)".. - "openspace.setPropertyValue('Scene.Apollo8LaunchTrail.Renderable.Enabled', false)".. - "openspace.sessionRecording.startPlayback('apollo8')", + "openspace.time.setDeltaTime(1);" .. + "openspace.time.setTime('1968 DEC 24 16:37:31');" .. + "openspace.navigation.setNavigationState({" .. + " Anchor = 'Apollo8'," .. + " Position = { 1.494592E1, 3.236777E1, -4.171296E1 }," .. + " ReferenceFrame = 'Root'," .. + " Up = { 0.960608E0, -0.212013E0, 0.179675E0 }" .. + "});" .. + "openspace.setPropertyValue('*Trail.Renderable.Enabled', false)", Documentation = "Jump to right before the earthrise photo", Name = "Set Earthrise time", GuiPath = "/Missions/Apollo/8", Local = false - }, { Key = "U", @@ -115,13 +120,7 @@ asset.onInitialize(function () openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.MinimumAllowedDistance', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.LodScaleFactor', 24.0); - openspace.navigation.setCameraState({ - Anchor = earthAsset.Earth.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 }, - }) - - openspace.globebrowsing.goToGeo(20, -60, 15000000) + openspace.globebrowsing.goToGeo(earthAsset.Earth.Identifier, 20, -60, 15000000) end) asset.onDeinitialize(function () diff --git a/data/assets/apollo_sites.scene b/data/assets/apollo_sites.scene index 2c59d6f25a..05b0460970 100644 --- a/data/assets/apollo_sites.scene +++ b/data/assets/apollo_sites.scene @@ -96,12 +96,7 @@ asset.onInitialize(function () -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true); - openspace.navigation.setCameraState({ - Anchor = moonAsset.Moon.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0, 0, 0, 0 }, - }) - openspace.globebrowsing.goToGeo(20, -60, 15000000) + openspace.globebrowsing.goToGeo(moonAsset.Moon.Identifier, 20, -60, 15000000) openspace.setPropertyValueSingle("Scene.Moon.Renderable.PerformShading", false) end) diff --git a/data/assets/dawn.scene b/data/assets/dawn.scene index b519b87da2..8af4d7bf6d 100644 --- a/data/assets/dawn.scene +++ b/data/assets/dawn.scene @@ -10,10 +10,9 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "Dawn", "Ceres", "Vesta" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = DawnAsset.Dawn.Identifier, Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = { -0.106166, 0.981574, -0.084545, 0.134513 }, }) end) diff --git a/data/assets/default.scene b/data/assets/default.scene index 81300e342a..c6d3e2523c 100644 --- a/data/assets/default.scene +++ b/data/assets/default.scene @@ -1,20 +1,15 @@ asset.require('./base') local earthAsset = asset.require('scene/solarsystem/planets/earth/earth') + asset.onInitialize(function () local now = openspace.time.currentWallTime() - -- Jump back one day to show a complete planet + -- Jump back one day to be able to show complete weather data on Earth. openspace.time.setTime(openspace.time.advancedTime(now, "-1d")) + openspace.globebrowsing.goToGeo("Earth", 58.5877, 16.1924, 20000000) + openspace.markInterestingNodes({ "Earth", "Mars", "Moon", "Sun" }) - - openspace.navigation.setCameraState({ - Anchor = earthAsset.Earth.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 }, - }) - - openspace.globebrowsing.goToGeo(58.5877, 16.1924, 20000000) end) asset.onDeinitialize(function () diff --git a/data/assets/examples/basic.scene b/data/assets/examples/basic.scene index 182c4776fe..ec17991a57 100644 --- a/data/assets/examples/basic.scene +++ b/data/assets/examples/basic.scene @@ -1,8 +1,9 @@ local assetHelper = asset.require('util/asset_helper') local sceneHelper = asset.require('util/scene_helper') local propertyHelper = asset.require('util/property_helper') +local debugHelper = asset.require('util/debug_helper') --- At this point, a sceene needs basic spice data to load. +-- At this point, a scene needs basic spice data to load. asset.require('spice/base') asset.require('util/default_keybindings') @@ -12,10 +13,15 @@ asset.require('util/default_joystick') asset.require('util/webgui') local spheres = asset.require('examples/spheres') +debugHelper.registerCartesianAxes(asset, { + Parent = "Root", + Scale = 10 +}) + asset.onInitialize(function () - openspace.navigation.setCameraState({ - Anchor = spheres.ExampleSphere1.Identifier, - Position = { 20, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 } + openspace.navigation.setNavigationState({ + Anchor = "Root", + Position = { 20, 20, 20 }, + Up = {0, 1, 0}, }) end) diff --git a/data/assets/gaia.scene b/data/assets/gaia.scene index 94d2f8ddbb..45213dfeaa 100644 --- a/data/assets/gaia.scene +++ b/data/assets/gaia.scene @@ -35,10 +35,9 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "Gaia" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = earthAsset.Earth.Identifier, Position = { 1000000000000.0, 1000000000000.0, 1000000000000.0 }, - Rotation = { 0.683224, -0.765934, -0.601234, -0.418073 }, }) end) diff --git a/data/assets/insight.scene b/data/assets/insight.scene index 3c02820e60..d185471418 100644 --- a/data/assets/insight.scene +++ b/data/assets/insight.scene @@ -60,10 +60,11 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "Insight" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = insightAsset.Insight.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 }, + Position = { 8.430115E0, -1.791710E1, 2.813660E0 }, + ReferenceFrame = "Root", + Up = { 0.494659E0,0.357162E0,0.792306E0 }, }) end) diff --git a/data/assets/juno.scene b/data/assets/juno.scene index 9ed6afaccd..f17e5c3f8b 100644 --- a/data/assets/juno.scene +++ b/data/assets/juno.scene @@ -18,10 +18,11 @@ asset.onInitialize(function () 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = junoAsset.Juno.Identifier, - Position = { 1837386367.601345, -389860693812.834839, 714830404470.398926 }, - Rotation = { -0.336540, 0.711402, -0.099212, 0.608937 }, + Position = { 1.243398E8, 7.176068E7, -1.519733E7 }, + ReferenceFrame = "Root", + Up = { -0.377400E0, 0.764573E0, 0.522492E0 }, }) end) diff --git a/data/assets/messenger.scene b/data/assets/messenger.scene index 850077d2b0..dc2f722880 100644 --- a/data/assets/messenger.scene +++ b/data/assets/messenger.scene @@ -33,10 +33,11 @@ asset.onInitialize(function () 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = "Mercury", - Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = {0.180662, 0.021334, 0.979084, 0.091111}, + Position = { 2.423690E11, 1.979038E11, -2.241483E10 }, + ReferenceFrame = "Root", + Up = { -0.492046E0, 0.666088E0, 0.560551E0 } }) end) diff --git a/data/assets/newhorizons.scene b/data/assets/newhorizons.scene index 71f77d618a..9de5012f7d 100644 --- a/data/assets/newhorizons.scene +++ b/data/assets/newhorizons.scene @@ -255,10 +255,11 @@ asset.onInitialize(function () openspace.setPropertyValueSingle('Scene.Charon.Renderable.Enabled', false) openspace.setPropertyValueSingle("Scene.PlutoBarycenterTrail.Renderable.Enabled", false) - openspace.navigation.setCameraState({ - Anchor = NewHorizonsAsset.NewHorizons.Identifier, - Position = { 4662120063743.592773, 1263245003503.724854, -955413856565.788086 }, - Rotation = { 0.683224, -0.165934, 0.701234, 0.118073 }, + openspace.navigation.setNavigationState({ + Anchor = "NewHorizons", + ReferenceFrame = "Root", + Position = { -6.572656E1, -7.239404E1, -2.111890E1 }, + Up = { 0.102164, -0.362945, 0.926193 } }) end) diff --git a/data/assets/osirisrex.scene b/data/assets/osirisrex.scene index a53e817cd2..285fdb5252 100644 --- a/data/assets/osirisrex.scene +++ b/data/assets/osirisrex.scene @@ -134,10 +134,9 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "OsirisRex", "BennuBarycenter", "Earth" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = OsirisRexAsset.OsirisRex.Identifier, - Position = { 26974590199.661884, 76314608558.908020, -127086452897.101791 }, - Rotation = { 0.729548, -0.126024, 0.416827, 0.527382 }, + Position = { 26974590199.661884, 76314608558.908020, -127086452897.101791 } }) end) diff --git a/data/assets/rosetta.scene b/data/assets/rosetta.scene index 67d5dc7951..315c8804fc 100644 --- a/data/assets/rosetta.scene +++ b/data/assets/rosetta.scene @@ -134,10 +134,11 @@ asset.onInitialize(function () 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = Comet67PAsset.Comet67P.Identifier, - Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = { -0.106166, 0.981574, -0.084545, 0.134513 }, + ReferenceFrame = "Root", + Position = { -7.294781E5 , -6.657894E5, 2.509047E6 }, + Up = { 0.146529E0, 0.944727E0, 0.293290E0 } }) openspace.setPropertyValue('Scene.67P.Renderable.PerformShading', false); diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset b/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset index aaab113192..fb9f1e14c5 100644 --- a/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset +++ b/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset @@ -2,36 +2,36 @@ local heightmaps = asset.syncedResource({ - Name = "Apollo Globebrowsing", + Name = "Apollo Globebrowsing Heightmaps", Type = "HttpSynchronization", Identifier = "apollo_globebrowsing_heightmaps", Version = 1 }) local basemaps = asset.syncedResource({ - Name = "Apollo Globebrowsing", + Name = "Apollo Globebrowsing Basemaps", Type = "HttpSynchronization", Identifier = "apollo_globebrowsing_basemaps", Version = 1 }) local naclighting = asset.syncedResource({ - Name = "Apollo Globebrowsing", + Name = "Apollo Globebrowsing NAC Lighting", Type = "HttpSynchronization", Identifier = "apollo_globebrowsing_naclighting", Version = 1 }) local stations = asset.syncedResource({ - Name = "Apollo 17 Globebrowsing", + Name = "Apollo 17 Globebrowsing Stations", Type = "HttpSynchronization", Identifier = "apollo_17_stations", Version = 1 }) asset.onInitialize(function () - openspace.globebrowsing.addBlendingLayersFromDirectory(heightmaps,"Moon") - openspace.globebrowsing.addBlendingLayersFromDirectory(basemaps,"Moon") - openspace.globebrowsing.addBlendingLayersFromDirectory(naclighting,"Moon") - openspace.globebrowsing.addBlendingLayersFromDirectory(stations,"Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(heightmaps, "Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(basemaps, "Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(naclighting, "Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(stations, "Moon") end) diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset index 157b5dbbfd..7938f89387 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset @@ -14,7 +14,7 @@ local carpoGroup = { { Identifier = "Carpo", Parent = { - Name = parentIdentifier, + Identifier = parentIdentifier, Spice = parentSpice }, Spice = "CARPO", diff --git a/data/assets/voyager.scene b/data/assets/voyager.scene index d91cc5254d..c5789bf926 100644 --- a/data/assets/voyager.scene +++ b/data/assets/voyager.scene @@ -47,10 +47,10 @@ asset.onInitialize(function () "Earth", "Voyager 1", "Voyager 2", "Jupiter", "Saturn", "Uranus", "Neptune" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = VoyagerAsset.Voyager_1.Identifier, - Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = { -0.106166, 0.981574, -0.084545, 0.134513 }, + ReferenceFrame = "Root", + Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 } }) end) diff --git a/include/openspace/interaction/interpolator.h b/include/openspace/interaction/interpolator.h index b2f79a9e55..54750bc1eb 100644 --- a/include/openspace/interaction/interpolator.h +++ b/include/openspace/interaction/interpolator.h @@ -51,7 +51,7 @@ public: private: std::function _transferFunction; - float _t = 0.f; + float _t = 1.f; float _interpolationTime = 1.f; float _scaledDeltaTime = 0.f; }; diff --git a/include/openspace/interaction/navigationhandler.h b/include/openspace/interaction/navigationhandler.h index 3ab99cd0e9..0da3db3ab8 100644 --- a/include/openspace/interaction/navigationhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -25,13 +25,17 @@ #ifndef __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ #define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ -#include - +#include +#include #include +#include +#include +#include #include #include #include #include +#include namespace openspace { class Camera; @@ -48,6 +52,25 @@ class OrbitalNavigator; class NavigationHandler : public properties::PropertyOwner { public: + struct NavigationState { + NavigationState() = default; + NavigationState(const ghoul::Dictionary& dictionary); + NavigationState(std::string anchor, std::string aim, std::string referenceFrame, + glm::dvec3 position, std::optional up = std::nullopt, + double yaw = 0.0, double pitch = 0.0); + + ghoul::Dictionary dictionary() const; + static documentation::Documentation Documentation(); + + std::string anchor; + std::string aim; + std::string referenceFrame; + glm::dvec3 position; + std::optional up; + double yaw = 0.0; + double pitch = 0.0; + }; + NavigationHandler(); ~NavigationHandler(); @@ -55,10 +78,10 @@ public: void deinitialize(); // Mutators + void setNavigationStateNextFame(NavigationState state); void setCamera(Camera* camera); void setInterpolationTime(float durationInSeconds); - void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); void updateCamera(double deltaTime); void setEnableKeyFrameInteraction(); void setDisableKeyFrameInteraction(); @@ -66,12 +89,11 @@ public: void stopPlayback(); // Accessors - ghoul::Dictionary cameraStateDictionary(); Camera* camera() const; const InputState& inputState() const; const OrbitalNavigator& orbitalNavigator() const; OrbitalNavigator& orbitalNavigator(); - KeyframeNavigator& keyframeNavigator() const; + KeyframeNavigator& keyframeNavigator(); bool isKeyFrameInteractionEnabled() const; float interpolationTime() const; @@ -100,10 +122,14 @@ public: void clearJoystickButtonCommand(int button); std::vector joystickButtonCommand(int button) const; + NavigationState navigationState(const SceneGraphNode& referenceFrame) const; + void saveNavigationState(const std::string& filepath, + const std::string& referenceFrameIdentifier); - void saveCameraStateToFile(const std::string& filepath); - void restoreCameraStateFromFile(const std::string& filepath); + void loadNavigationState(const std::string& filepath); + + void setNavigationStateNextFrame(NavigationState state); /** * \return The Lua library that contains all Lua functions available to affect the @@ -112,15 +138,18 @@ public: static scripting::LuaLibrary luaLibrary(); private: - bool _cameraUpdatedFromScript = false; + void applyNavigationState(const NavigationHandler::NavigationState& ns); + bool _playbackModeEnabled = false; - std::unique_ptr _inputState; + InputState _inputState; Camera* _camera = nullptr; std::function _playbackEndCallback; - std::unique_ptr _orbitalNavigator; - std::unique_ptr _keyframeNavigator; + OrbitalNavigator _orbitalNavigator; + KeyframeNavigator _keyframeNavigator; + + std::optional _pendingNavigationState; properties::BoolProperty _useKeyFrameInteraction; }; diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h index 3f60af50c6..0eff98c64c 100644 --- a/include/openspace/interaction/orbitalnavigator.h +++ b/include/openspace/interaction/orbitalnavigator.h @@ -38,6 +38,8 @@ #include #include +#include + namespace openspace { class SceneGraphNode; class Camera; @@ -58,6 +60,7 @@ public: Camera* camera() const; void setCamera(Camera* camera); + void clearPreviousState(); void setFocusNode(const std::string& focusNode); void setAnchorNode(const std::string& anchorNode); @@ -70,6 +73,7 @@ public: void resetNodeMovements(); JoystickCameraStates& joystickStates(); + const JoystickCameraStates& joystickStates() const; bool followingNodeRotation() const; const SceneGraphNode* anchorNode() const; @@ -146,10 +150,9 @@ private: const SceneGraphNode* _anchorNode = nullptr; const SceneGraphNode* _aimNode = nullptr; - glm::dvec3 _previousAnchorNodePosition; - glm::dquat _previousAnchorNodeRotation; - - glm::dvec3 _previousAimNodePosition; + std::optional_previousAnchorNodePosition; + std::optional _previousAnchorNodeRotation; + std::optional _previousAimNodePosition; double _currentCameraToSurfaceDistance = 0.0; bool _directlySetStereoDistance = false; diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index e17d676b3e..e5cc4fd5f4 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -338,16 +339,24 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { "goToGeo", &globebrowsing::luascriptfunctions::goToGeo, {}, - "number, number, number", - "Go to geographic coordinates latitude and longitude" + "[string], number, number, [number]", + "Go to geographic coordinates of a globe. The first (optional) argument is " + "the identifier of a scene graph node that has a RenderableGlobe attached. " + "If no globe is passed in, the current anchor will be used. " + "The second argument is latitude and the third is longitude (degrees). " + "North and East are expressed as positive angles, while South and West are " + "negative. The optional fourh argument is the altitude in meters. If no " + "altitude is provided, the altitude will be kept as the current distance to " + "the surface of the specified globe." }, { "getGeoPosition", &globebrowsing::luascriptfunctions::getGeoPosition, {}, - "name, latitude, longitude, altitude", - "Returns the specified surface position on the globe as three floating point " - "values" + "string, number, number, number", + "Returns the specified surface position on the globe identified by the first " + "argument, as three floating point values - latitude, longitude and altitude " + "(degrees and meters)." }, { "getGeoPositionForCamera", @@ -355,7 +364,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { {}, "void", "Get geographic coordinates of the camera poosition in latitude, " - "longitude, and altitude" + "longitude, and altitude (degrees and meters)." }, { "loadWMSCapabilities", @@ -395,29 +404,29 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { return res; } -void GlobeBrowsingModule::goToChunk(int x, int y, int level) { - Camera* cam = global::navigationHandler.camera(); - goToChunk(*cam, globebrowsing::TileIndex(x,y,level), glm::vec2(0.5f, 0.5f), true); +void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe, + int x, int y, int level) +{ + goToChunk(globe, globebrowsing::TileIndex(x, y, level), glm::vec2(0.5f, 0.5f), true); } -void GlobeBrowsingModule::goToGeo(double latitude, double longitude) { +void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude) +{ using namespace globebrowsing; - Camera* cam = global::navigationHandler.camera(); goToGeodetic2( - *cam, + globe, Geodetic2{ glm::radians(latitude), glm::radians(longitude) }, true ); } -void GlobeBrowsingModule::goToGeo(double latitude, double longitude, - double altitude) +void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude, double altitude) { using namespace globebrowsing; - - Camera* cam = global::navigationHandler.camera(); goToGeodetic3( - *cam, + globe, { Geodetic2{ glm::radians(latitude), glm::radians(longitude) }, altitude @@ -437,32 +446,15 @@ glm::vec3 GlobeBrowsingModule::cartesianCoordinatesFromGeo( altitude }; - const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianPosition(pos); - //glm::dmat4 modelTransform = globe.modelTransform(); - //glm::dvec3 positionWorldSpace = glm::dvec3(modelTransform * - //glm::dvec4(positionModelSpace, 1.0)); - - return glm::vec3(positionModelSpace); + return glm::vec3(globe.ellipsoid().cartesianPosition(pos)); } -void GlobeBrowsingModule::goToChunk(Camera& camera, const globebrowsing::TileIndex& ti, +void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe, + const globebrowsing::TileIndex& ti, glm::vec2 uv, bool doResetCameraDirection) { using namespace globebrowsing; - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; - } - - // Camera position in model space - const glm::dvec3 camPos = camera.positionVec3(); - const glm::dmat4 inverseModelTransform = glm::inverse(globe->modelTransform()); - const glm::dvec3 cameraPositionModelSpace = glm::dvec3( - inverseModelTransform * glm::dvec4(camPos, 1) - ); - const GeodeticPatch patch(ti); const Geodetic2 corner = patch.corner(SOUTH_WEST); Geodetic2 positionOnPatch = patch.size(); @@ -473,32 +465,50 @@ void GlobeBrowsingModule::goToChunk(Camera& camera, const globebrowsing::TileInd corner.lon + positionOnPatch.lon }; - const glm::dvec3 positionOnEllipsoid = globe->ellipsoid().geodeticSurfaceProjection( + // Compute altitude + const glm::dvec3 cameraPosition = global::navigationHandler.camera()->positionVec3(); + SceneGraphNode* globeSceneGraphNode = dynamic_cast(globe.owner()); + if (!globeSceneGraphNode) { + LERROR( + "Cannot go to chunk. The renderable is not attached to a scene graph node." + ); + return; + } + const glm::dmat4 inverseModelTransform = globeSceneGraphNode->inverseModelTransform(); + const glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1.0)); + const SurfacePositionHandle posHandle = globe.calculateSurfacePositionHandle( cameraPositionModelSpace ); - const double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); + + const Geodetic2 geo2 = globe.ellipsoid().cartesianToGeodetic2( + posHandle.centerToReferenceSurface + ); - goToGeodetic3(camera, {pointPosition, altitude}, doResetCameraDirection); + const double altitude = glm::length( + cameraPositionModelSpace - posHandle.centerToReferenceSurface + ); + + goToGeodetic3(globe, { pointPosition, altitude }, doResetCameraDirection); } -void GlobeBrowsingModule::goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, +void GlobeBrowsingModule::goToGeodetic2(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic2 geo2, bool doResetCameraDirection) { using namespace globebrowsing; - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; + const glm::dvec3 cameraPosition = global::navigationHandler.camera()->positionVec3(); + SceneGraphNode* globeSceneGraphNode = dynamic_cast(globe.owner()); + if (!globeSceneGraphNode) { + LERROR("Error when going to Geodetic2"); } - interaction::NavigationHandler& nav = global::navigationHandler; - const glm::dvec3 cameraPosition = nav.camera()->positionVec3(); - const glm::dmat4 inverseModelTransform = - nav.orbitalNavigator().anchorNode()->inverseModelTransform(); + const glm::dmat4 inverseModelTransform = globeSceneGraphNode->inverseModelTransform(); + const glm::dvec3 cameraPositionModelSpace = glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1.0)); - const SurfacePositionHandle posHandle = globe->calculateSurfacePositionHandle( + const SurfacePositionHandle posHandle = globe.calculateSurfacePositionHandle( cameraPositionModelSpace ); @@ -506,71 +516,58 @@ void GlobeBrowsingModule::goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 posHandle.referenceSurfaceOutDirection * posHandle.heightToSurface; const double altitude = glm::length(cameraPositionModelSpace - centerToActualSurface); - goToGeodetic3(camera, { geo2, altitude }, doResetCameraDirection); + goToGeodetic3(globe, { geo2, altitude }, doResetCameraDirection); } -void GlobeBrowsingModule::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, +void GlobeBrowsingModule::goToGeodetic3(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic3 geo3, bool doResetCameraDirection) { using namespace globebrowsing; + const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianPosition(geo3); - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; - } - const glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianPosition(geo3); - const glm::dmat4 modelTransform = globe->modelTransform(); - const glm::dvec3 positionWorldSpace = glm::dvec3(modelTransform * - glm::dvec4(positionModelSpace, 1.0)); - camera.setPositionVec3(positionWorldSpace); + const glm::dvec3 slightlyNorth = globe.ellipsoid().cartesianSurfacePosition( + Geodetic2{ geo3.geodetic2.lat + 0.001, geo3.geodetic2.lon } + ); - if (doResetCameraDirection) { - resetCameraDirection(camera, geo3.geodetic2); - } + interaction::NavigationHandler::NavigationState state; + state.anchor = globe.owner()->identifier(); + state.referenceFrame = globe.owner()->identifier(); + state.position = positionModelSpace; + state.up = slightlyNorth; + + global::navigationHandler.setNavigationStateNextFrame(state); } -void GlobeBrowsingModule::resetCameraDirection(Camera& camera, - globebrowsing::Geodetic2 geo2) +glm::dquat GlobeBrowsingModule::lookDownCameraRotation( + const globebrowsing::RenderableGlobe& globe, + glm::dvec3 cameraModelSpace, + globebrowsing::Geodetic2 geo2) { using namespace globebrowsing; - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; - } - // Camera is described in world space - const glm::dmat4 modelTransform = globe->modelTransform(); + const glm::dmat4 modelTransform = globe.modelTransform(); // Lookup vector - const glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianSurfacePosition( + const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianSurfacePosition( geo2 ); - const glm::dvec3 slightlyNorth = globe->ellipsoid().cartesianSurfacePosition( + const glm::dvec3 slightlyNorth = globe.ellipsoid().cartesianSurfacePosition( Geodetic2{ geo2.lat + 0.001, geo2.lon } ); const glm::dvec3 lookUpModelSpace = glm::normalize( slightlyNorth - positionModelSpace ); - const glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace; - - // Lookat vector - const glm::dvec3 lookAtWorldSpace = glm::dvec3( - modelTransform * glm::dvec4(positionModelSpace, 1.0) - ); - - // Eye position - const glm::dvec3 eye = camera.positionVec3(); // Matrix - const glm::dmat4 lookAtMatrix = glm::lookAt(eye, lookAtWorldSpace, lookUpWorldSpace); + const glm::dmat4 lookAtMatrix = + glm::lookAt(cameraModelSpace, positionModelSpace, lookUpModelSpace); // Set rotation const glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix)); - camera.setRotation(rotation); + return rotation; } const globebrowsing::RenderableGlobe* @@ -732,5 +729,4 @@ uint64_t GlobeBrowsingModule::wmsCacheSize() const { return size * 1024 * 1024; } - } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 9db83196a9..fc96cd91c4 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -53,9 +53,12 @@ public: GlobeBrowsingModule(); - void goToChunk(int x, int y, int level); - void goToGeo(double latitude, double longitude); - void goToGeo(double latitude, double longitude, double altitude); + void goToChunk(const globebrowsing::RenderableGlobe& globe, int x, int y, int level); + void goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude); + + void goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude, double altitude); glm::vec3 cartesianCoordinatesFromGeo(const globebrowsing::RenderableGlobe& globe, double latitude, double longitude, double altitude); @@ -94,13 +97,17 @@ protected: void internalInitialize(const ghoul::Dictionary&) override; private: - void goToChunk(Camera& camera, const globebrowsing::TileIndex& ti, glm::vec2 uv, - bool doResetCameraDirection); - void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, - bool doResetCameraDirection); - void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, - bool doResetCameraDirection); - void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); + void goToChunk(const globebrowsing::RenderableGlobe& globe, + const globebrowsing::TileIndex& ti, glm::vec2 uv, bool doResetCameraDirection); + + void goToGeodetic2(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic2 geo2, bool doResetCameraDirection); + + void goToGeodetic3(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic3 geo3, bool doResetCameraDirection); + + glm::dquat lookDownCameraRotation(const globebrowsing::RenderableGlobe& globe, + glm::dvec3 cameraPositionModelSpace, globebrowsing::Geodetic2 geo2); /** \return a comma separated list of layer group names. diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index b9928a119f..0c6479b211 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -128,31 +128,79 @@ int deleteLayer(lua_State* L) { } int goToChunk(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::goToChunk"); + ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::goToChunk"); - const int x = ghoul::lua::value(L, 1); - const int y = ghoul::lua::value(L, 2); - const int level = ghoul::lua::value(L, 3); - lua_pop(L, 3); + const std::string& globeIdentifier = ghoul::lua::value(L, 1); + const int x = ghoul::lua::value(L, 2); + const int y = ghoul::lua::value(L, 3); + const int level = ghoul::lua::value(L, 4); + lua_pop(L, 4); - global::moduleEngine.module()->goToChunk(x, y, level); + SceneGraphNode* n = sceneGraphNode(globeIdentifier); + if (!n) { + return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + } + + const RenderableGlobe* globe = dynamic_cast(n->renderable()); + if (!globe) { + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + } + + global::moduleEngine.module()->goToChunk(*globe, x, y, level); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int goToGeo(lua_State* L) { - const int nArguments = ghoul::lua::checkArgumentsAndThrow(L, 2, 3, "lua::goToGeo"); + const int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo"); - const double latitude = ghoul::lua::value(L, 1); - const double longitude = ghoul::lua::value(L, 2); + // Check if the user provided a Scene graph node identifier as the first argument. + // lua_isstring returns true for both numbers and strings, so better use !lua_isnumber + const bool providedGlobeIdentifier = !lua_isnumber(L, 1); + const int parameterOffset = providedGlobeIdentifier ? 1 : 0; - if (nArguments == 2) { - global::moduleEngine.module()->goToGeo(latitude, longitude); + const SceneGraphNode* n; + if (providedGlobeIdentifier) { + const std::string& globeIdentifier = ghoul::lua::value(L, 1); + n = sceneGraphNode(globeIdentifier); + if (!n) { + return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + } } - else if (nArguments == 3) { - const double altitude = ghoul::lua::value(L, 3); + else { + n = global::navigationHandler.orbitalNavigator().anchorNode(); + if (!n) { + return ghoul::lua::luaError(L, "No anchor node is set."); + } + } + + const double latitude = ghoul::lua::value(L, parameterOffset + 1); + const double longitude = ghoul::lua::value(L, parameterOffset + 2); + + const RenderableGlobe* globe = dynamic_cast(n->renderable()); + if (!globe) { + if (providedGlobeIdentifier) { + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + } + else { + return ghoul::lua::luaError(L, + "Current anchor node is not a RenderableGlobe. " + "Either change the anchor to a globe, or specify a globe identifier " + "as the first argument" + ); + } + } + + if (nArguments == parameterOffset + 2) { global::moduleEngine.module()->goToGeo( + *globe, latitude, longitude + ); + } + else if (nArguments == parameterOffset + 3) { + const double altitude = ghoul::lua::value(L, parameterOffset + 3); + global::moduleEngine.module()->goToGeo( + *globe, latitude, longitude, altitude @@ -168,19 +216,19 @@ int goToGeo(lua_State* L) { int getGeoPosition(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::getGeoPosition"); - const std::string& name = ghoul::lua::value(L, 1); + const std::string& globeIdentifier = ghoul::lua::value(L, 1); const double latitude = ghoul::lua::value(L, 2); const double longitude = ghoul::lua::value(L, 3); const double altitude = ghoul::lua::value(L, 4); lua_pop(L, 4); - SceneGraphNode* n = sceneGraphNode(name); + SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + name); + return ghoul::lua::luaError(L, "Unknown globe identifier: " + globeIdentifier); } const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Name must be a RenderableGlobe"); + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); } GlobeBrowsingModule& mod = *(global::moduleEngine.module()); diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index d1ffd5d624..cae9cc2381 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -161,6 +161,11 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) _latitude.onChange([this]() { _positionIsDirty = true; }); _fixedAltitude.onChange([this]() { _positionIsDirty = true; }); _useFixedAltitude.onChange([this]() { _positionIsDirty = true; }); + + addProperty(_longitude); + addProperty(_latitude); + addProperty(_fixedAltitude); + addProperty(_useFixedAltitude); } void GlobeTranslation::fillAttachedNode() { diff --git a/recordings/apollo8 b/recordings/apollo8 deleted file mode 100644 index c9cafbdcaac57d01aa5cf35d5406fef593b8d869..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5994 zcmb{0?Nd~B6u|M76qF{|)C_?^OvZ48Wrd;0(p?fATBHa{Nh!bs!=vmDi^+oFf@K;q zC50O1NMa5M8R|}fq%5#tusnnEEFupTg<>!*ghux;bMhZJ_syMq=g#*t=e)Y}drK9W z5Tpu+$k4<{P$ovWsp7*md%_`3DwTM7zHSMc2kD>N)+NbBTIqrmk3+J_cNAk`E{&BU z;VKw*l?ykm*iDZ2V9#D3y}3xFe|yibGO_SJqj5+!IX5@3*1c6`D-t6)6=Cec8hgX(4y4E1% zXzz_XiOYg%(wpe$Nh3A5KPWvR_ayKok2-8=FhmA?ib+t2kATka&rc zbB&H2qCVU`x_2fTA#KCVGyXrZL)3@zrV0IRgrv5T!|QIaL)3@BThSvHMgeN^?i@X% zXNRZ{Dc^qOun{3~zGsPB6+1+ISTnOi7K2c5n6Iv&njNA(=RKRw&hhB z`w>!o{oP9co9qzv;oN$|z!X9OQU6K4c#ct6GIn z%bJ{~kUI8>s1MOQnv!2eNUL}%!?vCsqCS`v-f(&op@4x;2AlaI>O*$w>eUhRt5bht zIA~;_i25L(7`%5FA^FO@wwwlbi25+292T8LXz}y9svV8&5cR>ubxHnJgz`i^?X&z4 z^}%7x{O&`9q`%!PA8%%#i27h0>G5@H6rhHC9_jiPc8L0LcGB1-N66lGS}*)VbN_o& zA2v+QnvNh8VPCo_sEr+>KE&E-1}`DxTUIl~i27g}FO)%Z#9#$Nr^+%%B%SONQ6Hq~*+;t&3JX~J z@o|2L`rv;j&S@N>4#WNjL;Mi+VRq-%z&V7D74=_m>0)0U^c+xz(;>cd%Sn%8E8?5!$g&fV;*qdvTGGE5VQkfA`aMZ*tKAA;=4 zMk5jWv$S}+mLH-%G<$X}N=2yeg?0Pvde~P-eW)vWJpIM|>Z~ff)%+0kA>&2+@e2qQ z{O+~X$PZB;GW~q6lq1xj>0ay5%f345gL&G|rY3|+w_JNIjvt~vdm_9Z4bDurWhH6CkA)RAg+j4~l`{&YJgAxff7 fQmX!ca$X0e2feR^U{R}RT6^wE5o;U=+|>UMgyQg7 diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 3d7e026b94..1d8de7effb 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -58,6 +58,9 @@ namespace openspace { void registerCoreClasses(documentation::DocumentationEngine& engine) { engine.addDocumentation(LogFactoryDocumentation()); engine.addDocumentation(Mission::Documentation()); + engine.addDocumentation( + interaction::NavigationHandler::NavigationState::Documentation() + ); engine.addDocumentation(Renderable::Documentation()); engine.addDocumentation(Rotation::Documentation()); engine.addDocumentation(Scale::Documentation()); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 52a268ca12..b1473854a8 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1013,8 +1013,6 @@ void OpenSpaceEngine::preSynchronization() { } global::renderEngine.updateScene(); - //_navigationHandler->updateCamera(dt); - if (_scene) { Camera* camera = _scene->camera(); diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp index c9b765a545..f4f0c21dc9 100644 --- a/src/interaction/navigationhandler.cpp +++ b/src/interaction/navigationhandler.cpp @@ -27,14 +27,17 @@ #include #include #include -#include -#include -#include #include +#include +#include #include +#include +#include #include #include #include +#include +#include #include namespace { @@ -43,7 +46,11 @@ namespace { constexpr const char* KeyAnchor = "Anchor"; constexpr const char* KeyAim = "Aim"; constexpr const char* KeyPosition = "Position"; - constexpr const char* KeyRotation = "Rotation"; + constexpr const char* KeyUp = "Up"; + constexpr const char* KeyYaw = "Yaw"; + constexpr const char* KeyPitch = "Pitch"; + constexpr const char* KeyReferenceFrame = "ReferenceFrame"; + const double Epsilon = 1E-7; constexpr const openspace::properties::Property::PropertyInfo KeyFrameInfo = { "UseKeyFrameInteraction", @@ -51,24 +58,101 @@ namespace { "If this is set to 'true' the entire interaction is based off key frames rather " "than using the mouse interaction." }; + } // namespace #include "navigationhandler_lua.inl" namespace openspace::interaction { + +ghoul::Dictionary +openspace::interaction::NavigationHandler::NavigationState::dictionary() const +{ + ghoul::Dictionary cameraDict; + cameraDict.setValue(KeyPosition, position); + cameraDict.setValue(KeyAnchor, anchor); + + if (anchor != referenceFrame) { + cameraDict.setValue(KeyReferenceFrame, referenceFrame); + } + if (!aim.empty()) { + cameraDict.setValue(KeyAim, aim); + } + if (up.has_value()) { + cameraDict.setValue(KeyUp, up.value()); + + if (std::abs(yaw) > Epsilon) { + cameraDict.setValue(KeyYaw, yaw); + } + if (std::abs(pitch) > Epsilon) { + cameraDict.setValue(KeyPitch, pitch); + } + } + + return cameraDict; +} + +openspace::interaction::NavigationHandler::NavigationState::NavigationState( + const ghoul::Dictionary& dictionary) +{ + const bool hasAnchor = dictionary.hasValue(KeyAnchor); + const bool hasPosition = dictionary.hasValue(KeyPosition); + if (!hasAnchor || !hasPosition) { + throw ghoul::RuntimeError( + "Position and Anchor need to be defined for navigation dictionary." + ); + } + + anchor = dictionary.value(KeyAnchor); + position = dictionary.value(KeyPosition); + + if (dictionary.hasValue(KeyReferenceFrame)) { + referenceFrame = dictionary.value(KeyReferenceFrame); + } + else { + referenceFrame = anchor; + } + if (dictionary.hasValue(KeyAim)) { + aim = dictionary.value(KeyAim); + } + + if (dictionary.hasValue(KeyUp)) { + up = dictionary.value(KeyUp); + + if (dictionary.hasValue(KeyYaw)) { + yaw = dictionary.value(KeyYaw); + } + if (dictionary.hasValue(KeyPitch)) { + pitch = dictionary.value(KeyPitch); + } + } +} + +openspace::interaction::NavigationHandler::NavigationState::NavigationState( + std::string anchor, + std::string aim, + std::string referenceFrame, + glm::dvec3 position, + std::optional up, + double yaw, + double pitch) + : anchor(std::move(anchor)) + , aim(std::move(aim)) + , referenceFrame(std::move(referenceFrame)) + , position(std::move(position)) + , up(std::move(up)) + , yaw(yaw) + , pitch(pitch) +{} + NavigationHandler::NavigationHandler() : properties::PropertyOwner({ "NavigationHandler" }) , _useKeyFrameInteraction(KeyFrameInfo, false) { - - _inputState = std::make_unique(); - _orbitalNavigator = std::make_unique(); - _keyframeNavigator = std::make_unique(); - // Add the properties addProperty(_useKeyFrameInteraction); - addPropertySubOwner(*_orbitalNavigator); + addPropertySubOwner(_orbitalNavigator); } NavigationHandler::~NavigationHandler() {} // NOLINT @@ -90,19 +174,25 @@ void NavigationHandler::deinitialize() { void NavigationHandler::setCamera(Camera* camera) { _camera = camera; - _orbitalNavigator->setCamera(camera); + _orbitalNavigator.setCamera(camera); } -const OrbitalNavigator& NavigationHandler::orbitalNavigator() const { - return *_orbitalNavigator; +void NavigationHandler::setNavigationStateNextFrame( + NavigationHandler::NavigationState state) +{ + _pendingNavigationState = std::move(state); } OrbitalNavigator& NavigationHandler::orbitalNavigator() { - return *_orbitalNavigator; + return _orbitalNavigator; } -KeyframeNavigator& NavigationHandler::keyframeNavigator() const { - return *_keyframeNavigator; +const OrbitalNavigator& NavigationHandler::orbitalNavigator() const { + return _orbitalNavigator; +} + +KeyframeNavigator& NavigationHandler::keyframeNavigator() { + return _keyframeNavigator; } bool NavigationHandler::isKeyFrameInteractionEnabled() const { @@ -110,33 +200,93 @@ bool NavigationHandler::isKeyFrameInteractionEnabled() const { } float NavigationHandler::interpolationTime() const { - return _orbitalNavigator->retargetInterpolationTime(); + return _orbitalNavigator.retargetInterpolationTime(); } void NavigationHandler::setInterpolationTime(float durationInSeconds) { - _orbitalNavigator->setRetargetInterpolationTime(durationInSeconds); + _orbitalNavigator.setRetargetInterpolationTime(durationInSeconds); } void NavigationHandler::updateCamera(double deltaTime) { - ghoul_assert(_inputState != nullptr, "InputState must not be nullptr"); ghoul_assert(_camera != nullptr, "Camera must not be nullptr"); - if (_cameraUpdatedFromScript) { - _cameraUpdatedFromScript = false; - } - else { - if (!_playbackModeEnabled && _camera) { - if (_useKeyFrameInteraction) { - _keyframeNavigator->updateCamera(*_camera, _playbackModeEnabled); - } - else { - _orbitalNavigator->updateStatesFromInput(*_inputState, deltaTime); - _orbitalNavigator->updateCameraStateFromStates(deltaTime); - } + if (_pendingNavigationState.has_value()) { + applyNavigationState(_pendingNavigationState.value()); + _orbitalNavigator.resetVelocities(); + _pendingNavigationState.reset(); + } else if (!_playbackModeEnabled && _camera) { + if (_useKeyFrameInteraction) { + _keyframeNavigator.updateCamera(*_camera, _playbackModeEnabled); + } + else { + _orbitalNavigator.updateStatesFromInput(_inputState, deltaTime); + _orbitalNavigator.updateCameraStateFromStates(deltaTime); } } } +void NavigationHandler::applyNavigationState(const NavigationHandler::NavigationState& ns) +{ + const SceneGraphNode* referenceFrame = sceneGraphNode(ns.referenceFrame); + const SceneGraphNode* anchor = sceneGraphNode(ns.anchor); + + if (!anchor) { + LERROR(fmt::format( + "Could not find scene graph node '{}' used as anchor.", ns.referenceFrame + )); + return; + } + if (!ns.aim.empty() && !sceneGraphNode(ns.aim)) { + LERROR(fmt::format( + "Could not find scene graph node '{}' used as aim.", ns.referenceFrame + )); + return; + } + if (!referenceFrame) { + LERROR(fmt::format( + "Could not find scene graph node '{}' used as reference frame.", + ns.referenceFrame) + ); + return; + } + + const glm::dvec3 anchorWorldPosition = anchor->worldPosition(); + const glm::dmat3 referenceFrameTransform = referenceFrame->worldRotationMatrix(); + + _orbitalNavigator.setAnchorNode(ns.anchor); + _orbitalNavigator.setAimNode(ns.aim); + + const SceneGraphNode* anchorNode = _orbitalNavigator.anchorNode(); + const SceneGraphNode* aimNode = _orbitalNavigator.aimNode(); + if (!aimNode) { + aimNode = anchorNode; + } + + const glm::dvec3 cameraPositionWorld = anchorWorldPosition + + glm::dvec3(referenceFrameTransform * glm::dvec4(ns.position, 1.0)); + + glm::dvec3 up = ns.up.has_value() ? + glm::normalize(referenceFrameTransform * ns.up.value()) : + glm::dvec3(0.0, 1.0, 0.0); + + // Construct vectors of a "neutral" view, i.e. when the aim is centered in view. + glm::dvec3 neutralView = + glm::normalize(aimNode->worldPosition() - cameraPositionWorld); + + glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt( + glm::dvec3(0.0), + neutralView, + up + ))); + + glm::dquat pitchRotation = glm::angleAxis(ns.pitch, glm::dvec3(1.f, 0.f, 0.f)); + glm::dquat yawRotation = glm::angleAxis(ns.yaw, glm::dvec3(0.f, -1.f, 0.f)); + + _camera->setPositionVec3(cameraPositionWorld); + _camera->setRotation(neutralCameraRotation * yawRotation * pitchRotation); + _orbitalNavigator.clearPreviousState(); +} + void NavigationHandler::setEnableKeyFrameInteraction() { _useKeyFrameInteraction = true; } @@ -150,8 +300,8 @@ void NavigationHandler::triggerPlaybackStart() { } void NavigationHandler::stopPlayback() { - _orbitalNavigator->resetVelocities(); - _orbitalNavigator->resetNodeMovements(); + _orbitalNavigator.resetVelocities(); + _orbitalNavigator.resetNodeMovements(); _playbackModeEnabled = false; } @@ -160,131 +310,120 @@ Camera* NavigationHandler::camera() const { } const InputState& NavigationHandler::inputState() const { - return *_inputState; + return _inputState; } void NavigationHandler::mouseButtonCallback(MouseButton button, MouseAction action) { - _inputState->mouseButtonCallback(button, action); + _inputState.mouseButtonCallback(button, action); } void NavigationHandler::mousePositionCallback(double x, double y) { - _inputState->mousePositionCallback(x, y); + _inputState.mousePositionCallback(x, y); } void NavigationHandler::mouseScrollWheelCallback(double pos) { - _inputState->mouseScrollWheelCallback(pos); + _inputState.mouseScrollWheelCallback(pos); } void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { - _inputState->keyboardCallback(key, modifier, action); + _inputState.keyboardCallback(key, modifier, action); } -void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) +NavigationHandler::NavigationState NavigationHandler::navigationState( + const SceneGraphNode& referenceFrame) const { - bool readSuccessful = true; + const SceneGraphNode* anchor = _orbitalNavigator.anchorNode(); + const SceneGraphNode* aim = _orbitalNavigator.aimNode(); - std::string anchor; - std::string aim; - glm::dvec3 cameraPosition; - glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first. - - readSuccessful &= cameraDict.getValue(KeyAnchor, anchor); - readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition); - readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation); - cameraDict.getValue(KeyAim, aim); // Aim is not required - - if (!readSuccessful) { - throw ghoul::RuntimeError( - "Position, Rotation and Focus need to be defined for camera dictionary." - ); + if (!aim) { + aim = anchor; } - // Set state - _orbitalNavigator->setAnchorNode(anchor); - _orbitalNavigator->setAimNode(aim); + const glm::dquat invNeutralRotation = glm::quat_cast(glm::lookAt( + glm::dvec3(0.0, 0.0, 0.0), + aim->worldPosition() - _camera->positionVec3(), + glm::normalize(_camera->lookUpVectorWorldSpace()) + )); - _camera->setPositionVec3(cameraPosition); - _camera->setRotation(glm::dquat( - cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w)); + glm::dquat localRotation = invNeutralRotation * _camera->rotationQuaternion(); + glm::dvec3 eulerAngles = glm::eulerAngles(localRotation); + + const double pitch = eulerAngles.x; + const double yaw = -eulerAngles.y; + + // Need to compensate by redisual roll left in local rotation: + const glm::dquat unroll = glm::angleAxis(eulerAngles.z, glm::dvec3(0, 0, 1)); + const glm::dvec3 neutralUp = + glm::inverse(invNeutralRotation) * unroll * _camera->lookUpVectorCameraSpace(); + + const glm::dmat3 invReferenceFrameTransform = + glm::inverse(referenceFrame.worldRotationMatrix()); + + const glm::dvec3 position = invReferenceFrameTransform * + (glm::dvec4(_camera->positionVec3() - anchor->worldPosition(), 1.0)); + + return NavigationState( + _orbitalNavigator.anchorNode()->identifier(), + _orbitalNavigator.aimNode() ? + _orbitalNavigator.aimNode()->identifier() : "", + referenceFrame.identifier(), + position, + invReferenceFrameTransform * neutralUp, yaw, pitch + ); } -ghoul::Dictionary NavigationHandler::cameraStateDictionary() { - glm::dvec3 cameraPosition; - glm::dquat quat; - glm::dvec4 cameraRotation; +void NavigationHandler::saveNavigationState(const std::string& filepath, + const std::string& referenceFrameIdentifier) +{ + const SceneGraphNode* referenceFrame = _orbitalNavigator.followingNodeRotation() ? + _orbitalNavigator.anchorNode() : + sceneGraph()->root(); - cameraPosition = _camera->positionVec3(); - quat = _camera->rotationQuaternion(); - cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z); - - ghoul::Dictionary cameraDict; - cameraDict.setValue(KeyPosition, cameraPosition); - cameraDict.setValue(KeyRotation, cameraRotation); - cameraDict.setValue(KeyAnchor, _orbitalNavigator->anchorNode()->identifier()); - if (_orbitalNavigator->aimNode()) { - cameraDict.setValue(KeyAim, _orbitalNavigator->aimNode()->identifier()); - } - - return cameraDict; -} - -void NavigationHandler::saveCameraStateToFile(const std::string& filepath) { - if (!filepath.empty()) { - std::string fullpath = absPath(filepath); - LINFO(fmt::format("Saving camera position: {}", filepath)); - - ghoul::Dictionary cameraDict = cameraStateDictionary(); - - // TODO(abock): Should get the camera state as a dictionary and save the - // dictionary to a file in form of a lua state and not use ofstreams here. - - std::ofstream ofs(fullpath.c_str()); - - glm::dvec3 p = _camera->positionVec3(); - glm::dquat q = _camera->rotationQuaternion(); - - ofs << "return {" << std::endl; - ofs << " " << KeyAnchor << " = " << "\"" << - _orbitalNavigator->anchorNode()->identifier() << "\"" - << "," << std::endl; - - if (_orbitalNavigator->aimNode()) { - ofs << " " << KeyAim << " = " << "\"" << - _orbitalNavigator->aimNode()->identifier() << "\"" - << "," << std::endl; + if (!referenceFrameIdentifier.empty()) { + referenceFrame = sceneGraphNode(referenceFrameIdentifier); + if (!referenceFrame) { + LERROR(fmt::format( + "Could not find node '{}' to use as reference frame", + referenceFrameIdentifier + )); + return; } + } - ofs << " " << KeyPosition << " = {" - << std::to_string(p.x) << ", " - << std::to_string(p.y) << ", " - << std::to_string(p.z) << "}," << std::endl; - ofs << " " << KeyRotation << " = {" - << std::to_string(q.w) << ", " - << std::to_string(q.x) << ", " - << std::to_string(q.y) << ", " - << std::to_string(q.z) << "}," << std::endl; - ofs << "}"<< std::endl; + if (!filepath.empty()) { + std::string absolutePath = absPath(filepath); + LINFO(fmt::format("Saving camera position: {}", absolutePath)); + ghoul::Dictionary cameraDict = navigationState(*referenceFrame).dictionary(); + ghoul::DictionaryLuaFormatter formatter; + + std::ofstream ofs(absolutePath.c_str()); + ofs << "return " << formatter.format(cameraDict); ofs.close(); } } -void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath) { - LINFO(fmt::format("Reading camera state from file: {}", filepath)); - if (!FileSys.fileExists(filepath)) { - throw ghoul::FileNotFoundError(filepath, "CameraFilePath"); +void NavigationHandler::loadNavigationState(const std::string& filepath) { + const std::string absolutePath = absPath(filepath); + LINFO(fmt::format("Reading camera state from file: {}", absolutePath)); + + if (!FileSys.fileExists(absolutePath)) { + throw ghoul::FileNotFoundError(absolutePath, "NavigationState"); } - ghoul::Dictionary cameraDict; + ghoul::Dictionary navigationStateDictionary; try { - ghoul::lua::loadDictionaryFromFile(filepath, cameraDict); - setCameraStateFromDictionary(cameraDict); - _cameraUpdatedFromScript = true; + ghoul::lua::loadDictionaryFromFile(absolutePath, navigationStateDictionary); + openspace::documentation::testSpecificationAndThrow( + NavigationState::Documentation(), + navigationStateDictionary, + "NavigationState" + ); + setNavigationStateNextFrame(NavigationState(navigationStateDictionary)); } catch (ghoul::RuntimeError& e) { - LWARNING("Unable to set camera position"); - LWARNING(e.message); + LERROR(fmt::format("Unable to set camera position: {}", e.message)); } } @@ -293,7 +432,7 @@ void NavigationHandler::setJoystickAxisMapping(int axis, JoystickCameraStates::AxisInvert shouldInvert, JoystickCameraStates::AxisNormalize shouldNormalize) { - _orbitalNavigator->joystickStates().setAxisMapping( + _orbitalNavigator.joystickStates().setAxisMapping( axis, mapping, shouldInvert, @@ -304,15 +443,15 @@ void NavigationHandler::setJoystickAxisMapping(int axis, JoystickCameraStates::AxisInformation NavigationHandler::joystickAxisMapping(int axis) const { - return _orbitalNavigator->joystickStates().axisMapping(axis); + return _orbitalNavigator.joystickStates().axisMapping(axis); } void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) { - _orbitalNavigator->joystickStates().setDeadzone(axis, deadzone); + _orbitalNavigator.joystickStates().setDeadzone(axis, deadzone); } float NavigationHandler::joystickAxisDeadzone(int axis) const { - return _orbitalNavigator->joystickStates().deadzone(axis); + return _orbitalNavigator.joystickStates().deadzone(axis); } void NavigationHandler::bindJoystickButtonCommand(int button, std::string command, @@ -320,7 +459,7 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman JoystickCameraStates::ButtonCommandRemote remote, std::string documentation) { - _orbitalNavigator->joystickStates().bindButtonCommand( + _orbitalNavigator.joystickStates().bindButtonCommand( button, std::move(command), action, @@ -330,11 +469,68 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman } void NavigationHandler::clearJoystickButtonCommand(int button) { - _orbitalNavigator->joystickStates().clearButtonCommand(button); + _orbitalNavigator.joystickStates().clearButtonCommand(button); } std::vector NavigationHandler::joystickButtonCommand(int button) const { - return _orbitalNavigator->joystickStates().buttonCommand(button); + return _orbitalNavigator.joystickStates().buttonCommand(button); +} + +documentation::Documentation NavigationHandler::NavigationState::Documentation() { + using namespace documentation; + + return { + "Navigation State", + "core_navigation_state", + { + { + KeyAnchor, + new StringVerifier, + Optional::No, + "The identifier of the anchor node." + }, + { + KeyAim, + new StringVerifier, + Optional::Yes, + "The identifier of the aim node, if used." + }, + { + KeyReferenceFrame, + new StringVerifier, + Optional::Yes, + "The identifier of the scene graph node to use as reference frame. " + "If not specified, this will be the same as the anchor." + }, + { + KeyPosition, + new DoubleVector3Verifier, + Optional::No, + "The position of the camera relative to the anchor node, " + "expressed in meters in the specified reference frame." + }, + { + KeyUp, + new DoubleVector3Verifier, + Optional::Yes, + "The up vector expressed in the coordinate system of the reference frame." + }, + { + KeyYaw, + new DoubleVerifier, + Optional::Yes, + "The yaw angle in radians. " + "Positive angle means yawing camera to the right." + }, + { + KeyPitch, + new DoubleVerifier, + Optional::Yes, + "The pitch angle in radians. " + "Positive angle means pitching camera upwards." + }, + } + }; } scripting::LuaLibrary NavigationHandler::luaLibrary() { @@ -342,25 +538,33 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() { "navigation", { { - "setCameraState", - &luascriptfunctions::setCameraState, + "setNavigationState", + &luascriptfunctions::setNavigationState, {}, - "object", - "Set the camera state" + "table", + "Set the navigation state. " + "The argument must be a valid Navigation State." }, { - "saveCameraStateToFile", - &luascriptfunctions::saveCameraStateToFile, + "saveNavigationState", + &luascriptfunctions::saveNavigationState, {}, - "string", - "Save the current camera state to file" + "string, [string]", + "Save the current navigation state to a file with the path given by the " + "first argument. The optoinal second argument is the scene graph node to " + "use as reference frame. By default, the reference frame will picked " + "based on whether the orbital navigator is currently following the " + "anchor node rotation. If it is, the anchor will be chosen as reference " + "frame. If not, the reference frame will be set to the scene graph root." }, { - "restoreCameraStateFromFile", - &luascriptfunctions::restoreCameraStateFromFile, + "loadNavigationState", + &luascriptfunctions::loadNavigationState, {}, "string", - "Restore the camera state from file" + "Load a navigation state from file. The file should be a lua file " + "returning the navigation state as a table formatted as a " + "Navigation State, such as the output files of saveNavigationState." }, { "retargetAnchor", diff --git a/src/interaction/navigationhandler_lua.inl b/src/interaction/navigationhandler_lua.inl index f2affeeea7..899859c36e 100644 --- a/src/interaction/navigationhandler_lua.inl +++ b/src/interaction/navigationhandler_lua.inl @@ -26,8 +26,8 @@ namespace openspace::luascriptfunctions { -int restoreCameraStateFromFile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::restoreCameraStateFromFile"); +int loadNavigationState(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadNavigationState"); const std::string& cameraStateFilePath = ghoul::lua::value( L, @@ -39,27 +39,35 @@ int restoreCameraStateFromFile(lua_State* L) { return ghoul::lua::luaError(L, "filepath string is empty"); } - global::navigationHandler.restoreCameraStateFromFile(cameraStateFilePath); + global::navigationHandler.loadNavigationState(cameraStateFilePath); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } -int setCameraState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setCameraState"); +int setNavigationState(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setNavigationState"); - try { - ghoul::Dictionary dictionary; - ghoul::lua::luaDictionaryFromState(L, dictionary); - global::navigationHandler.setCameraStateFromDictionary(dictionary); - } catch (const ghoul::RuntimeError& e) { + ghoul::Dictionary navigationStateDictionary; + ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary); + + using namespace openspace::documentation; + + TestResult r = testSpecification( + interaction::NavigationHandler::NavigationState::Documentation(), + navigationStateDictionary + ); + + if (!r.success) { lua_settop(L, 0); return ghoul::lua::luaError( L, - fmt::format("Could not set camera state: {}", e.what()) + fmt::format("Could not set camera state: {}", ghoul::to_string(r)) ); } + global::navigationHandler.setNavigationStateNextFrame(navigationStateDictionary); + // @CLEANUP: When luaDictionaryFromState doesn't leak space anymore, remove the next // line ---abock(2018-02-15) lua_settop(L, 0); @@ -67,21 +75,27 @@ int setCameraState(lua_State* L) { return 0; } -int saveCameraStateToFile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::saveCameraStateToFile"); - - const std::string& cameraStateFilePath = ghoul::lua::value( +int saveNavigationState(lua_State* L) { + const int n = ghoul::lua::checkArgumentsAndThrow( L, - 1, - ghoul::lua::PopValue::Yes + { 1, 2 }, + "lua::saveNavigationState" ); + const std::string& cameraStateFilePath = ghoul::lua::value(L, 1); + + std::string referenceFrame = ""; + if (n > 1) { + referenceFrame = ghoul::lua::value(L, 2); + } + if (cameraStateFilePath.empty()) { return ghoul::lua::luaError(L, "filepath string is empty"); } - global::navigationHandler.saveCameraStateToFile(cameraStateFilePath); + global::navigationHandler.saveNavigationState(cameraStateFilePath, referenceFrame); + lua_settop(L, 0); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index a1ae0da15b..2ec2474bf9 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -365,20 +365,26 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { const glm::dvec3 anchorPos = _anchorNode->worldPosition(); const glm::dvec3 prevCameraPosition = _camera->positionVec3(); - const glm::dvec3 anchorDisplacement = anchorPos - _previousAnchorNodePosition; + const glm::dvec3 anchorDisplacement = _previousAnchorNodePosition.has_value() ? + (anchorPos - _previousAnchorNodePosition.value()) : + glm::dvec3(0.0); CameraPose pose = { _camera->positionVec3() + anchorDisplacement, _camera->rotationQuaternion() }; - if (_aimNode && _aimNode != _anchorNode) { + const bool hasPreviousPositions = + _previousAnchorNodePosition.has_value() && + _previousAimNodePosition.has_value(); + + if (_aimNode && _aimNode != _anchorNode && hasPreviousPositions) { const glm::dvec3 aimPos = _aimNode->worldPosition(); const glm::dvec3 cameraToAnchor = - _previousAnchorNodePosition - prevCameraPosition; + _previousAnchorNodePosition.value() - prevCameraPosition; Displacement anchorToAim = { - _previousAimNodePosition - _previousAnchorNodePosition, + _previousAimNodePosition.value() - _previousAnchorNodePosition.value(), aimPos - anchorPos }; @@ -413,8 +419,9 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { glm::dquat anchorRotation = glm::quat_cast(_anchorNode->worldRotationMatrix()); - glm::dquat anchorNodeRotationDiff = - _previousAnchorNodeRotation * glm::inverse(anchorRotation); + glm::dquat anchorNodeRotationDiff = _previousAnchorNodeRotation.has_value() ? + _previousAnchorNodeRotation.value() * glm::inverse(anchorRotation) : + glm::dquat(); _previousAnchorNodeRotation = anchorRotation; @@ -563,11 +570,17 @@ void OrbitalNavigator::setAnchorNode(const SceneGraphNode* anchorNode) { _anchorNode = anchorNode; if (_anchorNode) { - _previousAnchorNodePosition = _anchorNode->worldPosition(); - _previousAnchorNodeRotation = glm::quat_cast(_anchorNode->worldRotationMatrix()); + _previousAnchorNodePosition.reset(); + _previousAnchorNodeRotation.reset(); } } +void OrbitalNavigator::clearPreviousState() { + _previousAnchorNodePosition.reset(); + _previousAnchorNodeRotation.reset(); + _previousAimNodePosition.reset(); +} + void OrbitalNavigator::setAimNode(const SceneGraphNode* aimNode) { _retargetAimInterpolator.end(); _aimNode = aimNode; @@ -652,6 +665,9 @@ void OrbitalNavigator::setRetargetInterpolationTime(float durationInSeconds) { } bool OrbitalNavigator::followingNodeRotation() const { + if (_aimNode != nullptr && _aimNode != _anchorNode) { + return false; + } return _followRotationInterpolator.value() >= 1.0; } @@ -1219,4 +1235,8 @@ JoystickCameraStates& OrbitalNavigator::joystickStates() { return _joystickStates; } +const JoystickCameraStates& OrbitalNavigator::joystickStates() const { + return _joystickStates; +} + } // namespace openspace::interaction diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 8fce29ad62..914242cf9a 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -374,14 +374,14 @@ void SceneGraphNode::update(const UpdateData& data) { } UpdateData newUpdateData = data; - _worldRotationCached = calculateWorldRotation(); - _worldScaleCached = calculateWorldScale(); // Assumes _worldRotationCached and _worldScaleCached have been calculated for parent _worldPositionCached = calculateWorldPosition(); + _worldRotationCached = calculateWorldRotation(); + _worldScaleCached = calculateWorldScale(); - newUpdateData.modelTransform.translation = worldPosition(); - newUpdateData.modelTransform.rotation = worldRotationMatrix(); - newUpdateData.modelTransform.scale = worldScale(); + newUpdateData.modelTransform.translation = _worldPositionCached; + newUpdateData.modelTransform.rotation = _worldRotationCached; + newUpdateData.modelTransform.scale = _worldScaleCached; glm::dmat4 translation = glm::translate( glm::dmat4(1.0), @@ -655,7 +655,7 @@ bool SceneGraphNode::hasGuiHintHidden() const { glm::dvec3 SceneGraphNode::calculateWorldPosition() const { // recursive up the hierarchy if there are parents available if (_parent) { - const glm::dvec3 wp = _parent->calculateWorldPosition(); + const glm::dvec3 wp = _parent->worldPosition(); const glm::dmat3 wrot = _parent->worldRotationMatrix(); const double ws = _parent->worldScale(); const glm::dvec3 p = position(); @@ -684,7 +684,7 @@ bool SceneGraphNode::isTimeFrameActive(const Time& time) const { glm::dmat3 SceneGraphNode::calculateWorldRotation() const { // recursive up the hierarchy if there are parents available if (_parent) { - return _parent->calculateWorldRotation() * rotationMatrix(); + return _parent->worldRotationMatrix() * rotationMatrix(); } else { return rotationMatrix(); @@ -694,7 +694,7 @@ glm::dmat3 SceneGraphNode::calculateWorldRotation() const { double SceneGraphNode::calculateWorldScale() const { // recursive up the hierarchy if there are parents available if (_parent) { - return _parent->calculateWorldScale() * scale(); + return _parent->worldScale() * scale(); } else { return scale(); From 6d725a7d50a04eb2bb70d2a96474478035961753 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Tue, 16 Jul 2019 13:29:21 +0200 Subject: [PATCH 06/32] Revive screen space browser and add example (#932) * Revive screen space browser and add example * Add reload triggerproperty and change autoplay policy --- data/assets/examples/screenspacebrowser.asset | 10 ++++++++ data/assets/util/asset_helper.asset | 24 +++++++++++++++++++ .../rendering/screenspacerenderable.h | 2 +- modules/cefwebgui/include/guirenderhandler.h | 4 ++-- modules/cefwebgui/shaders/gui_vs.glsl | 3 +-- modules/webbrowser/include/eventhandler.h | 4 ++-- .../webbrowser/include/screenspacebrowser.h | 9 +++++-- modules/webbrowser/src/eventhandler.cpp | 2 +- modules/webbrowser/src/screenspacebrowser.cpp | 23 ++++++++++++++---- modules/webbrowser/src/webbrowserapp.cpp | 3 ++- modules/webbrowser/src/webrenderhandler.cpp | 9 ++++--- modules/webbrowser/webbrowsermodule.cpp | 2 +- src/rendering/dashboard_lua.inl | 8 ++++++- src/rendering/screenspacerenderable.cpp | 5 ++-- 14 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 data/assets/examples/screenspacebrowser.asset diff --git a/data/assets/examples/screenspacebrowser.asset b/data/assets/examples/screenspacebrowser.asset new file mode 100644 index 0000000000..f10350749e --- /dev/null +++ b/data/assets/examples/screenspacebrowser.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') + +local spec = { + Type = "ScreenSpaceBrowser", + Identifier = "ScreenSpaceBrowserExample", + Name = "Screen Space Browser Example", + Url = "https://www.openspaceproject.com/" +}; + +assetHelper.registerScreenSpaceRenderables(asset, { spec }) diff --git a/data/assets/util/asset_helper.asset b/data/assets/util/asset_helper.asset index 8664122cbc..a785329785 100644 --- a/data/assets/util/asset_helper.asset +++ b/data/assets/util/asset_helper.asset @@ -42,6 +42,29 @@ local registerSceneGraphNodes = function (sceneAsset, nodes, override) end) end + +local registerScreenSpaceRenderables = function (sceneAsset, renderables, override) + override = override or false + if not override then + if tableLength(renderables) == 0 then + openspace.printWarning(sceneAsset.filePath .. ": Register function was called with an empty node list. Pass 'true' as third argument to silence this warning.") + return + end + end + + sceneAsset.onInitialize(function () + for i, node in ipairs(renderables) do + openspace.addScreenSpaceRenderable(node) + end + end) + sceneAsset.onDeinitialize(function () + for i = #renderables, 1, -1 do + renderable = renderables[i] + openspace.removeScreenSpaceRenderable(renderable.Identifier) + end + end) +end + local registerDashboardItems = function (dashboardAsset, items) dashboardAsset.onInitialize( function () @@ -176,6 +199,7 @@ end asset.export("registerSceneGraphNodes", registerSceneGraphNodes) asset.export("registerSceneGraphNodesAndExport", registerSceneGraphNodesAndExport) +asset.export("registerScreenSpaceRenderables", registerScreenSpaceRenderables) asset.export("registerSpiceKernels", registerSpiceKernels) asset.export("registerDashboardItems", registerDashboardItems) asset.export("requireAll", requireAll) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 6f780f29b4..e846f76de9 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -82,7 +82,7 @@ protected: void draw(glm::mat4 modelTransform); - virtual void bindTexture(); + virtual void bindTexture() = 0; virtual void unbindTexture(); properties::BoolProperty _enabled; diff --git a/modules/cefwebgui/include/guirenderhandler.h b/modules/cefwebgui/include/guirenderhandler.h index 203ccf3eb9..b28a1875f5 100644 --- a/modules/cefwebgui/include/guirenderhandler.h +++ b/modules/cefwebgui/include/guirenderhandler.h @@ -39,8 +39,8 @@ public: GUIRenderHandler(); virtual ~GUIRenderHandler(); - void draw(); - void render(); + void draw() override; + void render() override; private: std::unique_ptr _programObject; diff --git a/modules/cefwebgui/shaders/gui_vs.glsl b/modules/cefwebgui/shaders/gui_vs.glsl index 2488aa7924..2323d505d3 100644 --- a/modules/cefwebgui/shaders/gui_vs.glsl +++ b/modules/cefwebgui/shaders/gui_vs.glsl @@ -31,8 +31,7 @@ uniform mat4 ortho; out vec2 Texcoord; void main() { - Texcoord = vec2(position.x + 1.0f, position.y - 1.0f) * 0.5; - Texcoord.y *= -1.0f; + Texcoord = vec2(position.x + 1.0f, position.y + 1.0f) * 0.5; gl_Position = vec4(position, 0.0, 1.0); } diff --git a/modules/webbrowser/include/eventhandler.h b/modules/webbrowser/include/eventhandler.h index 1596a02cb0..3ef6bdce06 100644 --- a/modules/webbrowser/include/eventhandler.h +++ b/modules/webbrowser/include/eventhandler.h @@ -57,9 +57,9 @@ class BrowserInstance; class EventHandler { public: void initialize(); - void setBrowser(const CefRefPtr& browser); void setBrowserInstance(BrowserInstance* browserInstance); - void detachBrowser(); + void resetBrowserInstance(); + void touchPressCallback(const double x, const double y); void touchReleaseCallback(const double x, const double y); bool hasContentCallback(const double, const double); diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 41b4a2eb0b..fbfc5073d3 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma warning (push) @@ -72,14 +73,18 @@ public: private: class ScreenSpaceRenderHandler : public WebRenderHandler { public: - void draw(); - void render(); + void draw() override; + void render() override; void setTexture(GLuint t); }; + void bindTexture() override; + properties::StringProperty _url; properties::Vec2Property _dimensions; + properties::TriggerProperty _reload; + CefRefPtr _renderHandler; CefRefPtr _keyboardHandler; std::unique_ptr _browserInstance; diff --git a/modules/webbrowser/src/eventhandler.cpp b/modules/webbrowser/src/eventhandler.cpp index 8cd3c96b3f..1231178231 100644 --- a/modules/webbrowser/src/eventhandler.cpp +++ b/modules/webbrowser/src/eventhandler.cpp @@ -361,7 +361,7 @@ void EventHandler::setBrowserInstance(BrowserInstance* browserInstance) { _browserInstance = browserInstance; } -void EventHandler::detachBrowser() { +void EventHandler::resetBrowserInstance() { _browserInstance = nullptr; } diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 21c4e622bf..075c375f5c 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -35,7 +35,6 @@ namespace { constexpr const char* KeyIdentifier = "Indentifier"; - constexpr const char* KeyUrl = "URL"; constexpr const char* _loggerCat = "ScreenSpaceBrowser"; const openspace::properties::Property::PropertyInfo DimensionsInfo = { @@ -44,11 +43,17 @@ namespace { "Set the dimensions of the web browser windows." }; const openspace::properties::Property::PropertyInfo UrlInfo = { + "Url", "URL", - "url", "The URL to load" }; + const openspace::properties::Property::PropertyInfo ReloadInfo = { + "Reload", + "Reload", + "Reload the web browser" + }; + } // namespace namespace openspace { @@ -65,6 +70,7 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) : ScreenSpaceRenderable(dictionary) , _url(UrlInfo) , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) + , _reload(ReloadInfo) { if (dictionary.hasKey(KeyIdentifier)) { setIdentifier(dictionary.value(KeyIdentifier)); @@ -74,8 +80,8 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) ++id; } - if (dictionary.hasKeyAndValue(KeyUrl)) { - _url = dictionary.value(KeyUrl); + if (dictionary.hasKeyAndValue(UrlInfo.identifier)) { + _url = dictionary.value(UrlInfo.identifier); } glm::vec2 windowDimensions = global::windowDelegate.currentSubwindowSize(); @@ -94,9 +100,11 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) _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) { @@ -110,6 +118,7 @@ bool ScreenSpaceBrowser::initialize() { createShaders(); + _browserInstance->initialize(); _browserInstance->loadUrl(_url); return isReady(); } @@ -146,6 +155,8 @@ void ScreenSpaceBrowser::render() { } void ScreenSpaceBrowser::update() { + _objectSize = _texture->dimensions(); + if (_isUrlDirty) { _browserInstance->loadUrl(_url); _isUrlDirty = false; @@ -162,4 +173,8 @@ bool ScreenSpaceBrowser::isReady() const { return _shader && _texture; } +void ScreenSpaceBrowser::bindTexture() { + _texture->bind(); +} + } // namespace openspace diff --git a/modules/webbrowser/src/webbrowserapp.cpp b/modules/webbrowser/src/webbrowserapp.cpp index 6ccfaefaf5..dc49bd8fa9 100644 --- a/modules/webbrowser/src/webbrowserapp.cpp +++ b/modules/webbrowser/src/webbrowserapp.cpp @@ -41,10 +41,11 @@ void WebBrowserApp::OnContextCreated(CefRefPtr, CefRefPtr, } void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&, - CefRefPtr) + CefRefPtr commandLine) { // command_line->AppendSwitch("disable-gpu"); // command_line->AppendSwitch("disable-gpu-compositing"); + commandLine->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required"); } } // namespace openspace diff --git a/modules/webbrowser/src/webrenderhandler.cpp b/modules/webbrowser/src/webrenderhandler.cpp index 555e88d721..364855bd2e 100644 --- a/modules/webbrowser/src/webrenderhandler.cpp +++ b/modules/webbrowser/src/webrenderhandler.cpp @@ -78,11 +78,13 @@ void WebRenderHandler::OnPaint(CefRefPtr, CefRenderHandler::PaintEle // Copy the updated rectangle line by line. for (int y = lowerUpdatingRectBound.y; y < upperUpdatingRectBound.y; ++y) { int lineOffset = y * w + lowerUpdatingRectBound.x; + // Chromium stores image upside down compared to OpenGL, so we flip it: + int invLineOffset = (h - y - 1) * w + lowerUpdatingRectBound.x; int rectWidth = upperUpdatingRectBound.x - lowerUpdatingRectBound.x; std::copy( reinterpret_cast(buffer) + lineOffset, reinterpret_cast(buffer) + lineOffset + rectWidth, - _browserBuffer.data() + lineOffset + _browserBuffer.data() + invLineOffset ); } @@ -123,14 +125,15 @@ void WebRenderHandler::updateTexture() { GL_TEXTURE_2D, 0, _lowerDirtyRectBound.x, - _lowerDirtyRectBound.y, + _browserBufferSize.y - _upperDirtyRectBound.y, _upperDirtyRectBound.x - _lowerDirtyRectBound.x, _upperDirtyRectBound.y - _lowerDirtyRectBound.y, GL_BGRA_EXT, GL_UNSIGNED_BYTE, reinterpret_cast( _browserBuffer.data() + - _lowerDirtyRectBound.y * _browserBufferSize.x + _lowerDirtyRectBound.x + (_browserBufferSize.y - _upperDirtyRectBound.y) * + _browserBufferSize.x + _lowerDirtyRectBound.x ) ); diff --git a/modules/webbrowser/webbrowsermodule.cpp b/modules/webbrowser/webbrowsermodule.cpp index c9181fa28c..bf11e5eb34 100644 --- a/modules/webbrowser/webbrowsermodule.cpp +++ b/modules/webbrowser/webbrowsermodule.cpp @@ -98,7 +98,7 @@ void WebBrowserModule::internalDeinitialize() { return; } - _eventHandler.detachBrowser(); + _eventHandler.resetBrowserInstance(); bool forceBrowserShutdown = true; for (BrowserInstance* browser : _browsers) { diff --git a/src/rendering/dashboard_lua.inl b/src/rendering/dashboard_lua.inl index a6544c6af6..3157fa3d01 100644 --- a/src/rendering/dashboard_lua.inl +++ b/src/rendering/dashboard_lua.inl @@ -48,7 +48,13 @@ int addDashboardItem(lua_State* L) { } lua_settop(L, 0); - global::dashboard.addDashboardItem(DashboardItem::createFromDictionary(d)); + try { + global::dashboard.addDashboardItem(DashboardItem::createFromDictionary(d)); + } + catch (const ghoul::RuntimeError& e) { + LERRORC("addDashboardItem", e.what()); + return ghoul::lua::luaError(L, "Error adding dashboard item"); + } ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 98a2c4519f..10c1b6726b 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -614,9 +614,8 @@ void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) { unbindTexture(); } -void ScreenSpaceRenderable::bindTexture() {} - -void ScreenSpaceRenderable::unbindTexture() {} +void ScreenSpaceRenderable::unbindTexture() { +} } // namespace openspace From 64f8793ea0e16915fa3dfad1614b155e32589e12 Mon Sep 17 00:00:00 2001 From: David Laidlaw Date: Tue, 16 Jul 2019 07:51:39 -0400 Subject: [PATCH 07/32] minVR updates (#908) * changed libopenspace cmake module name to openspace-core * change mouse button callback to include modifiers * added some new ghoul initialization from the non-MinVR main.cpp * Add GLFW as an external dependency for MinVR --- .gitmodules | 3 +++ apps/OpenSpace-MinVR/CMakeLists.txt | 2 +- apps/OpenSpace-MinVR/ext/glfw | 1 + apps/OpenSpace-MinVR/main.cpp | 17 ++++++++++++++++- 4 files changed, 21 insertions(+), 2 deletions(-) create mode 160000 apps/OpenSpace-MinVR/ext/glfw diff --git a/.gitmodules b/.gitmodules index 4311e7851a..1bdc897bbd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,6 @@ [submodule "modules/fitsfilereader/ext/cfitsio"] path = modules/fitsfilereader/ext/cfitsio url = https://github.com/OpenSpace/cfitsio.git +[submodule "apps/OpenSpace-MinVR/ext/glfw"] + path = apps/OpenSpace-MinVR/ext/glfw + url = https://github.com/opensgct/glfw diff --git a/apps/OpenSpace-MinVR/CMakeLists.txt b/apps/OpenSpace-MinVR/CMakeLists.txt index 656da9b194..f58a2a13cc 100644 --- a/apps/OpenSpace-MinVR/CMakeLists.txt +++ b/apps/OpenSpace-MinVR/CMakeLists.txt @@ -50,7 +50,7 @@ target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ex target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/minvr/external/GLFW/src/include) -target_link_libraries(OpenSpace-MinVR libOpenSpace MinVR) +target_link_libraries(OpenSpace-MinVR openspace-core MinVR) # Web Browser and Web gui # Why not put these in the module's path? Because they do not have access to the diff --git a/apps/OpenSpace-MinVR/ext/glfw b/apps/OpenSpace-MinVR/ext/glfw new file mode 160000 index 0000000000..7ef34eb06d --- /dev/null +++ b/apps/OpenSpace-MinVR/ext/glfw @@ -0,0 +1 @@ +Subproject commit 7ef34eb06de54dd9186d3d21a401b2ef819b59e7 diff --git a/apps/OpenSpace-MinVR/main.cpp b/apps/OpenSpace-MinVR/main.cpp index b4cde8364e..1b309b4b8d 100644 --- a/apps/OpenSpace-MinVR/main.cpp +++ b/apps/OpenSpace-MinVR/main.cpp @@ -200,7 +200,14 @@ void Handler::onVREvent(const VRDataIndex& eventData) { if (button == MouseButton::Right && action == MouseAction::Press) { windowingGlobals.mouseButtons |= 1 << 2; } - global::openSpaceEngine.mouseButtonCallback(button, action); + + using KM = KeyModifier; + KM mod = KM::NoModifier; + mod |= keyboardState.modifierShift ? KM::Shift : KM::NoModifier; + mod |= keyboardState.modifierCtrl ? KM::Control : KM::NoModifier; + mod |= keyboardState.modifierAlt ? KM::Alt : KM::NoModifier; + + global::openSpaceEngine.mouseButtonCallback(button, action, mod); } } @@ -341,6 +348,14 @@ int main(int argc, char** argv) { ghoul::initialize(); + // Register the path of the executable, + // to make it possible to find other files in the same directory. + FileSys.registerPathToken( + "${BIN}", + ghoul::filesystem::File(absPath(argv[0])).directoryName(), + ghoul::filesystem::FileSystem::Override::Yes + ); + // Create the OpenSpace engine and get arguments for the SGCT engine std::string windowConfiguration; try { From a39d590b95f2a910f746c1445c976e33d20ab498 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 17 Jul 2019 12:01:30 +0200 Subject: [PATCH 08/32] Fix copy and paste error --- modules/globebrowsing/src/renderableglobe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 6361670ee6..4cccfedacd 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -176,7 +176,7 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo TargetLodScaleFactorInfo = { - "TargetLodScaleFactorInfo", + "TargetLodScaleFactor", "Target Level of Detail Scale Factor", "" // @TODO Missing documentation }; From 87df4a11a9dfe9075a311920c2bf167d58a1486e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 17 Jul 2019 14:30:01 +0200 Subject: [PATCH 09/32] Use correct identifier for Vesta --- data/assets/scene/solarsystem/missions/dawn/vesta.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/scene/solarsystem/missions/dawn/vesta.asset b/data/assets/scene/solarsystem/missions/dawn/vesta.asset index d6b1735e36..64bfabfca8 100644 --- a/data/assets/scene/solarsystem/missions/dawn/vesta.asset +++ b/data/assets/scene/solarsystem/missions/dawn/vesta.asset @@ -20,7 +20,7 @@ local images = asset.syncedResource({ local models = asset.syncedResource({ Name = "Vesta Models", Type = "HttpSynchronization", - Identifier = "vesta_comet", + Identifier = "vesta_model", Version = 1 }) From c97d5126eced98f43bd6ba57b60cb7df6a9d2052 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 17 Jul 2019 15:21:13 +0200 Subject: [PATCH 10/32] Feature/timeline translation (#931) * Work on timeline translations * Add Apollo 11 Descent data * Ability to display negative altitudes * Expose globe translation properties * Added timeline rotation, and some scene updates. * Cleaning up apollo_sites scene; fixing boulder 1 in place to adress heightmap issue * Use quaternion slerp instaet of linear interpolation + Cleanup * Change to old lem model while waiting for new version to be pushed to data repo * Small fixes --- data/assets/apollo_sites.scene | 24 +- .../solarsystem/missions/apollo/a11_lem.asset | 4 +- .../solarsystem/missions/apollo/a17_lem.asset | 1 + .../missions/apollo/apollo11.asset | 186 +- .../apollo/apollo11_lem_descent.asset | 1835 +++++++++++++++++ .../apollo11_lem_descent_rotation.asset | 1587 ++++++++++++++ .../missions/apollo/apollo8launchtrail.asset | 74 + .../missions/apollo/bouldersstation2.asset | 12 +- .../missions/apollo/bouldersstation6.asset | 12 +- .../missions/apollo/bouldersstation7.asset | 4 +- include/openspace/util/timeline.h | 11 +- include/openspace/util/timeline.inl | 24 +- modules/base/CMakeLists.txt | 13 +- modules/base/basemodule.cpp | 7 + modules/base/rotation/timelinerotation.cpp | 118 ++ modules/base/rotation/timelinerotation.h | 49 + .../base/translation/timelinetranslation.cpp | 114 + .../base/translation/timelinetranslation.h | 50 + .../src/dashboarditemglobelocation.cpp | 9 +- .../globebrowsing/src/globetranslation.cpp | 103 +- modules/globebrowsing/src/globetranslation.h | 4 +- .../space/translation/horizonstranslation.cpp | 2 +- 22 files changed, 4085 insertions(+), 158 deletions(-) create mode 100644 data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent.asset create mode 100644 data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent_rotation.asset create mode 100644 data/assets/scene/solarsystem/missions/apollo/apollo8launchtrail.asset create mode 100644 modules/base/rotation/timelinerotation.cpp create mode 100644 modules/base/rotation/timelinerotation.h create mode 100644 modules/base/translation/timelinetranslation.cpp create mode 100644 modules/base/translation/timelinetranslation.h diff --git a/data/assets/apollo_sites.scene b/data/assets/apollo_sites.scene index 05b0460970..8a487e3b25 100644 --- a/data/assets/apollo_sites.scene +++ b/data/assets/apollo_sites.scene @@ -2,12 +2,10 @@ asset.require('./base') --moonrocks.scene local sceneHelper = asset.require('util/scene_helper') - -- local station2 = asset.require('scene/solarsystem/missions/apollo/bouldersstation2') -- local station6 = asset.require('scene/solarsystem/missions/apollo/bouldersstation6') -- local station7 = asset.require('scene/solarsystem/missions/apollo/bouldersstation7') asset.require('scene/solarsystem/missions/apollo/apollo11') -asset.require('scene/solarsystem/missions/apollo/a11_lem') asset.require('scene/solarsystem/missions/apollo/a17_lem') asset.require('scene/solarsystem/missions/apollo/apollo_globebrowsing') asset.require('scene/solarsystem/missions/apollo/apollo_11_lem_flipbook') @@ -37,11 +35,11 @@ local Keybindings = { }, { Key = "F11", - Command = "openspace.time.setTime('1969 JUL 20 20:17:40');" .. + Command = "openspace.time.setTime('1969 JUL 20 20:17:40');" .. "openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true);" .. "openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true);" .. "openspace.setPropertyValueSingle('Scene.Moon.Renderable.LodScaleFactor', 20.11);" .. - "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo11LemModel');" .. + "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo11LemPosition');" .. "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);" .. "openspace.setPropertyValueSingle('Scene.Apollo11MoonTrail.Renderable.Enabled', true);" .. "openspace.setPropertyValueSingle('Scene.Apollo11LemTrail.Renderable.Enabled', true);", @@ -82,8 +80,11 @@ asset.onInitialize(function () sceneHelper.bindKeys(Keybindings) - openspace.markInterestingNodes({ "Moon", "Apollo11LemModel", "Apollo17LemModel", "Apollo11", "Apollo11LunarLander" }) - + openspace.markInterestingNodes({ + "Moon", "Apollo11LemModel", "Apollo17LemModel", + "Apollo11", "Apollo11LunarLander", + -- "Station_2_Boulder2", "Station_6_Fragment1" + }) -- To enable both sites by default, uncomment these lines -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0.000000); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.Enabled', true); @@ -95,12 +96,19 @@ asset.onInitialize(function () -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_station7.BlendMode', 0.000000); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true); - + + openspace.setPropertyValueSingle('Scene.Apollo11LemDescentModel.Renderable.RotationVector', { 273.205475,6.904110,308.712311 }); + openspace.setPropertyValueSingle('Scene.Apollo11LemLandedModel.Renderable.RotationVector', { 273.205475,6.904110,308.712311 }); + openspace.globebrowsing.goToGeo(moonAsset.Moon.Identifier, 20, -60, 15000000) openspace.setPropertyValueSingle("Scene.Moon.Renderable.PerformShading", false) end) asset.onDeinitialize(function () - openspace.removeInterestingNodes({ "Moon", "Apollo11Lem", "Apollo17Lem", "Apollo11", "Apollo11LunarLander" }) + openspace.removeInterestingNodes({ + "Moon", "Apollo11Lem", "Apollo17Lem", + "Apollo11", "Apollo11LemPosition", + -- "Station_6_Fragment1", "Station_6_Fragments_2_3" + }) end) diff --git a/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset b/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset index 2a9182d715..05b81e0af4 100644 --- a/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset +++ b/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset @@ -15,8 +15,8 @@ local Apollo11Lem = { Globe = moonAsset.Moon.Identifier, Longitude = -360+23.47306, Latitude = 0.67402, - FixedAltitude = -1927.65, - UseFixedAltitude = true + Altitude = -1927.65, + UseHeightMap = false }, }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset b/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset index 9d6f403071..3a88c8cf75 100644 --- a/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset +++ b/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset @@ -14,6 +14,7 @@ local Apollo17Lem = { Globe = moonAsset.Moon.Identifier, Longitude = -329.22833, Latitude = 20.19092, + UseHeightmap = true }, }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo11.asset b/data/assets/scene/solarsystem/missions/apollo/apollo11.asset index 64f5dcd9bd..e07492b1e1 100644 --- a/data/assets/scene/solarsystem/missions/apollo/apollo11.asset +++ b/data/assets/scene/solarsystem/missions/apollo/apollo11.asset @@ -1,5 +1,8 @@ local assetHelper = asset.require('util/asset_helper') local sunTransforms = asset.require('scene/solarsystem/sun/transforms') +local descentKeyframes = asset.require('./apollo11_lem_descent.asset') +local descentRotationKeyframes = asset.require('./apollo11_lem_descent_rotation.asset') +local model = asset.require('scene/solarsystem/missions/apollo/lem_model') asset.require('spice/base') @@ -24,7 +27,7 @@ local kernels = { kernelsFolder .. '/apollo11_orbits_full9km.bsp', kernelsFolder .. '/apollo11_orbits_lm9km.bsp', } - +--landing - 1969-07-20T20:17:40 local apolloSpiceId = "-911" local apolloLemSpiceId = "-911500" @@ -107,81 +110,44 @@ local Apollo11MoonTrail = { } } --- Uncomment if you want to follow the mock decent --- local Apollo11LemPosition = { --- Identifier = "Apollo11LemPosition", --- Parent = "Moon", --- TimeFrame = { --- Type = "TimeFrameInterval", --- Start = "1969 JUL 20 19:10:25.183", --- End = "1969 JUL 20 20:17:46.183" --- }, --- Transform = { --- Translation = { --- Type = "SpiceTranslation", --- Target = apolloLemSpiceId, --- Observer = "MOON", --- Frame = "MOON_ME", --- Kernels = kernels --- }, --- }, --- GUI = { --- Hidden = true, --- Name = "Apollo 11 Lunar Lander Position", --- Path = "/Solar System/Missions/Apollo/11" --- } --- } --- local Apollo11LunarLanderModel = { --- Identifier = "Apollo11LunarLander", --- Parent = Apollo11LemPosition.Identifier, --- Transform = { --- Rotation = { --- Type = "StaticRotation", --- Rotation = {0.0, 0.0, -3.1415/2} --- }, --- Scale = { --- Type = "StaticScale", --- Scale = 100.0 --- } --- }, --- TimeFrame = { --- Type = "TimeFrameInterval", --- Start = "1969 JUL 20 19:10:25.183", --- End = "1969 JUL 20 20:17:46.183" --- }, --- Renderable = { --- Type = "RenderableModel", --- Geometry = { --- Type = "MultiModelGeometry", --- GeometryFile = modelFolder .. "/lem_nasa.obj" --- }, --- ColorTexture = modelFolder .. "/gray.png", --- LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) --- }, --- GUI = { --- Hidden = false, --- Name = "Apollo 11 Lunar Lander", --- Path = "/Solar System/Missions/Apollo/11" --- } --- } - -local Apollo11LemTrail = { - Identifier = "Apollo11LemTrail", - Parent = "Moon", - Renderable = { - Type = "RenderableTrailTrajectory", - Translation = { +local lemTranslation = { + Type = "TimelineTranslation", + Keyframes = { + -- 20:14:30 is an arbitrary cutoff, but last 4 minutes data in descentKeyframes + -- begins at 20.14.40. Due to linear interpolation, we will get + -- a 10s linear transition to the location where the descentKeyframes start. + ['1969 JUL 20 20:14:30'] = { Type = "SpiceTranslation", Target = apolloLemSpiceId, Observer = "MOON", Frame = "IAU_MOON", Kernels = kernels }, - Color = {0.780000,0.940000,0.340000 }, + ['1969 JUL 20 20:14:40'] = { + Type = "TimelineTranslation", + Keyframes = descentKeyframes.keyframes + } + } +} + +local lemRotation = { + Type = "TimelineRotation", + Keyframes = descentRotationKeyframes.keyframes +} + + + +local Apollo11LemTrail = { + Identifier = "Apollo11LemTrail", + Parent = "Moon", + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = lemTranslation, + Color = { 0.780000,0.940000,0.340000 }, StartTime = "1969 JUL 20 19:10:25.183", EndTime = "1969 JUL 20 20:17:46.183", - SampleInterval = 60, + SampleInterval = 2, EnableFade = false, Enabled = false, }, @@ -191,11 +157,91 @@ local Apollo11LemTrail = { } } +local Apollo11LemPosition = { + Identifier = "Apollo11LemPosition", + Parent = "Moon", + TimeFrame = { + Type = "TimeFrameInterval", + Start = "1969 JUL 20 19:10:25.183" + }, + Transform = { + Translation = lemTranslation, + Rotation = lemRotation + }, + GUI = { + Hidden = false, + Name = "Apollo 11 Lunar Lander Position", + Path = "/Solar System/Missions/Apollo/11" + } +} +--landing - 1969-07-20T20:17:40 + +local Apollo11LemDescentModel = { + Identifier = "Apollo11LemDescentModel", + Parent = Apollo11LemPosition.Identifier, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "1969 JUL 19 19:38:29.183", + End = "1969 JUL 20 20:17:40.0" + }, + Transform = { + Scale = { + Type = "StaticScale", + Scale = 0.24 + } + }, + Renderable = { + Type = "RenderableModel", + Geometry = { + Type = "MultiModelGeometry", + GeometryFile = model.modelFolder .. "/LM-2_ver2clean.obj" + }, + ColorTexture = model.modelFolder .. "/LM-2_ver2clean_u1_v1.jpeg", + LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) + }, + GUI = { + Hidden = false, + Name = "Apollo 11 Descent Lem", + Path = "/Solar System/Missions/Apollo/11" + } +} + +local Apollo11LemLandedModel = { + Identifier = "Apollo11LemLandedModel", + Parent = Apollo11LemPosition.Identifier, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "1969 JUL 20 20:17:40.0" + }, + Transform = { + Scale = { + Type = "StaticScale", + Scale = 0.24 + } + }, + Renderable = { + Type = "RenderableModel", + Geometry = { + Type = "MultiModelGeometry", + GeometryFile = model.modelFolder .. "/LM-2_ver2clean.obj" + }, + ColorTexture = model.modelFolder .. "/LM-2_ver2clean_u1_v1.jpeg", + LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) + }, + GUI = { + Hidden = false, + Name = "Apollo 11 Landed Lem", + Path = "/Solar System/Missions/Apollo/11" + } +} + + local exportList = { - Apollo11Position, - -- Apollo11LemPosition, + Apollo11Position, + Apollo11LemPosition, Apollo11Model, - -- Apollo11LunarLanderModel, + Apollo11LemDescentModel, + Apollo11LemLandedModel, Apollo11MoonTrail, Apollo11LemTrail, } diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent.asset b/data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent.asset new file mode 100644 index 0000000000..93128f5181 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent.asset @@ -0,0 +1,1835 @@ +-- The following keyframe data was converted from the_last_four_minutes_2019-06-09.kml, +-- which is available at http://apollo.mem-tek.com/GoogleMoonKMZ.html + +-- In the conversion, some assumptions and simplifications were made: +-- * The descent markers in the KML have Point nodes expressed "relative to ground" +-- We assume that the ground is fixed at altitude 1927.65 meters below the reference ellipsoid, +-- in order to match height data from a height map constructed from LRO data. +-- * We manually offset the coordiantes slightly, by 0.013496003622691433 degrees in longitude and -0.007472581881668883 degrees in latitude, +-- in order to match the landing spot specified at long: 23.47306, lat: 0.67402 extracted from footage from LRO. +-- The kml file provided 23.45956399637731, lat: 0.6814925818816688 as the landing coordinates - hence the manual offset. +-- If more accurate height/color maps are aqcuired, these values can be adjusted by running the conversion script again. +-- For more information, contact emil.axelsson@liu.se. + + +local keyframes = { + ['1969-07-20T20:13:40'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.64480784327766, + Latitude = 0.6899960896998255, + Altitude = -1546.3568594681615, + UseHeightmap = false + }, + ['1969-07-20T20:13:41'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.64371058653857, + Latitude = 0.6878218095380976, + Altitude = -1565.4215164947534, + UseHeightmap = false + }, + ['1969-07-20T20:13:42'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.64182673932963, + Latitude = 0.6868724573827948, + Altitude = -1565.4215164947534, + UseHeightmap = false + }, + ['1969-07-20T20:13:43'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.64054706630478, + Latitude = 0.6858670898943581, + Altitude = -1579.0391286566048, + UseHeightmap = false + }, + ['1969-07-20T20:13:44'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.63636509003987, + Latitude = 0.6869318608730292, + Altitude = -1579.0391286566048, + UseHeightmap = false + }, + ['1969-07-20T20:13:45'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.63333610553231, + Latitude = 0.6875049989808152, + Altitude = -1584.4861735213453, + UseHeightmap = false + }, + ['1969-07-20T20:13:46'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.630258198415152, + Latitude = 0.6879251024075629, + Altitude = -1587.2096959537155, + UseHeightmap = false + }, + ['1969-07-20T20:13:47'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.62944534804935, + Latitude = 0.6868614912680597, + Altitude = -1592.656740818456, + UseHeightmap = false + }, + ['1969-07-20T20:13:48'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.62679291745059, + Latitude = 0.6859161360075229, + Altitude = -1604.9125917641222, + UseHeightmap = false + }, + ['1969-07-20T20:13:49'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.624085315638872, + Latitude = 0.685126212476227, + Altitude = -1619.8919651421588, + UseHeightmap = false + }, + ['1969-07-20T20:13:50'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.62142772795633, + Latitude = 0.6848656185526153, + Altitude = -1630.7860548716399, + UseHeightmap = false + }, + ['1969-07-20T20:13:51'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.617193313827283, + Latitude = 0.6849603490017026, + Altitude = -1630.7860548716399, + UseHeightmap = false + }, + ['1969-07-20T20:13:52'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.61543137875974, + Latitude = 0.68523470439912, + Altitude = -1629.4242936554547, + UseHeightmap = false + }, + ['1969-07-20T20:13:53'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.61158202958536, + Latitude = 0.6853852597026965, + Altitude = -1633.5095773040102, + UseHeightmap = false + }, + ['1969-07-20T20:13:54'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.60991413189263, + Latitude = 0.6852537398149626, + Altitude = -1643.041905817306, + UseHeightmap = false + }, + ['1969-07-20T20:13:55'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.607915527643012, + Latitude = 0.6853963551830907, + Altitude = -1662.106562843898, + UseHeightmap = false + }, + ['1969-07-20T20:13:56'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.605996916437142, + Latitude = 0.6830167672762936, + Altitude = -1663.4683240600832, + UseHeightmap = false + }, + ['1969-07-20T20:13:57'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.6027345854584, + Latitude = 0.6824580715414034, + Altitude = -1671.09418687072, + UseHeightmap = false + }, + ['1969-07-20T20:13:58'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.60047452065999, + Latitude = 0.6837230890353062, + Altitude = -1671.638891357194, + UseHeightmap = false + }, + ['1969-07-20T20:13:59'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.598006245556462, + Latitude = 0.6851039272779041, + Altitude = -1670.277130141009, + UseHeightmap = false + }, + ['1969-07-20T20:14:00'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.594980604909782, + Latitude = 0.6859011120513393, + Altitude = -1683.8947423028603, + UseHeightmap = false + }, + ['1969-07-20T20:14:01'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.595085912567033, + Latitude = 0.685405665002322, + Altitude = -1698.874115680897, + UseHeightmap = false + }, + ['1969-07-20T20:14:02'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.5930664955042, + Latitude = 0.6852493785380211, + Altitude = -1701.597638113267, + UseHeightmap = false + }, + ['1969-07-20T20:14:03'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.591385100243283, + Latitude = 0.6848676328581234, + Altitude = -1709.768205410378, + UseHeightmap = false + }, + ['1969-07-20T20:14:04'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.58888799865371, + Latitude = 0.6847945134519827, + Altitude = -1717.9387727074889, + UseHeightmap = false + }, + ['1969-07-20T20:14:05'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.58707895840121, + Latitude = 0.6847997274847563, + Altitude = -1720.662295139859, + UseHeightmap = false + }, + ['1969-07-20T20:14:06'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.585134523523262, + Latitude = 0.6844679679748537, + Altitude = -1726.1093400045995, + UseHeightmap = false + }, + ['1969-07-20T20:14:07'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.58309233633901, + Latitude = 0.6845115405154798, + Altitude = -1730.194623653155, + UseHeightmap = false + }, + ['1969-07-20T20:14:08'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.581800658763132, + Latitude = 0.6837790677972603, + Altitude = -1737.0034297340808, + UseHeightmap = false + }, + ['1969-07-20T20:14:09'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.580055660445762, + Latitude = 0.6831436064664251, + Altitude = -1741.0887133826361, + UseHeightmap = false + }, + ['1969-07-20T20:14:10'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.57863282556605, + Latitude = 0.6828140286921376, + Altitude = -1749.259280679747, + UseHeightmap = false + }, + ['1969-07-20T20:14:11'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.57640031861404, + Latitude = 0.6825176811105468, + Altitude = -1751.9828031121174, + UseHeightmap = false + }, + ['1969-07-20T20:14:12'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.57398679174075, + Latitude = 0.6826876185178852, + Altitude = -1750.6210418959322, + UseHeightmap = false + }, + ['1969-07-20T20:14:13'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.57156483164977, + Latitude = 0.6825035088375115, + Altitude = -1758.7916091930429, + UseHeightmap = false + }, + ['1969-07-20T20:14:14'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.568805614344672, + Latitude = 0.6825830127392937, + Altitude = -1764.2386540577836, + UseHeightmap = false + }, + ['1969-07-20T20:14:15'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.56712274763365, + Latitude = 0.6821390846562359, + Altitude = -1764.2386540577836, + UseHeightmap = false + }, + ['1969-07-20T20:14:16'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.56530723506546, + Latitude = 0.6815597518028071, + Altitude = -1772.4092213548943, + UseHeightmap = false + }, + ['1969-07-20T20:14:17'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.56412162578659, + Latitude = 0.6811736246098009, + Altitude = -1773.7709825710795, + UseHeightmap = false + }, + ['1969-07-20T20:14:18'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.56276962682385, + Latitude = 0.6808738576281527, + Altitude = -1779.2180274358202, + UseHeightmap = false + }, + ['1969-07-20T20:14:19'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.560994966586822, + Latitude = 0.6806433210749815, + Altitude = -1781.9415498681901, + UseHeightmap = false + }, + ['1969-07-20T20:14:20'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.55943927760013, + Latitude = 0.680762500394614, + Altitude = -1788.7503559491158, + UseHeightmap = false + }, + ['1969-07-20T20:14:21'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.55808185917876, + Latitude = 0.6806932677701746, + Altitude = -1788.205651462642, + UseHeightmap = false + }, + ['1969-07-20T20:14:22'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.556393791415733, + Latitude = 0.6811207130416086, + Altitude = -1791.4738783814862, + UseHeightmap = false + }, + ['1969-07-20T20:14:23'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.55496480157647, + Latitude = 0.6814204204715102, + Altitude = -1792.8356395976714, + UseHeightmap = false + }, + ['1969-07-20T20:14:24'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.55306742293409, + Latitude = 0.6817752241315425, + Altitude = -1795.5591620300418, + UseHeightmap = false + }, + ['1969-07-20T20:14:25'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.55137129589691, + Latitude = 0.6815869620825672, + Altitude = -1802.3679681109675, + UseHeightmap = false + }, + ['1969-07-20T20:14:26'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.54977453252549, + Latitude = 0.681089420496018, + Altitude = -1805.0914905433376, + UseHeightmap = false + }, + ['1969-07-20T20:14:27'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.548083879890072, + Latitude = 0.6807962459602379, + Altitude = -1807.8150129757078, + UseHeightmap = false + }, + ['1969-07-20T20:14:28'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.546540200146502, + Latitude = 0.6805000865197504, + Altitude = -1810.5385354080781, + UseHeightmap = false + }, + ['1969-07-20T20:14:29'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.54516644867878, + Latitude = 0.6804026508636472, + Altitude = -1815.9855802728187, + UseHeightmap = false + }, + ['1969-07-20T20:14:30'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.54408346592703, + Latitude = 0.6805503084088244, + Altitude = -1817.3473414890038, + UseHeightmap = false + }, + ['1969-07-20T20:14:31'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.54339758182375, + Latitude = 0.6804859303352504, + Altitude = -1818.709102705189, + UseHeightmap = false + }, + ['1969-07-20T20:14:32'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.54194570925206, + Latitude = 0.6803064377127922, + Altitude = -1821.4326251375592, + UseHeightmap = false + }, + ['1969-07-20T20:14:33'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.54085221251783, + Latitude = 0.6801546546560774, + Altitude = -1824.9732042996407, + UseHeightmap = false + }, + ['1969-07-20T20:14:34'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.53954140597472, + Latitude = 0.6797325898259152, + Altitude = -1827.696726732011, + UseHeightmap = false + }, + ['1969-07-20T20:14:35'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.537934104316932, + Latitude = 0.679569186740729, + Altitude = -1831.7820103805664, + UseHeightmap = false + }, + ['1969-07-20T20:14:36'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.53689199133522, + Latitude = 0.6794114031790662, + Altitude = -1833.6884760832256, + UseHeightmap = false + }, + ['1969-07-20T20:14:37'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.53536814560564, + Latitude = 0.6791732992510942, + Altitude = -1836.9567030020698, + UseHeightmap = false + }, + ['1969-07-20T20:14:38'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.53395331216349, + Latitude = 0.6792039275673737, + Altitude = -1839.4078731912032, + UseHeightmap = false + }, + ['1969-07-20T20:14:39'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.53275788877434, + Latitude = 0.6790059399149831, + Altitude = -1840.497282164151, + UseHeightmap = false + }, + ['1969-07-20T20:14:40'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.531279977460432, + Latitude = 0.6788794363528592, + Altitude = -1844.5825658127067, + UseHeightmap = false + }, + ['1969-07-20T20:14:41'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.52959475512685, + Latitude = 0.6788906739797406, + Altitude = -1845.9443270288918, + UseHeightmap = false + }, + ['1969-07-20T20:14:42'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.52769228385669, + Latitude = 0.6787279693068425, + Altitude = -1848.123144974788, + UseHeightmap = false + }, + ['1969-07-20T20:14:43'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.52685377337869, + Latitude = 0.6787634478561919, + Altitude = -1850.8466674071583, + UseHeightmap = false + }, + ['1969-07-20T20:14:44'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.526284004538702, + Latitude = 0.6785694853441325, + Altitude = -1853.0254853530546, + UseHeightmap = false + }, + ['1969-07-20T20:14:45'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.5258419320743, + Latitude = 0.6784720829848033, + Altitude = -1852.2084286233435, + UseHeightmap = false + }, + ['1969-07-20T20:14:46'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.524906401275462, + Latitude = 0.6784174518581257, + Altitude = -1855.7490077854247, + UseHeightmap = false + }, + ['1969-07-20T20:14:47'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.52349915098792, + Latitude = 0.6782893729810321, + Altitude = -1857.383121244847, + UseHeightmap = false + }, + ['1969-07-20T20:14:48'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.522315823805602, + Latitude = 0.6780556991046269, + Altitude = -1859.5619391907433, + UseHeightmap = false + }, + ['1969-07-20T20:14:49'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.52101739233993, + Latitude = 0.6779647310824661, + Altitude = -1862.2854616231134, + UseHeightmap = false + }, + ['1969-07-20T20:14:50'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.51994166433182, + Latitude = 0.6778711676787862, + Altitude = -1864.7366318122467, + UseHeightmap = false + }, + ['1969-07-20T20:14:51'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.51898851685442, + Latitude = 0.6778817565177891, + Altitude = -1866.643097514906, + UseHeightmap = false + }, + ['1969-07-20T20:14:52'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.51808183367586, + Latitude = 0.6778718533214779, + Altitude = -1868.821915460802, + UseHeightmap = false + }, + ['1969-07-20T20:14:53'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.517315195124922, + Latitude = 0.6777409244088132, + Altitude = -1869.6389721905132, + UseHeightmap = false + }, + ['1969-07-20T20:14:54'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.516423288093712, + Latitude = 0.6776383502937863, + Altitude = -1872.0901423796465, + UseHeightmap = false + }, + ['1969-07-20T20:14:55'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.515618488386473, + Latitude = 0.6775904175972421, + Altitude = -1873.7242558390685, + UseHeightmap = false + }, + ['1969-07-20T20:14:56'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.514931748492103, + Latitude = 0.677451729714544, + Altitude = -1875.0860170552537, + UseHeightmap = false + }, + ['1969-07-20T20:14:57'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.5141592094038, + Latitude = 0.6774090469390076, + Altitude = -1876.1754260282019, + UseHeightmap = false + }, + ['1969-07-20T20:14:58'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.513268517407862, + Latitude = 0.677380792748438, + Altitude = -1878.3542439740982, + UseHeightmap = false + }, + ['1969-07-20T20:14:59'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.51249864236425, + Latitude = 0.6773301671802587, + Altitude = -1878.8989484605722, + UseHeightmap = false + }, + ['1969-07-20T20:15:00'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.511670817073732, + Latitude = 0.6773498341149018, + Altitude = -1879.9883574335202, + UseHeightmap = false + }, + ['1969-07-20T20:15:01'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.510927468201952, + Latitude = 0.6773124695718212, + Altitude = -1881.0777664064683, + UseHeightmap = false + }, + ['1969-07-20T20:15:02'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.510140364179833, + Latitude = 0.6772452153026853, + Altitude = -1882.9842321091276, + UseHeightmap = false + }, + ['1969-07-20T20:15:03'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50940612514804, + Latitude = 0.6772084204274821, + Altitude = -1884.3459933253127, + UseHeightmap = false + }, + ['1969-07-20T20:15:04'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.508556629045042, + Latitude = 0.6771417022964165, + Altitude = -1885.1630500550239, + UseHeightmap = false + }, + ['1969-07-20T20:15:05'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.5078270022667, + Latitude = 0.6770996409435569, + Altitude = -1885.707754541498, + UseHeightmap = false + }, + ['1969-07-20T20:15:06'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50712374883535, + Latitude = 0.6770942256987497, + Altitude = -1886.7971635144459, + UseHeightmap = false + }, + ['1969-07-20T20:15:07'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50638631083077, + Latitude = 0.6770208020089364, + Altitude = -1888.158924730631, + UseHeightmap = false + }, + ['1969-07-20T20:15:08'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50572166907488, + Latitude = 0.6769421116864789, + Altitude = -1888.431276973868, + UseHeightmap = false + }, + ['1969-07-20T20:15:09'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.505080467779102, + Latitude = 0.6769068207439769, + Altitude = -1889.5206859468162, + UseHeightmap = false + }, + ['1969-07-20T20:15:10'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.504394828536693, + Latitude = 0.6768437996516232, + Altitude = -1890.6100949197644, + UseHeightmap = false + }, + ['1969-07-20T20:15:11'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50370057106609, + Latitude = 0.6767452474349132, + Altitude = -1891.9718561359496, + UseHeightmap = false + }, + ['1969-07-20T20:15:12'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.503056349392182, + Latitude = 0.6766723806693259, + Altitude = -1893.3336173521345, + UseHeightmap = false + }, + ['1969-07-20T20:15:13'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50246925266341, + Latitude = 0.6766252349202276, + Altitude = -1893.8783218386086, + UseHeightmap = false + }, + ['1969-07-20T20:15:14'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50184956306549, + Latitude = 0.6765535257068991, + Altitude = -1894.9677308115567, + UseHeightmap = false + }, + ['1969-07-20T20:15:15'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.501422630419572, + Latitude = 0.6765112802947014, + Altitude = -1894.1506740818456, + UseHeightmap = false + }, + ['1969-07-20T20:15:16'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50104221348722, + Latitude = 0.676487362071662, + Altitude = -1893.8783218386086, + UseHeightmap = false + }, + ['1969-07-20T20:15:17'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50076948252455, + Latitude = 0.6764658967447386, + Altitude = -1892.2442083791866, + UseHeightmap = false + }, + ['1969-07-20T20:15:18'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.50013364513089, + Latitude = 0.6764482060496164, + Altitude = -1893.3336173521345, + UseHeightmap = false + }, + ['1969-07-20T20:15:19'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.499460285339502, + Latitude = 0.6764309028737, + Altitude = -1894.9677308115567, + UseHeightmap = false + }, + ['1969-07-20T20:15:20'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.498899330647752, + Latitude = 0.6763755753041285, + Altitude = -1896.057139784505, + UseHeightmap = false + }, + ['1969-07-20T20:15:21'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.49826864115494, + Latitude = 0.6763489810183512, + Altitude = -1896.601844270979, + UseHeightmap = false + }, + ['1969-07-20T20:15:22'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.49765193973772, + Latitude = 0.6763177659437667, + Altitude = -1897.41890100069, + UseHeightmap = false + }, + ['1969-07-20T20:15:23'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.49706547748806, + Latitude = 0.6762368192356724, + Altitude = -1898.2359577304012, + UseHeightmap = false + }, + ['1969-07-20T20:15:24'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.496489420526313, + Latitude = 0.676209886695223, + Altitude = -1899.053014460112, + UseHeightmap = false + }, + ['1969-07-20T20:15:25'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.495878153012562, + Latitude = 0.6761763249034947, + Altitude = -1900.1424234330602, + UseHeightmap = false + }, + ['1969-07-20T20:15:26'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.4953425244022, + Latitude = 0.6761311089575274, + Altitude = -1901.5041846492454, + UseHeightmap = false + }, + ['1969-07-20T20:15:27'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.494725217962213, + Latitude = 0.6761017566851846, + Altitude = -1902.5935936221936, + UseHeightmap = false + }, + ['1969-07-20T20:15:28'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.494112443564592, + Latitude = 0.6760842983575135, + Altitude = -1903.4106503519047, + UseHeightmap = false + }, + ['1969-07-20T20:15:29'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.493537644480202, + Latitude = 0.6760386448926926, + Altitude = -1903.9553548383788, + UseHeightmap = false + }, + ['1969-07-20T20:15:30'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.49299719757025, + Latitude = 0.6760147528943234, + Altitude = -1903.9553548383788, + UseHeightmap = false + }, + ['1969-07-20T20:15:31'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.492415313069813, + Latitude = 0.6759919962423392, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:32'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.491877755110142, + Latitude = 0.6759640721591937, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:33'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.49128819308786, + Latitude = 0.6759491077295323, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:34'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.49073158429634, + Latitude = 0.6759379383686839, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:35'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.490174891596332, + Latitude = 0.6759054634588104, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:36'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.489635065407523, + Latitude = 0.6758939648884956, + Altitude = -1904.5000593248528, + UseHeightmap = false + }, + ['1969-07-20T20:15:37'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.4891060535486, + Latitude = 0.6759004097281942, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:38'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48855436619652, + Latitude = 0.6758862600165565, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:39'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.488052711552413, + Latitude = 0.6758544116957282, + Altitude = -1904.5000593248528, + UseHeightmap = false + }, + ['1969-07-20T20:15:40'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48754943516269, + Latitude = 0.6758316193430558, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:41'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.487094304824993, + Latitude = 0.6758175052522961, + Altitude = -1904.2277070816158, + UseHeightmap = false + }, + ['1969-07-20T20:15:42'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.486618165034592, + Latitude = 0.6757757367756437, + Altitude = -1904.7724115680899, + UseHeightmap = false + }, + ['1969-07-20T20:15:43'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48604740534131, + Latitude = 0.675733428263931, + Altitude = -1905.3171160545637, + UseHeightmap = false + }, + ['1969-07-20T20:15:44'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48548248435554, + Latitude = 0.6756797157749009, + Altitude = -1905.8618205410378, + UseHeightmap = false + }, + ['1969-07-20T20:15:45'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48494957486896, + Latitude = 0.6756120527881188, + Altitude = -1905.8618205410378, + UseHeightmap = false + }, + ['1969-07-20T20:15:46'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.484598386683622, + Latitude = 0.675584857481579, + Altitude = -1907.49593400046, + UseHeightmap = false + }, + ['1969-07-20T20:15:47'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.4841269963268, + Latitude = 0.6755482784409179, + Altitude = -1908.040638486934, + UseHeightmap = false + }, + ['1969-07-20T20:15:48'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48373390336955, + Latitude = 0.6754890811171497, + Altitude = -1908.8576952166452, + UseHeightmap = false + }, + ['1969-07-20T20:15:49'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48325134882829, + Latitude = 0.6754258626149947, + Altitude = -1908.4491668517896, + UseHeightmap = false + }, + ['1969-07-20T20:15:50'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48284574619883, + Latitude = 0.6753753196460469, + Altitude = -1909.1300474598822, + UseHeightmap = false + }, + ['1969-07-20T20:15:51'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48245362823393, + Latitude = 0.6753264776464533, + Altitude = -1909.4023997031193, + UseHeightmap = false + }, + ['1969-07-20T20:15:52'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.482060114185842, + Latitude = 0.6752749804130574, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:53'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.481698202127482, + Latitude = 0.675223605520775, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:54'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48129046365451, + Latitude = 0.6751730022703166, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:55'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.480893026154902, + Latitude = 0.6751376710849429, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:56'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48059324160945, + Latitude = 0.6750772226256051, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:57'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48034984354739, + Latitude = 0.6750430267458865, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:58'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.48005268645993, + Latitude = 0.6750019848756621, + Altitude = -1909.6747519463563, + UseHeightmap = false + }, + ['1969-07-20T20:15:59'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47978070153665, + Latitude = 0.6749655364121049, + Altitude = -1909.9471041895933, + UseHeightmap = false + }, + ['1969-07-20T20:16:00'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47951311851127, + Latitude = 0.6749420304945992, + Altitude = -1909.9471041895933, + UseHeightmap = false + }, + ['1969-07-20T20:16:01'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47927978098579, + Latitude = 0.6748989409040068, + Altitude = -1909.9471041895933, + UseHeightmap = false + }, + ['1969-07-20T20:16:02'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47904250519933, + Latitude = 0.6748472712728636, + Altitude = -1910.4918086760674, + UseHeightmap = false + }, + ['1969-07-20T20:16:03'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47879202998348, + Latitude = 0.674809514541568, + Altitude = -1910.7641609193045, + UseHeightmap = false + }, + ['1969-07-20T20:16:04'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.478567222437622, + Latitude = 0.6747692774477394, + Altitude = -1910.7641609193045, + UseHeightmap = false + }, + ['1969-07-20T20:16:05'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47836548542964, + Latitude = 0.6747160116119115, + Altitude = -1910.7641609193045, + UseHeightmap = false + }, + ['1969-07-20T20:16:06'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47818769774975, + Latitude = 0.6746866473279819, + Altitude = -1911.3088654057785, + UseHeightmap = false + }, + ['1969-07-20T20:16:07'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.477896613823983, + Latitude = 0.6746547793250971, + Altitude = -1913.2153311084376, + UseHeightmap = false + }, + ['1969-07-20T20:16:08'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47781195503974, + Latitude = 0.6746276583132307, + Altitude = -1913.2153311084376, + UseHeightmap = false + }, + ['1969-07-20T20:16:09'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.477664452707373, + Latitude = 0.6746112868414526, + Altitude = -1914.0323878381487, + UseHeightmap = false + }, + -- ['1969-07-20T20:16:10'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.477750217762413, + -- Latitude = 0.6745910947360472, + -- Altitude = -1912.6706266219635, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:11'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.477590925415402, + -- Latitude = 0.6745598993839581, + -- Altitude = -1912.6706266219635, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:12'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47745952757753, + -- Latitude = 0.6745298610932787, + -- Altitude = -1912.6706266219635, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:13'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.477271343369093, + -- Latitude = 0.6745166392893209, + -- Altitude = -1913.2153311084376, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:14'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.477100932665042, + -- Latitude = 0.6744937499451563, + -- Altitude = -1914.3047400813857, + -- UseHeightmap = false + -- }, + ['1969-07-20T20:16:15'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47697690593997, + Latitude = 0.6744644602883288, + Altitude = -1914.8494445678598, + UseHeightmap = false + }, + ['1969-07-20T20:16:16'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.476842953277412, + Latitude = 0.6744457159538018, + Altitude = -1915.1217968110968, + UseHeightmap = false + }, + ['1969-07-20T20:16:17'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.476774052091812, + Latitude = 0.6744243634139203, + Altitude = -1914.8494445678598, + UseHeightmap = false + }, + ['1969-07-20T20:16:18'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47665204889191, + Latitude = 0.6743981221140924, + Altitude = -1915.1217968110968, + UseHeightmap = false + }, + ['1969-07-20T20:16:19'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47657652039885, + Latitude = 0.6743808573601865, + Altitude = -1915.1217968110968, + UseHeightmap = false + }, + ['1969-07-20T20:16:20'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.476475036022492, + Latitude = 0.6743552389834175, + Altitude = -1914.8494445678598, + UseHeightmap = false + }, + ['1969-07-20T20:16:21'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47638671770867, + Latitude = 0.6743412077411113, + Altitude = -1915.3941490543339, + UseHeightmap = false + }, + ['1969-07-20T20:16:22'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.476286834646782, + Latitude = 0.6743241644041175, + Altitude = -1915.3941490543339, + UseHeightmap = false + }, + ['1969-07-20T20:16:23'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47623840477727, + Latitude = 0.6743121023448013, + Altitude = -1915.3941490543339, + UseHeightmap = false + }, + ['1969-07-20T20:16:24'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.476125794037742, + Latitude = 0.6743019779643423, + Altitude = -1915.938853540808, + UseHeightmap = false + }, + ['1969-07-20T20:16:25'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47604582826371, + Latitude = 0.6742984062330349, + Altitude = -1916.211205784045, + UseHeightmap = false + }, + ['1969-07-20T20:16:26'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47599605084473, + Latitude = 0.6742864748966985, + Altitude = -1916.211205784045, + UseHeightmap = false + }, + ['1969-07-20T20:16:27'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47598166921822, + Latitude = 0.6742856341308172, + Altitude = -1916.755910270519, + UseHeightmap = false + }, + -- ['1969-07-20T20:16:28'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47600003592791, + -- Latitude = 0.6742816108377042, + -- Altitude = -1916.211205784045, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:29'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47593990066764, + -- Latitude = 0.6742699316275284, + -- Altitude = -1916.483558027282, + -- UseHeightmap = false + -- }, + ['1969-07-20T20:16:30'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47587957412098, + Latitude = 0.6742661771136219, + Altitude = -1916.755910270519, + UseHeightmap = false + }, + ['1969-07-20T20:16:31'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47579282136856, + Latitude = 0.6742214263433656, + Altitude = -1917.028262513756, + UseHeightmap = false + }, + ['1969-07-20T20:16:32'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47571834266516, + Latitude = 0.6741885448706321, + Altitude = -1917.5729670002302, + UseHeightmap = false + }, + -- ['1969-07-20T20:16:33'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47569457676149, + -- Latitude = 0.6741859152655852, + -- Altitude = -1917.3006147569931, + -- UseHeightmap = false + -- }, + ['1969-07-20T20:16:34'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47557041293751, + Latitude = 0.6741798073326593, + Altitude = -1918.117671486704, + UseHeightmap = false + }, + ['1969-07-20T20:16:35'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.475475681892203, + Latitude = 0.6741822414281841, + Altitude = -1918.117671486704, + UseHeightmap = false + }, + ['1969-07-20T20:16:36'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47541533097675, + Latitude = 0.6742009046793005, + Altitude = -1918.390023729941, + UseHeightmap = false + }, + ['1969-07-20T20:16:37'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47532207549478, + Latitude = 0.6742269926054295, + Altitude = -1918.662375973178, + UseHeightmap = false + }, + ['1969-07-20T20:16:38'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47522251798864, + Latitude = 0.6742695236577596, + Altitude = -1918.662375973178, + UseHeightmap = false + }, + ['1969-07-20T20:16:39'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47513564425997, + Latitude = 0.6742809051574165, + Altitude = -1918.662375973178, + UseHeightmap = false + }, + ['1969-07-20T20:16:40'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47498810518855, + Latitude = 0.6743095342428154, + Altitude = -1920.2964894326003, + UseHeightmap = false + }, + -- ['1969-07-20T20:16:41'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47489523759891, + -- Latitude = 0.6743154022599566, + -- Altitude = -1920.0241371893633, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:42'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47479438729774, + -- Latitude = 0.6743324078003049, + -- Altitude = -1920.2964894326003, + -- UseHeightmap = false + -- }, + -- ['1969-07-20T20:16:43'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47475788126512, + -- Latitude = 0.674345583979325, + -- Altitude = -1920.0241371893633, + -- UseHeightmap = false + -- }, + ['1969-07-20T20:16:44'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.474678823712882, + Latitude = 0.6743691203511213, + Altitude = -1920.2964894326003, + UseHeightmap = false + }, + ['1969-07-20T20:16:45'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47460302474115, + Latitude = 0.6743890347121807, + Altitude = -1920.2964894326003, + UseHeightmap = false + }, + ['1969-07-20T20:16:46'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47450130965027, + Latitude = 0.6744202280781089, + Altitude = -1920.8411939190744, + UseHeightmap = false + }, + ['1969-07-20T20:16:47'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.474379586340042, + Latitude = 0.6744490653475903, + Altitude = -1921.1135461623114, + UseHeightmap = false + }, + ['1969-07-20T20:16:48'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47431921657337, + Latitude = 0.6745028925523043, + Altitude = -1921.1135461623114, + UseHeightmap = false + }, + ['1969-07-20T20:16:49'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47424698504895, + Latitude = 0.6745115395661241, + Altitude = -1921.1135461623114, + UseHeightmap = false + }, + ['1969-07-20T20:16:50'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.474158028620153, + Latitude = 0.6745268900936557, + Altitude = -1921.6582506487855, + UseHeightmap = false + }, + ['1969-07-20T20:16:51'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47408003386958, + Latitude = 0.674531434078838, + Altitude = -1921.6582506487855, + UseHeightmap = false + }, + ['1969-07-20T20:16:52'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473993195514502, + Latitude = 0.6745434127092755, + Altitude = -1921.9306028920225, + UseHeightmap = false + }, + -- ['1969-07-20T20:16:53'] = { + -- Type = "GlobeTranslation", + -- Globe = "Moon", + -- Longitude = 23.47392353665608, + -- Latitude = 0.6745464032805983, + -- Altitude = -1922.2029551352596, + -- UseHeightmap = false + -- }, + ['1969-07-20T20:16:54'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47388537487237, + Latitude = 0.674552865152663, + Altitude = -1921.9306028920225, + UseHeightmap = false + }, + ['1969-07-20T20:16:55'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47382957912373, + Latitude = 0.6745443566727537, + Altitude = -1921.9306028920225, + UseHeightmap = false + }, + ['1969-07-20T20:16:56'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47378652829031, + Latitude = 0.6745361955127924, + Altitude = -1921.6582506487855, + UseHeightmap = false + }, + ['1969-07-20T20:16:57'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473741159081282, + Latitude = 0.6745139398577651, + Altitude = -1921.6582506487855, + UseHeightmap = false + }, + ['1969-07-20T20:16:58'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473674434325403, + Latitude = 0.6745046665169872, + Altitude = -1922.2029551352596, + UseHeightmap = false + }, + ['1969-07-20T20:16:59'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47366202033169, + Latitude = 0.6744553774680945, + Altitude = -1922.2029551352596, + UseHeightmap = false + }, + ['1969-07-20T20:17:00'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47360771579434, + Latitude = 0.6744345598586292, + Altitude = -1922.7476596217336, + UseHeightmap = false + }, + ['1969-07-20T20:17:01'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47357090816817, + Latitude = 0.6744054827778567, + Altitude = -1923.0200118649707, + UseHeightmap = false + }, + ['1969-07-20T20:17:02'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47354290217646, + Latitude = 0.6743765403194303, + Altitude = -1923.2923641082077, + UseHeightmap = false + }, + ['1969-07-20T20:17:03'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47354640286736, + Latitude = 0.6743332580785223, + Altitude = -1923.5647163514448, + UseHeightmap = false + }, + ['1969-07-20T20:17:04'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473541367503802, + Latitude = 0.6742974556070759, + Altitude = -1923.8370685946818, + UseHeightmap = false + }, + ['1969-07-20T20:17:05'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47350854369485, + Latitude = 0.6742858449512636, + Altitude = -1924.1094208379188, + UseHeightmap = false + }, + ['1969-07-20T20:17:06'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47347424911663, + Latitude = 0.6742611487873781, + Altitude = -1924.6541253243927, + UseHeightmap = false + }, + ['1969-07-20T20:17:07'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473503629496022, + Latitude = 0.6742462694505276, + Altitude = -1924.6541253243927, + UseHeightmap = false + }, + ['1969-07-20T20:17:08'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473512768546712, + Latitude = 0.6742384048959066, + Altitude = -1924.6541253243927, + UseHeightmap = false + }, + ['1969-07-20T20:17:09'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47353343175876, + Latitude = 0.6742241072273591, + Altitude = -1924.3817730811559, + UseHeightmap = false + }, + ['1969-07-20T20:17:10'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47353316391657, + Latitude = 0.6742142580747189, + Altitude = -1925.4711820541038, + UseHeightmap = false + }, + ['1969-07-20T20:17:11'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47355774790429, + Latitude = 0.6742015107317392, + Altitude = -1924.9264775676297, + UseHeightmap = false + }, + ['1969-07-20T20:17:12'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.4735540335665, + Latitude = 0.6741800864866416, + Altitude = -1924.9264775676297, + UseHeightmap = false + }, + ['1969-07-20T20:17:13'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47353500681606, + Latitude = 0.6741617950501063, + Altitude = -1925.1988298108668, + UseHeightmap = false + }, + ['1969-07-20T20:17:14'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47350664772458, + Latitude = 0.6741447111551033, + Altitude = -1925.4711820541038, + UseHeightmap = false + }, + ['1969-07-20T20:17:15'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473494757982273, + Latitude = 0.6741430011390509, + Altitude = -1925.4711820541038, + UseHeightmap = false + }, + ['1969-07-20T20:17:16'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473485349949943, + Latitude = 0.6741431504511513, + Altitude = -1925.4711820541038, + UseHeightmap = false + }, + ['1969-07-20T20:17:17'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473464448566723, + Latitude = 0.674141681840806, + Altitude = -1925.4711820541038, + UseHeightmap = false + }, + ['1969-07-20T20:17:18'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47344203973089, + Latitude = 0.6741518055278933, + Altitude = -1925.4711820541038, + UseHeightmap = false + }, + ['1969-07-20T20:17:19'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473416197134252, + Latitude = 0.6741705280217748, + Altitude = -1925.7435342973408, + UseHeightmap = false + }, + ['1969-07-20T20:17:20'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47339416150648, + Latitude = 0.6741799656622618, + Altitude = -1925.7435342973408, + UseHeightmap = false + }, + ['1969-07-20T20:17:21'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.4733232813815, + Latitude = 0.6741727841821631, + Altitude = -1926.288238783815, + UseHeightmap = false + }, + ['1969-07-20T20:17:24'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47324174890097, + Latitude = 0.6742091863213222, + Altitude = -1926.288238783815, + UseHeightmap = false + }, + ['1969-07-20T20:17:27'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47317556908458, + Latitude = 0.6742072669430229, + Altitude = -1926.560591027052, + UseHeightmap = false + }, + ['1969-07-20T20:17:30'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47310752310149, + Latitude = 0.6742134078571678, + Altitude = -1926.832943270289, + UseHeightmap = false + }, + ['1969-07-20T20:17:32'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.473074792306253, + Latitude = 0.6741925230045956, + Altitude = -1927.105295513526, + UseHeightmap = false + }, + ['1969-07-20T20:17:40'] = { + Type = "GlobeTranslation", + Globe = "Moon", + Longitude = 23.47306, + Latitude = 0.67402, + Altitude = -1927.65, + UseHeightmap = false + }, +}; + +asset.export('keyframes', keyframes); + diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent_rotation.asset b/data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent_rotation.asset new file mode 100644 index 0000000000..2c45cb9d0f --- /dev/null +++ b/data/assets/scene/solarsystem/missions/apollo/apollo11_lem_descent_rotation.asset @@ -0,0 +1,1587 @@ +asset.export('keyframes', { + -- ['1969-7-20T20:9:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3815, -0.0048, -0.4891} + -- }, + -- ['1969-7-20T20:9:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3773, 0.0042, -0.3557} + -- }, + -- ['1969-7-20T20:9:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3677, 0.0184, -0.2218} + -- }, + -- ['1969-7-20T20:9:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3606, -0.0117, -0.0861} + -- }, + -- ['1969-7-20T20:10:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3587, -0.0222, -0.0219} + -- }, + -- ['1969-7-20T20:10:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3622, -0.0207, -0.0533} + -- }, + -- ['1969-7-20T20:10:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3639, -0.0032, -0.0640} + -- }, + -- ['1969-7-20T20:10:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3612, 0.0178, -0.0685} + -- }, + -- ['1969-7-20T20:10:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3571, 0.0196, -0.0796} + -- }, + -- ['1969-7-20T20:10:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3484, 0.0029, -0.0913} + -- }, + -- ['1969-7-20T20:10:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3597, -0.0149, -0.0832} + -- }, + -- ['1969-7-20T20:10:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3587, -0.0220, -0.0679} + -- }, + -- ['1969-7-20T20:10:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3482, -0.0121, -0.0736} + -- }, + -- ['1969-7-20T20:10:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3520, -0.0098, -0.0876} + -- }, + -- ['1969-7-20T20:10:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3503, -0.0240, -0.0872} + -- }, + -- ['1969-7-20T20:10:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3470, 0.0245, -0.0545} + -- }, + -- ['1969-7-20T20:10:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3420, 0.0115, -0.0518} + -- }, + -- ['1969-7-20T20:10:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3294, -0.0153, -0.0556} + -- }, + -- ['1969-7-20T20:10:31'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3399, -0.0136, -0.0573} + -- }, + -- ['1969-7-20T20:10:33'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3459, 0.0002, -0.0569} + -- }, + -- ['1969-7-20T20:10:35'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3440, 0.0012, -0.0542} + -- }, + -- ['1969-7-20T20:10:37'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3230, -0.0096, -0.0527} + -- }, + -- ['1969-7-20T20:10:39'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2966, -0.0119, -0.0510} + -- }, + -- ['1969-7-20T20:10:41'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3146, -0.0040, -0.0504} + -- }, + -- ['1969-7-20T20:10:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.3355, -0.0015, -0.0514} + -- }, + -- ['1969-7-20T20:10:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2916, 0.0061, -0.0516} + -- }, + -- ['1969-7-20T20:10:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2901, -0.0257, -0.0516} + -- }, + -- ['1969-7-20T20:10:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2818, -0.0123, -0.0495} + -- }, + -- ['1969-7-20T20:10:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2682, 0.0058, -0.0477} + -- }, + -- ['1969-7-20T20:10:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2732, 0.0035, -0.0195} + -- }, + -- ['1969-7-20T20:10:54'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2740, 0.0029, 0.0123} + -- }, + -- ['1969-7-20T20:10:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2778, 0.0035, 0.0234} + -- }, + -- ['1969-7-20T20:10:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2573, 0.0069, 0.0174} + -- }, + -- ['1969-7-20T20:10:58'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2515, -0.0023, 0.0115} + -- }, + -- ['1969-7-20T20:10:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2333, -0.0092, 0.0092} + -- }, + -- ['1969-7-20T20:11:0'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2191, -0.0157, 0.0056} + -- }, + -- ['1969-7-20T20:11:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2246, -0.0195, 0.0029} + -- }, + -- ['1969-7-20T20:11:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2419, -0.0146, -0.0019} + -- }, + -- ['1969-7-20T20:11:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2274, -0.0054, -0.0048} + -- }, + -- ['1969-7-20T20:11:6'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2218, -0.0042, -0.0056} + -- }, + -- ['1969-7-20T20:11:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2047, 0.0010, -0.0065} + -- }, + -- ['1969-7-20T20:11:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2042, -0.0054, -0.0069} + -- }, + -- ['1969-7-20T20:11:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2007, -0.0100, -0.0077} + -- }, + -- ['1969-7-20T20:11:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2136, -0.0173, -0.0077} + -- }, + -- ['1969-7-20T20:11:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.2013, -0.0021, -0.0077} + -- }, + -- ['1969-7-20T20:11:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1928, 0.0102, -0.0056} + -- }, + -- ['1969-7-20T20:11:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1854, 0.0090, -0.0057} + -- }, + -- ['1969-7-20T20:11:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1856, -0.0075, -0.0044} + -- }, + -- ['1969-7-20T20:11:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1670, -0.0157, -0.0023} + -- }, + -- ['1969-7-20T20:11:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1599, -0.0149, 0.0012} + -- }, + -- ['1969-7-20T20:11:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1514, -0.0119, 0.0012} + -- }, + -- ['1969-7-20T20:11:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1465, -0.0094, 0.0040} + -- }, + -- ['1969-7-20T20:11:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1593, -0.0176, 0.0063} + -- }, + -- ['1969-7-20T20:11:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1712, -0.0144, 0.0132} + -- }, + -- ['1969-7-20T20:11:24'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1727, -0.0052, 0.0176} + -- }, + -- ['1969-7-20T20:11:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1652, 0.0083, 0.0190} + -- }, + -- ['1969-7-20T20:11:26'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1827, -0.0044, 0.0178} + -- }, + -- ['1969-7-20T20:11:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1942, -0.0172, 0.0180} + -- }, + -- ['1969-7-20T20:11:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1788, -0.0071, 0.0188} + -- }, + -- ['1969-7-20T20:11:30'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1639, 0.0035, 0.0176} + -- }, + -- ['1969-7-20T20:11:31'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1614, 0.0048, 0.0178} + -- }, + -- ['1969-7-20T20:11:31'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1551, 0.0083, 0.0169} + -- }, + -- ['1969-7-20T20:11:33'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1643, 0.0060, 0.0175} + -- }, + -- ['1969-7-20T20:11:35'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1746, 0.0006, 0.0173} + -- }, + -- ['1969-7-20T20:11:35'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1679, -0.0008, 0.0178} + -- }, + -- ['1969-7-20T20:11:37'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1735, -0.0127, 0.0173} + -- }, + -- ['1969-7-20T20:11:37'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1599, -0.0044, 0.0186} + -- }, + -- ['1969-7-20T20:11:39'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1545, 0.0012, 0.0167} + -- }, + -- ['1969-7-20T20:11:39'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1461, 0.0075, 0.0169} + -- }, + -- ['1969-7-20T20:11:41'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1470, 0.0012, 0.0155} + -- }, + -- ['1969-7-20T20:11:41'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1442, -0.0086, 0.0148} + -- }, + -- ['1969-7-20T20:11:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1411, -0.0236, 0.0142} + -- }, + -- ['1969-7-20T20:11:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1302, -0.0240, 0.0131} + -- }, + -- ['1969-7-20T20:11:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1098, -0.0115, 0.0140} + -- }, + -- ['1969-7-20T20:11:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1043, -0.0088, 0.0134} + -- }, + -- ['1969-7-20T20:11:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0979, -0.0025, 0.0144} + -- }, + -- ['1969-7-20T20:11:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1092, -0.0125, 0.0144} + -- }, + -- ['1969-7-20T20:11:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1175, -0.0205, 0.0146} + -- }, + -- ['1969-7-20T20:11:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1230, -0.0249, 0.0157} + -- }, + -- ['1969-7-20T20:11:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1099, -0.0119, 0.0161} + -- }, + -- ['1969-7-20T20:11:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.1056, -0.0071, 0.0167} + -- }, + -- ['1969-7-20T20:11:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0916, 0.0044, 0.0131} + -- }, + -- ['1969-7-20T20:11:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0901, 0.0073, 0.0111} + -- }, + -- ['1969-7-20T20:11:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0839, 0.0040, 0.0075} + -- }, + -- ['1969-7-20T20:11:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0832, 0.0015, 0.0050} + -- }, + -- ['1969-7-20T20:11:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0831, -0.0109, 0.0003} + -- }, + -- ['1969-7-20T20:11:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0812, -0.0147, -0.0009} + -- }, + -- ['1969-7-20T20:11:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0814, -0.0278, -0.0031} + -- }, + -- ['1969-7-20T20:11:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0696, -0.0224, -0.0050} + -- }, + -- ['1969-7-20T20:12:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0617, -0.0242, -0.0067} + -- }, + -- ['1969-7-20T20:12:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0508, -0.0174, -0.0075} + -- }, + -- ['1969-7-20T20:12:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0523, -0.0174, -0.0094} + -- }, + -- ['1969-7-20T20:12:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0466, -0.0117, -0.0094} + -- }, + -- ['1969-7-20T20:12:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0565, -0.0107, -0.0109} + -- }, + -- ['1969-7-20T20:12:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0559, -0.0080, -0.0109} + -- }, + -- ['1969-7-20T20:12:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0686, -0.0065, -0.0113} + -- }, + -- ['1969-7-20T20:12:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0692, -0.0082, -0.0115} + -- }, + -- ['1969-7-20T20:12:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0722, -0.0075, -0.0107} + -- }, + -- ['1969-7-20T20:12:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0707, -0.0144, -0.0113} + -- }, + -- ['1969-7-20T20:12:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0630, -0.0153, -0.0103} + -- }, + -- ['1969-7-20T20:12:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0605, -0.0261, -0.0102} + -- }, + -- ['1969-7-20T20:12:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0441, -0.0305, -0.0096} + -- }, + -- ['1969-7-20T20:12:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0427, -0.0410, -0.0086} + -- }, + -- ['1969-7-20T20:12:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0283, -0.0228, -0.0075} + -- }, + -- ['1969-7-20T20:12:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0329, -0.0178, -0.0050} + -- }, + -- ['1969-7-20T20:12:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0260, -0.0009, -0.0027} + -- }, + -- ['1969-7-20T20:12:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0404, -0.0059, -0.0004} + -- }, + -- ['1969-7-20T20:12:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0467, -0.0140, 0.0023} + -- }, + -- ['1969-7-20T20:12:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0584, -0.0220, 0.0044} + -- }, + -- ['1969-7-20T20:12:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0416, -0.0176, 0.0088} + -- }, + -- ['1969-7-20T20:12:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0370, -0.0102, 0.0104} + -- }, + -- ['1969-7-20T20:12:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0222, -0.0063, 0.0121} + -- }, + -- ['1969-7-20T20:12:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0193, 0.0006, 0.0108} + -- }, + -- ['1969-7-20T20:12:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0166, -0.0059, 0.0098} + -- }, + -- ['1969-7-20T20:12:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0164, -0.0038, 0.0092} + -- }, + -- ['1969-7-20T20:12:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0237, -0.0188, 0.0081} + -- }, + -- ['1969-7-20T20:12:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0249, -0.0199, 0.0081} + -- }, + -- ['1969-7-20T20:12:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0329, -0.0330, 0.0077} + -- }, + -- ['1969-7-20T20:12:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0209, -0.0255, 0.0079} + -- }, + -- ['1969-7-20T20:12:31'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0157, -0.0205, 0.0084} + -- }, + -- ['1969-7-20T20:12:31'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0034, -0.0159, 0.0092} + -- }, + -- ['1969-7-20T20:12:33'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0044, -0.0136, 0.0106} + -- }, + -- ['1969-7-20T20:12:33'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9963, -0.0161, 0.0096} + -- }, + -- ['1969-7-20T20:12:35'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0036, -0.0180, 0.0084} + -- }, + -- ['1969-7-20T20:12:35'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9998, -0.0253, 0.0073} + -- }, + -- ['1969-7-20T20:12:37'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0088, -0.0265, 0.0065} + -- }, + -- ['1969-7-20T20:12:37'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0105, -0.0339, 0.0065} + -- }, + -- ['1969-7-20T20:12:39'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0230, -0.0280, 0.0060} + -- }, + -- ['1969-7-20T20:12:39'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0253, -0.0282, 0.0067} + -- }, + -- ['1969-7-20T20:12:41'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0216, -0.0071, 0.0067} + -- }, + -- ['1969-7-20T20:12:42'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0118, -0.0115, 0.0079} + -- }, + -- ['1969-7-20T20:12:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9946, -0.0098, 0.0077} + -- }, + -- ['1969-7-20T20:12:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9927, -0.0172, 0.0081} + -- }, + -- ['1969-7-20T20:12:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9890, -0.0147, 0.0094} + -- }, + -- ['1969-7-20T20:12:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0046, -0.0125, 0.0094} + -- }, + -- ['1969-7-20T20:12:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0109, -0.0048, 0.0104} + -- }, + -- ['1969-7-20T20:12:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0186, -0.0057, 0.0083} + -- }, + -- ['1969-7-20T20:12:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9940, -0.0226, 0.0048} + -- }, + -- ['1969-7-20T20:12:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9861, -0.0278, 0.0023} + -- }, + -- ['1969-7-20T20:12:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9712, -0.0301, 0.0000} + -- }, + -- ['1969-7-20T20:12:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9768, -0.0176, -0.0013} + -- }, + -- ['1969-7-20T20:12:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9791, -0.0088, -0.0025} + -- }, + -- ['1969-7-20T20:12:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9890, -0.0017, -0.0036} + -- }, + -- ['1969-7-20T20:12:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9906, -0.0245, -0.0056} + -- }, + -- ['1969-7-20T20:12:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9892, -0.0303, -0.0067} + -- }, + -- ['1969-7-20T20:12:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9852, -0.0470, -0.0086} + -- }, + -- ['1969-7-20T20:12:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9837, -0.0307, -0.0088} + -- }, + -- ['1969-7-20T20:12:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9873, -0.0128, -0.0090} + -- }, + -- ['1969-7-20T20:12:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9861, 0.0010, -0.0088} + -- }, + -- ['1969-7-20T20:13:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9944, -0.0117, -0.0094} + -- }, + -- ['1969-7-20T20:13:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9900, -0.0194, -0.0100} + -- }, + -- ['1969-7-20T20:13:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9917, -0.0355, -0.0103} + -- }, + -- ['1969-7-20T20:13:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9856, -0.0395, -0.0105} + -- }, + -- ['1969-7-20T20:13:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9969, -0.0299, -0.0096} + -- }, + -- ['1969-7-20T20:13:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9965, -0.0228, -0.0088} + -- }, + -- ['1969-7-20T20:13:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-1.0015, -0.0073, -0.0075} + -- }, + -- ['1969-7-20T20:13:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9908, -0.0098, -0.0067} + -- }, + -- ['1969-7-20T20:13:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9814, -0.0034, -0.0057} + -- }, + -- ['1969-7-20T20:13:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9729, -0.0071, -0.0044} + -- }, + -- ['1969-7-20T20:13:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9716, -0.0002, -0.0029} + -- }, + -- ['1969-7-20T20:13:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9729, -0.0044, -0.0013} + -- }, + -- ['1969-7-20T20:13:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9793, 0.0010, 0.0006} + -- }, + -- ['1969-7-20T20:13:14'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9869, -0.0040, 0.0031} + -- }, + -- ['1969-7-20T20:13:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9938, -0.0031, 0.0048} + -- }, + -- ['1969-7-20T20:13:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9978, -0.0134, 0.0067} + -- }, + -- ['1969-7-20T20:13:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9881, -0.0334, 0.0048} + -- }, + -- ['1969-7-20T20:13:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9881, -0.0449, 0.0023} + -- }, + -- ['1969-7-20T20:13:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9756, -0.0447, -0.0015} + -- }, + -- ['1969-7-20T20:13:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9804, -0.0351, -0.0034} + -- }, + -- ['1969-7-20T20:13:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9769, -0.0269, -0.0052} + -- }, + -- ['1969-7-20T20:13:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9816, -0.0182, -0.0073} + -- }, + -- ['1969-7-20T20:13:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9783, -0.0192, -0.0084} + -- }, + -- ['1969-7-20T20:13:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9808, -0.0149, -0.0103} + -- }, + -- ['1969-7-20T20:13:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9771, -0.0197, -0.0117} + -- }, + -- ['1969-7-20T20:13:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9748, -0.0171, -0.0127} + -- }, + -- ['1969-7-20T20:13:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9710, -0.0197, -0.0144} + -- }, + -- ['1969-7-20T20:13:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9643, -0.0186, -0.0146} + -- }, + -- ['1969-7-20T20:13:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9616, -0.0165, -0.0159} + -- }, + -- ['1969-7-20T20:13:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9534, -0.0163, -0.0159} + -- }, + -- ['1969-7-20T20:13:31'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.9605, -0.0096, -0.0165} + -- }, + -- ['1969-7-20T20:13:41'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.8092, -0.0297, -0.0155} + -- }, + -- ['1969-7-20T20:13:41'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.8097, -0.0389, -0.0149} + -- }, + -- ['1969-7-20T20:13:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7923, -0.0358, -0.0138} + -- }, + -- ['1969-7-20T20:13:43'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7988, -0.0267, -0.0125} + -- }, + -- ['1969-7-20T20:13:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7909, -0.0128, -0.0094} + -- }, + -- ['1969-7-20T20:13:45'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7967, -0.0061, -0.0080} + -- }, + -- ['1969-7-20T20:13:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7748, -0.0207, -0.0056} + -- }, + -- ['1969-7-20T20:13:47'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7681, -0.0278, -0.0048} + -- }, + -- ['1969-7-20T20:13:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7574, -0.0426, -0.0027} + -- }, + -- ['1969-7-20T20:13:49'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7582, -0.0364, -0.0004} + -- }, + -- ['1969-7-20T20:13:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7699, -0.0324, 0.0036} + -- }, + -- ['1969-7-20T20:13:51'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7676, -0.0245, 0.0040} + -- }, + -- ['1969-7-20T20:13:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7733, -0.0194, 0.0023} + -- }, + -- ['1969-7-20T20:13:53'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7574, -0.0207, 0.0008} + -- }, + -- ['1969-7-20T20:13:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7440, -0.0310, -0.0017} + -- }, + -- ['1969-7-20T20:13:55'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7405, -0.0569, -0.0044} + -- }, + -- ['1969-7-20T20:13:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7549, -0.0587, -0.0054} + -- }, + -- ['1969-7-20T20:13:57'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7518, -0.0326, -0.0046} + -- }, + -- ['1969-7-20T20:13:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7465, 0.0040, -0.0050} + -- }, + -- ['1969-7-20T20:13:59'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.7465, 0.0113, -0.0050} + -- }, + -- ['1969-7-20T20:14:1'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6939, 0.0029, -0.0063} + -- }, + -- ['1969-7-20T20:14:2'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6912, 0.0079, -0.0079} + -- }, + -- ['1969-7-20T20:14:3'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6793, 0.0048, -0.0077} + -- }, + -- ['1969-7-20T20:14:4'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6817, 0.0090, -0.0098} + -- }, + -- ['1969-7-20T20:14:5'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6730, 0.0117, -0.0090} + -- }, + -- ['1969-7-20T20:14:6'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6684, 0.0102, -0.0096} + -- }, + -- ['1969-7-20T20:14:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6604, 0.0115, -0.0109} + -- }, + -- ['1969-7-20T20:14:7'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6418, 0.0006, -0.0098} + -- }, + -- ['1969-7-20T20:14:9'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6301, -0.0067, -0.0121} + -- }, + -- ['1969-7-20T20:14:10'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6128, -0.0142, -0.0119} + -- }, + -- ['1969-7-20T20:14:11'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6180, -0.0134, -0.0119} + -- }, + -- ['1969-7-20T20:14:12'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6249, -0.0057, -0.0121} + -- }, + -- ['1969-7-20T20:14:13'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6299, -0.0057, -0.0098} + -- }, + -- ['1969-7-20T20:14:14'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6437, -0.0009, -0.0100} + -- }, + -- ['1969-7-20T20:14:15'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6328, -0.0105, -0.0100} + -- }, + -- ['1969-7-20T20:14:16'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6285, -0.0232, -0.0088} + -- }, + -- ['1969-7-20T20:14:17'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6195, -0.0291, -0.0117} + -- }, + -- ['1969-7-20T20:14:18'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6073, -0.0374, -0.0127} + -- }, + -- ['1969-7-20T20:14:19'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.6027, -0.0362, -0.0132} + -- }, + -- ['1969-7-20T20:14:20'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5892, -0.0314, -0.0147} + -- }, + -- ['1969-7-20T20:14:21'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5829, -0.0096, -0.0157} + -- }, + -- ['1969-7-20T20:14:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5674, 0.0119, -0.0263} + -- }, + -- ['1969-7-20T20:14:23'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5674, 0.0261, -0.0324} + -- }, + -- ['1969-7-20T20:14:25'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5637, 0.0232, -0.0439} + -- }, + -- ['1969-7-20T20:14:26'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5670, 0.0081, -0.0525} + -- }, + -- ['1969-7-20T20:14:27'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5739, 0.0013, -0.0564} + -- }, + -- ['1969-7-20T20:14:28'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5660, -0.0021, -0.0587} + -- }, + -- ['1969-7-20T20:14:29'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5603, -0.0025, -0.0604} + -- }, + -- ['1969-7-20T20:14:30'] = { + -- Type = "StaticRotation", + -- Rotation = {-0.5394, 0.0092, -0.0562} + -- }, + ['1969-7-20T20:10:00'] = { + Type = "StaticRotation", + Rotation = {0, 0, 1.5708} + }, + ['1969-7-20T20:12:10'] = { + Type = "StaticRotation", + Rotation = {0, 0, 1.5708} + }, + ['1969-7-20T20:12:14'] = { + Type = "StaticRotation", + Rotation = {0, 0, 1.5708} + }, + ['1969-7-20T20:14:30'] = { + Type = "StaticRotation", + Rotation = {0, 0, 1.5708} + }, + + ['1969-7-20T20:14:31'] = { + Type = "StaticRotation", + Rotation = {-0.5133, 0.0131, -0.0531} + }, + ['1969-7-20T20:14:32'] = { + Type = "StaticRotation", + Rotation = {-0.5043, 0.0117, -0.0487} + }, + ['1969-7-20T20:14:33'] = { + Type = "StaticRotation", + Rotation = {-0.4893, 0.0090, -0.0447} + }, + ['1969-7-20T20:14:33'] = { + Type = "StaticRotation", + Rotation = {-0.4851, -0.0008, -0.0429} + }, + ['1969-7-20T20:14:35'] = { + Type = "StaticRotation", + Rotation = {-0.4865, -0.0057, -0.0382} + }, + ['1969-7-20T20:14:35'] = { + Type = "StaticRotation", + Rotation = {-0.4788, -0.0073, -0.0345} + }, + ['1969-7-20T20:14:37'] = { + Type = "StaticRotation", + Rotation = {-0.4824, -0.0130, -0.0307} + }, + ['1969-7-20T20:14:37'] = { + Type = "StaticRotation", + Rotation = {-0.4836, -0.0103, -0.0268} + }, + ['1969-7-20T20:14:39'] = { + Type = "StaticRotation", + Rotation = {-0.4792, -0.0121, -0.0203} + }, + ['1969-7-20T20:14:40'] = { + Type = "StaticRotation", + Rotation = {-0.4874, -0.0140, -0.0211} + }, + ['1969-7-20T20:14:41'] = { + Type = "StaticRotation", + Rotation = {-0.5030, 0.0002, -0.0209} + }, + ['1969-7-20T20:14:42'] = { + Type = "StaticRotation", + Rotation = {-0.5361, -0.0040, -0.0209} + }, + ['1969-7-20T20:14:44'] = { + Type = "StaticRotation", + Rotation = {-0.4715, -0.0040, -0.0234} + }, + ['1969-7-20T20:14:45'] = { + Type = "StaticRotation", + Rotation = {-0.4433, -0.0050, -0.0238} + }, + ['1969-7-20T20:14:46'] = { + Type = "StaticRotation", + Rotation = {-0.4280, -0.0019, -0.0268} + }, + ['1969-7-20T20:14:47'] = { + Type = "StaticRotation", + Rotation = {-0.4310, -0.0069, -0.0259} + }, + ['1969-7-20T20:14:48'] = { + Type = "StaticRotation", + Rotation = {-0.4389, -0.0147, -0.0257} + }, + ['1969-7-20T20:14:49'] = { + Type = "StaticRotation", + Rotation = {-0.4519, -0.0178, -0.0287} + }, + ['1969-7-20T20:14:50'] = { + Type = "StaticRotation", + Rotation = {-0.4579, -0.0201, -0.0278} + }, + ['1969-7-20T20:14:51'] = { + Type = "StaticRotation", + Rotation = {-0.4554, -0.0147, -0.0265} + }, + ['1969-7-20T20:14:52'] = { + Type = "StaticRotation", + Rotation = {-0.4468, -0.0084, -0.0284} + }, + ['1969-7-20T20:14:53'] = { + Type = "StaticRotation", + Rotation = {-0.4316, -0.0127, -0.0268} + }, + ['1969-7-20T20:14:53'] = { + Type = "StaticRotation", + Rotation = {-0.4228, -0.0171, -0.0255} + }, + ['1969-7-20T20:14:55'] = { + Type = "StaticRotation", + Rotation = {-0.4046, -0.0174, -0.0274} + }, + ['1969-7-20T20:14:57'] = { + Type = "StaticRotation", + Rotation = {-0.3806, -0.0211, -0.0243} + }, + ['1969-7-20T20:14:57'] = { + Type = "StaticRotation", + Rotation = {-0.3751, -0.0178, -0.0249} + }, + ['1969-7-20T20:14:59'] = { + Type = "StaticRotation", + Rotation = {-0.3670, -0.0153, -0.0230} + }, + ['1969-7-20T20:14:59'] = { + Type = "StaticRotation", + Rotation = {-0.3641, -0.0100, -0.0209} + }, + ['1969-7-20T20:15:1'] = { + Type = "StaticRotation", + Rotation = {-0.3526, -0.0021, -0.0207} + }, + ['1969-7-20T20:15:1'] = { + Type = "StaticRotation", + Rotation = {-0.3457, -0.0038, -0.0195} + }, + ['1969-7-20T20:15:3'] = { + Type = "StaticRotation", + Rotation = {-0.3371, -0.0038, -0.0161} + }, + ['1969-7-20T20:15:3'] = { + Type = "StaticRotation", + Rotation = {-0.3309, -0.0015, -0.0192} + }, + ['1969-7-20T20:15:5'] = { + Type = "StaticRotation", + Rotation = {-0.3263, -0.0096, -0.0232} + }, + ['1969-7-20T20:15:5'] = { + Type = "StaticRotation", + Rotation = {-0.3240, 0.0015, -0.0243} + }, + ['1969-7-20T20:15:7'] = { + Type = "StaticRotation", + Rotation = {-0.3160, 0.0061, -0.0295} + }, + ['1969-7-20T20:15:7'] = { + Type = "StaticRotation", + Rotation = {-0.3135, 0.0035, -0.0318} + }, + ['1969-7-20T20:15:9'] = { + Type = "StaticRotation", + Rotation = {-0.3074, 0.0108, -0.0341} + }, + ['1969-7-20T20:15:9'] = { + Type = "StaticRotation", + Rotation = {-0.3022, 0.0027, -0.0360} + }, + ['1969-7-20T20:15:11'] = { + Type = "StaticRotation", + Rotation = {-0.2995, -0.0061, -0.0406} + }, + ['1969-7-20T20:15:11'] = { + Type = "StaticRotation", + Rotation = {-0.2976, -0.0098, -0.0416} + }, + ['1969-7-20T20:15:13'] = { + Type = "StaticRotation", + Rotation = {-0.2901, -0.0127, -0.0447} + }, + ['1969-7-20T20:15:14'] = { + Type = "StaticRotation", + Rotation = {-0.2886, -0.0169, -0.0470} + }, + ['1969-7-20T20:15:15'] = { + Type = "StaticRotation", + Rotation = {-0.2700, -0.0174, -0.0491} + }, + ['1969-7-20T20:15:15'] = { + Type = "StaticRotation", + Rotation = {-0.2107, -0.0119, -0.0512} + }, + ['1969-7-20T20:15:17'] = { + Type = "StaticRotation", + Rotation = {-0.1630, -0.0123, -0.0560} + }, + ['1969-7-20T20:15:18'] = { + Type = "StaticRotation", + Rotation = {-0.1101, -0.0077, -0.0583} + }, + ['1969-7-20T20:15:19'] = { + Type = "StaticRotation", + Rotation = {-0.0868, -0.0029, -0.0613} + }, + ['1969-7-20T20:15:19'] = { + Type = "StaticRotation", + Rotation = {-0.0893, -0.0036, -0.0642} + }, + ['1969-7-20T20:15:21'] = { + Type = "StaticRotation", + Rotation = {-0.0892, -0.0029, -0.0675} + }, + ['1969-7-20T20:15:21'] = { + Type = "StaticRotation", + Rotation = {-0.0970, -0.0004, -0.0698} + }, + ['1969-7-20T20:15:23'] = { + Type = "StaticRotation", + Rotation = {-0.1020, -0.0079, -0.0736} + }, + ['1969-7-20T20:15:24'] = { + Type = "StaticRotation", + Rotation = {-0.0959, -0.0069, -0.0771} + }, + ['1969-7-20T20:15:25'] = { + Type = "StaticRotation", + Rotation = {-0.0999, -0.0057, -0.0794} + }, + ['1969-7-20T20:15:26'] = { + Type = "StaticRotation", + Rotation = {-0.1001, -0.0075, -0.0828} + }, + ['1969-7-20T20:15:27'] = { + Type = "StaticRotation", + Rotation = {-0.0966, -0.0067, -0.0849} + }, + ['1969-7-20T20:15:28'] = { + Type = "StaticRotation", + Rotation = {-0.1039, -0.0050, -0.0876} + }, + ['1969-7-20T20:15:29'] = { + Type = "StaticRotation", + Rotation = {-0.1055, -0.0059, -0.0893} + }, + ['1969-7-20T20:15:30'] = { + Type = "StaticRotation", + Rotation = {-0.1010, -0.0050, -0.0909} + }, + ['1969-7-20T20:15:31'] = { + Type = "StaticRotation", + Rotation = {-0.1066, -0.0036, -0.0903} + }, + ['1969-7-20T20:15:32'] = { + Type = "StaticRotation", + Rotation = {-0.1106, -0.0032, -0.0882} + }, + ['1969-7-20T20:15:33'] = { + Type = "StaticRotation", + Rotation = {-0.1074, -0.0019, -0.0874} + }, + ['1969-7-20T20:15:34'] = { + Type = "StaticRotation", + Rotation = {-0.1131, 0.0021, -0.0857} + }, + ['1969-7-20T20:15:35'] = { + Type = "StaticRotation", + Rotation = {-0.1193, 0.0036, -0.0842} + }, + ['1969-7-20T20:15:36'] = { + Type = "StaticRotation", + Rotation = {-0.1193, 0.0083, -0.0819} + }, + ['1969-7-20T20:15:37'] = { + Type = "StaticRotation", + Rotation = {-0.1233, 0.0129, -0.0809} + }, + ['1969-7-20T20:15:38'] = { + Type = "StaticRotation", + Rotation = {-0.1365, 0.0194, -0.0786} + }, + ['1969-7-20T20:15:39'] = { + Type = "StaticRotation", + Rotation = {-0.1334, 0.0230, -0.0765} + }, + ['1969-7-20T20:15:40'] = { + Type = "StaticRotation", + Rotation = {-0.1267, 0.0257, -0.0744} + }, + ['1969-7-20T20:15:41'] = { + Type = "StaticRotation", + Rotation = {-0.1271, 0.0288, -0.0732} + }, + ['1969-7-20T20:15:42'] = { + Type = "StaticRotation", + Rotation = {-0.1206, 0.0272, -0.0700} + }, + ['1969-7-20T20:15:43'] = { + Type = "StaticRotation", + Rotation = {-0.1465, 0.0244, -0.0692} + }, + ['1969-7-20T20:15:44'] = { + Type = "StaticRotation", + Rotation = {-0.1931, 0.0217, -0.0692} + }, + ['1969-7-20T20:15:45'] = { + Type = "StaticRotation", + Rotation = {-0.1981, 0.0205, -0.0679} + }, + ['1969-7-20T20:15:46'] = { + Type = "StaticRotation", + Rotation = {-0.2048, 0.0173, -0.0656} + }, + ['1969-7-20T20:15:47'] = { + Type = "StaticRotation", + Rotation = {-0.2151, 0.0169, -0.0650} + }, + ['1969-7-20T20:15:48'] = { + Type = "StaticRotation", + Rotation = {-0.2385, 0.0132, -0.0633} + }, + ['1969-7-20T20:15:49'] = { + Type = "StaticRotation", + Rotation = {-0.2590, 0.0092, -0.0623} + }, + ['1969-7-20T20:15:50'] = { + Type = "StaticRotation", + Rotation = {-0.2607, 0.0077, -0.0608} + }, + ['1969-7-20T20:15:51'] = { + Type = "StaticRotation", + Rotation = {-0.2646, 0.0056, -0.0600} + }, + ['1969-7-20T20:15:52'] = { + Type = "StaticRotation", + Rotation = {-0.2680, 0.0004, -0.0575} + }, + ['1969-7-20T20:15:53'] = { + Type = "StaticRotation", + Rotation = {-0.2682, -0.0011, -0.0560} + }, + ['1969-7-20T20:15:54'] = { + Type = "StaticRotation", + Rotation = {-0.2742, -0.0044, -0.0543} + }, + ['1969-7-20T20:15:55'] = { + Type = "StaticRotation", + Rotation = {-0.2757, -0.0061, -0.0522} + }, + ['1969-7-20T20:15:56'] = { + Type = "StaticRotation", + Rotation = {-0.2727, -0.0065, -0.0491} + }, + ['1969-7-20T20:15:57'] = { + Type = "StaticRotation", + Rotation = {-0.2724, -0.0063, -0.0474} + }, + ['1969-7-20T20:15:58'] = { + Type = "StaticRotation", + Rotation = {-0.2732, -0.0077, -0.0445} + }, + ['1969-7-20T20:15:59'] = { + Type = "StaticRotation", + Rotation = {-0.2709, -0.0092, -0.0420} + }, + ['1969-7-20T20:16:0'] = { + Type = "StaticRotation", + Rotation = {-0.2690, -0.0102, -0.0387} + }, + ['1969-7-20T20:16:1'] = { + Type = "StaticRotation", + Rotation = {-0.2704, -0.0115, -0.0368} + }, + ['1969-7-20T20:16:2'] = { + Type = "StaticRotation", + Rotation = {-0.2704, -0.0142, -0.0332} + }, + ['1969-7-20T20:16:3'] = { + Type = "StaticRotation", + Rotation = {-0.2700, -0.0153, -0.0305} + }, + ['1969-7-20T20:16:4'] = { + Type = "StaticRotation", + Rotation = {-0.2736, -0.0176, -0.0268} + }, + ['1969-7-20T20:16:5'] = { + Type = "StaticRotation", + Rotation = {-0.2752, -0.0199, -0.0243} + }, + ['1969-7-20T20:16:6'] = { + Type = "StaticRotation", + Rotation = {-0.2752, -0.0238, -0.0207} + }, + ['1969-7-20T20:16:7'] = { + Type = "StaticRotation", + Rotation = {-0.2702, -0.0245, -0.0205} + }, + ['1969-7-20T20:16:8'] = { + Type = "StaticRotation", + Rotation = {-0.1841, -0.0217, -0.0219} + }, + ['1969-7-20T20:16:9'] = { + Type = "StaticRotation", + Rotation = {-0.1632, -0.0217, -0.0226} + }, + ['1969-7-20T20:16:26'] = { + Type = "StaticRotation", + Rotation = {-0.0989, -0.0184, -0.0391} + }, + ['1969-7-20T20:16:27'] = { + Type = "StaticRotation", + Rotation = {-0.0968, -0.0167, -0.0393} + }, + ['1969-7-20T20:16:28'] = { + Type = "StaticRotation", + Rotation = {-0.0171, -0.0103, -0.0406} + }, + ['1969-7-20T20:16:29'] = { + Type = "StaticRotation", + Rotation = {-0.0157, -0.0105, -0.0412} + }, + ['1969-7-20T20:16:30'] = { + Type = "StaticRotation", + Rotation = {0.0127, -0.0103, -0.0427} + }, + ['1969-7-20T20:16:31'] = { + Type = "StaticRotation", + Rotation = {0.0134, -0.0147, -0.0433} + }, + ['1969-7-20T20:16:32'] = { + Type = "StaticRotation", + Rotation = {0.0042, -0.0370, -0.0470} + }, + ['1969-7-20T20:16:33'] = { + Type = "StaticRotation", + Rotation = {0.0092, -0.0506, -0.0487} + }, + ['1969-7-20T20:16:34'] = { + Type = "StaticRotation", + Rotation = {0.0244, -0.0512, -0.0510} + }, + ['1969-7-20T20:16:35'] = { + Type = "StaticRotation", + Rotation = {0.0042, -0.0546, -0.0512} + }, + ['1969-7-20T20:16:36'] = { + Type = "StaticRotation", + Rotation = {-0.0006, -0.0558, -0.0533} + }, + ['1969-7-20T20:16:37'] = { + Type = "StaticRotation", + Rotation = {0.0050, -0.0522, -0.0543} + }, + ['1969-7-20T20:16:38'] = { + Type = "StaticRotation", + Rotation = {0.0077, -0.0343, -0.0548} + }, + ['1969-7-20T20:16:39'] = { + Type = "StaticRotation", + Rotation = {-0.0004, -0.0155, -0.0550} + }, + ['1969-7-20T20:16:40'] = { + Type = "StaticRotation", + Rotation = {0.0036, -0.0105, -0.0571} + }, + ['1969-7-20T20:16:41'] = { + Type = "StaticRotation", + Rotation = {-0.0080, -0.0086, -0.0579} + }, + ['1969-7-20T20:16:42'] = { + Type = "StaticRotation", + Rotation = {-0.0698, -0.0140, -0.0604} + }, + ['1969-7-20T20:16:43'] = { + Type = "StaticRotation", + Rotation = {-0.0579, -0.0134, -0.0623} + }, + ['1969-7-20T20:16:44'] = { + Type = "StaticRotation", + Rotation = {-0.0462, -0.0090, -0.0648} + }, + ['1969-7-20T20:16:45'] = { + Type = "StaticRotation", + Rotation = {-0.0466, -0.0067, -0.0665} + }, + ['1969-7-20T20:16:46'] = { + Type = "StaticRotation", + Rotation = {-0.0529, -0.0027, -0.0694} + }, + ['1969-7-20T20:16:47'] = { + Type = "StaticRotation", + Rotation = {-0.0518, 0.0079, -0.0707} + }, + ['1969-7-20T20:16:48'] = { + Type = "StaticRotation", + Rotation = {-0.0602, 0.0299, -0.0729} + }, + ['1969-7-20T20:16:49'] = { + Type = "StaticRotation", + Rotation = {-0.0510, 0.0562, -0.0729} + }, + ['1969-7-20T20:16:50'] = { + Type = "StaticRotation", + Rotation = {-0.0539, 0.0562, -0.0765} + }, + ['1969-7-20T20:16:51'] = { + Type = "StaticRotation", + Rotation = {-0.0928, 0.0545, -0.0813} + }, + ['1969-7-20T20:16:52'] = { + Type = "StaticRotation", + Rotation = {-0.0886, 0.0560, -0.0844} + }, + ['1969-7-20T20:16:53'] = { + Type = "StaticRotation", + Rotation = {-0.0832, 0.0552, -0.0865} + }, + ['1969-7-20T20:16:54'] = { + Type = "StaticRotation", + Rotation = {-0.0805, 0.0573, -0.0899} + }, + ['1969-7-20T20:16:55'] = { + Type = "StaticRotation", + Rotation = {-0.0784, 0.0614, -0.0924} + }, + ['1969-7-20T20:16:56'] = { + Type = "StaticRotation", + Rotation = {-0.0729, 0.0635, -0.0945} + }, + ['1969-7-20T20:16:57'] = { + Type = "StaticRotation", + Rotation = {-0.0792, 0.0627, -0.0976} + }, + ['1969-7-20T20:17:7'] = { + Type = "StaticRotation", + Rotation = {-0.1056, -0.0366, -0.1402} + }, + ['1969-7-20T20:17:7'] = { + Type = "StaticRotation", + Rotation = {-0.1053, -0.0395, -0.1428} + }, + ['1969-7-20T20:17:9'] = { + Type = "StaticRotation", + Rotation = {-0.0725, -0.0314, -0.1503} + }, + ['1969-7-20T20:17:9'] = { + Type = "StaticRotation", + Rotation = {-0.0259, -0.0270, -0.1542} + }, + ['1969-7-20T20:17:11'] = { + Type = "StaticRotation", + Rotation = {0.0874, -0.0059, -0.1614} + }, + ['1969-7-20T20:17:12'] = { + Type = "StaticRotation", + Rotation = {0.0769, -0.0096, -0.1678} + }, + ['1969-7-20T20:17:13'] = { + Type = "StaticRotation", + Rotation = {0.0740, -0.0270, -0.1743} + }, + ['1969-7-20T20:17:14'] = { + Type = "StaticRotation", + Rotation = {0.0673, -0.0458, -0.1810} + }, + ['1969-7-20T20:17:15'] = { + Type = "StaticRotation", + Rotation = {0.0550, -0.0506, -0.1860} + }, + ['1969-7-20T20:17:16'] = { + Type = "StaticRotation", + Rotation = {0.0449, -0.0577, -0.1931} + }, + ['1969-7-20T20:17:17'] = { + Type = "StaticRotation", + Rotation = {0.0437, -0.0617, -0.1967} + }, + ['1969-7-20T20:17:18'] = { + Type = "StaticRotation", + Rotation = {0.0297, -0.0650, -0.2027} + }, + ['1969-7-20T20:17:19'] = { + Type = "StaticRotation", + Rotation = {0.0203, -0.0518, -0.2061} + }, + ['1969-7-20T20:17:20'] = { + Type = "StaticRotation", + Rotation = {0.0211, -0.0201, -0.2109} + }, + ['1969-7-20T20:17:21'] = { + Type = "StaticRotation", + Rotation = {0.0228, -0.0197, -0.2159} + }, + ['1969-7-20T20:17:22'] = { + Type = "StaticRotation", + Rotation = {-0.0201, -0.0257, -0.2230} + }, + ['1969-7-20T20:17:23'] = { + Type = "StaticRotation", + Rotation = {-0.0299, -0.0125, -0.2287} + }, + ['1969-7-20T20:17:24'] = { + Type = "StaticRotation", + Rotation = {-0.0368, -0.0025, -0.2355} + }, + ['1969-7-20T20:17:25'] = { + Type = "StaticRotation", + Rotation = {-0.0464, 0.0209, -0.2408} + }, + ['1969-7-20T20:17:26'] = { + Type = "StaticRotation", + Rotation = {-0.0548, 0.0474, -0.2472} + }, + ['1969-7-20T20:17:27'] = { + Type = "StaticRotation", + Rotation = {-0.0535, 0.0464, -0.2481} + }, + ['1969-7-20T20:17:28'] = { + Type = "StaticRotation", + Rotation = {-0.0512, 0.0508, -0.2491} + }, + ['1969-7-20T20:17:29'] = { + Type = "StaticRotation", + Rotation = {-0.0625, 0.0781, -0.2504} + }, + ['1969-7-20T20:17:30'] = { + Type = "StaticRotation", + Rotation = {-0.0811, 0.0711, -0.2531} + }, + ['1969-7-20T20:17:31'] = { + Type = "StaticRotation", + Rotation = {-0.0855, 0.0692, -0.2544} + }, + ['1969-7-20T20:17:32'] = { + Type = "StaticRotation", + Rotation = {-0.0940, 0.0673, -0.2569} + }, + ['1969-7-20T20:17:33'] = { + Type = "StaticRotation", + Rotation = {-0.0963, 0.0648, -0.2587} + }, + ['1969-7-20T20:17:34'] = { + Type = "StaticRotation", + Rotation = {-0.0909, 0.0619, -0.2587} + }, + ['1969-7-20T20:17:35'] = { + Type = "StaticRotation", + Rotation = {-0.0832, 0.0602, -0.2585} + }, + ['1969-7-20T20:17:36'] = { + Type = "StaticRotation", + Rotation = {-0.0761, 0.0326, -0.2602} + }, + ['1969-7-20T20:17:37'] = { + Type = "StaticRotation", + Rotation = {-0.0612, 0.0013, -0.2635} + }, + ['1969-7-20T20:17:38'] = { + Type = "StaticRotation", + Rotation = {-0.0274, -0.0079, -0.2727} + }, + ['1969-7-20T20:17:39'] = { + Type = "StaticRotation", + Rotation = {-0.0061, -0.0470, -0.2732} + }, + ['1969-7-20T20:17:40'] = { + Type = "StaticRotation", + Rotation = {-0.0794, -0.0088, -0.2447} + }, +}) diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo8launchtrail.asset b/data/assets/scene/solarsystem/missions/apollo/apollo8launchtrail.asset new file mode 100644 index 0000000000..701051ff6e --- /dev/null +++ b/data/assets/scene/solarsystem/missions/apollo/apollo8launchtrail.asset @@ -0,0 +1,74 @@ +local assetHelper = asset.require('util/asset_helper') +local sunTransforms = asset.require('scene/solarsystem/sun/transforms') +local kernelsFolder = asset.syncedResource({ + Name = "Apollo Kernels", + Type = "HttpSynchronization", + Identifier = "apollo_spice", + Version = 1 +}) + +local kernels = { + kernelsFolder .. "/moon_080317.tf", + kernelsFolder .. "/apollo8.tf", + kernelsFolder .. "/moon_pa_de421_1900-2050.bpc", + kernelsFolder .. '/apollo8.tsc', + kernelsFolder .. '/apollo8.bsp', + kernelsFolder .. '/apollo8_earthrise.bc', +} + +local apolloSpiceId = "-908" + + +local Apollo8LaunchTrail = { + Identifier = "Apollo8LaunchTrail", + Parent = "Earth", + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = { + Type = "SpiceTranslation", + Target = apolloSpiceId, + Observer = "EARTH", + Frame = "IAU_EARTH", + Kernels = kernels + }, + Color = { 0.70, 0.50, 0.20 }, + StartTime = "1968 DEC 21 12:51:00", + EndTime = "1968 DEC 21 23:23:22", + SampleInterval = 30 + }, + GUI = { + Name = "Apollo 8 Launch Trail", + Path = "/Solar System/Missions/Apollo" + } +} + +local Apollo8EarthBarycenterTrail = { + Identifier = "Apollo8EarthBarycenterTrail", + Parent = "EarthBarycenter", + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = { + Type = "SpiceTranslation", + Target = apolloSpiceId, + Observer = "EARTH BARYCENTER", + Frame = "GALACTIC", + Kernels = kernels + }, + Color = { 1, 0.0, 0.0 }, + StartTime = "1968 DEC 21", + EndTime = "1968 DEC 28", + SampleInterval = 30, + Enabled = false, + }, + GUI = { + Name = "Apollo 8 Earth Barycenter Trail", + Path = "/Solar System/Missions/Apollo" + } +} + +local exportList = { + Apollo8LaunchTrail, + Apollo8EarthBarycenterTrail, +} + +assetHelper.registerSceneGraphNodesAndExport(asset, exportList) diff --git a/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset b/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset index 5723c970bc..2d096b99d0 100644 --- a/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset +++ b/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset @@ -33,8 +33,8 @@ local Station2Boulder1Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.5294692, Latitude = 20.098824, - FixedAltitude = -2442.8, - UseFixedAltitude = true + Altitude = -2442.8, + UseHeightMap = false } }, GUI = { @@ -78,8 +78,8 @@ local Station2Boulder2Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.5287892, Latitude = 20.098240, - FixedAltitude = -2434.6, - UseFixedAltitude = true + Altitude = -2434.6, + UseHeightMap = false } }, GUI = { @@ -123,8 +123,8 @@ local Station2Boulder3Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.5294692, Latitude = 20.098610, - FixedAltitude = -2441.55, - UseFixedAltitude = true + Altitude = -2441.55, + UseHeightMap = false } }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset b/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset index dba9844a7c..919de3f9a8 100644 --- a/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset +++ b/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset @@ -37,6 +37,8 @@ local Station6Frag1Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.80068, Latitude = 20.2903, + Altitude = -2562.6, + UseHeightmap = false } }, GUI = { @@ -54,6 +56,8 @@ local Station6Frag1Model = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.8007, Latitude = 20.2903, + Altitude = -2562.6, + UseHeightmap = false } }, Transform = { @@ -104,8 +108,8 @@ local Station6Frag2Model = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.80055, Latitude = 20.289808, - FixedAltitude = -2566.5, - UseFixedAltitude = true + Altitude = -2566.5, + UseHeightmap = false } }, Renderable = { @@ -140,8 +144,8 @@ local Station6Frag3Model = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.80053, Latitude = 20.29030, - FixedAltitude = -2563.0, - UseFixedAltitude = true + Altitude = -2563.0, + UseHeightMap = false } }, Renderable = { diff --git a/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset b/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset index 555d4fcb82..d2eab52355 100644 --- a/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset +++ b/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset @@ -34,8 +34,8 @@ local Station7BoulderHolder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.8165882, Latitude = 20.2908556, - FixedAltitude = -2593.5, - UseFixedAltitude = true + Altitude = -2593.5, + UseHeightMap = true } }, GUI = { diff --git a/include/openspace/util/timeline.h b/include/openspace/util/timeline.h index b47d9cf4e3..81f2a9687b 100644 --- a/include/openspace/util/timeline.h +++ b/include/openspace/util/timeline.h @@ -44,7 +44,12 @@ struct KeyframeBase { */ template struct Keyframe : public KeyframeBase { - Keyframe(size_t i, double t, T p); + Keyframe(size_t i, double t, T d); + + Keyframe(Keyframe const&) = default; + Keyframe(Keyframe&&) = default; + Keyframe& operator=(Keyframe&&) = default; + Keyframe& operator=(Keyframe const&) = default; T data; }; @@ -56,7 +61,8 @@ class Timeline { public: virtual ~Timeline() = default; - void addKeyframe(double time, T data); + void addKeyframe(double time, const T& data); + void addKeyframe(double time, T&& data); void clearKeyframes(); void removeKeyframe(size_t id); void removeKeyframesBefore(double timestamp, bool inclusive = false); @@ -66,6 +72,7 @@ public: size_t nKeyframes() const; const Keyframe* firstKeyframeAfter(double timestamp, bool inclusive = false) const; const Keyframe* lastKeyframeBefore(double timestamp, bool inclusive = false) const; + const std::deque>& keyframes() const; private: diff --git a/include/openspace/util/timeline.inl b/include/openspace/util/timeline.inl index 79ccf4c51a..d2811a6aee 100644 --- a/include/openspace/util/timeline.inl +++ b/include/openspace/util/timeline.inl @@ -25,13 +25,25 @@ namespace openspace { template -Keyframe::Keyframe(size_t i, double t, T p) +Keyframe::Keyframe(size_t i, double t, T d) : KeyframeBase{ i, t } - , data(p) + , data(std::move(d)) {} template -void Timeline::addKeyframe(double timestamp, T data) { +void Timeline::addKeyframe(double timestamp, T&& data) { + Keyframe keyframe(++_nextKeyframeId, timestamp, std::move(data)); + const auto iter = std::upper_bound( + _keyframes.cbegin(), + _keyframes.cend(), + keyframe, + &compareKeyframeTimes + ); + _keyframes.insert(iter, std::move(keyframe)); +} + +template +void Timeline::addKeyframe(double timestamp, const T& data) { Keyframe keyframe(++_nextKeyframeId, timestamp, data); const auto iter = std::upper_bound( _keyframes.cbegin(), @@ -39,7 +51,7 @@ void Timeline::addKeyframe(double timestamp, T data) { keyframe, &compareKeyframeTimes ); - _keyframes.insert(iter, keyframe); + _keyframes.insert(iter, std::move(keyframe)); } template @@ -143,7 +155,7 @@ void Timeline::removeKeyframe(size_t id) { std::remove_if( _keyframes.begin(), _keyframes.end(), - [id] (Keyframe keyframe) { return keyframe.id == id; } + [id] (const Keyframe& keyframe) { return keyframe.id == id; } ), _keyframes.end() ); @@ -209,7 +221,7 @@ const Keyframe* Timeline::lastKeyframeBefore(double timestamp, bool inclus return &(*it); } -template +template const std::deque>& Timeline::keyframes() const { return _keyframes; } diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index de4b747968..2ce1e6846c 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -54,8 +54,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceframebuffer.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimagelocal.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimageonline.h - ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.h - ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/rotation/timelinerotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/constantrotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/fixedrotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/luarotation.h @@ -65,6 +64,10 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/scale/timedependentscale.h ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeinterval.h ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeunion.h + ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/translation/timelinetranslation.h + ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -98,8 +101,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceframebuffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimagelocal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimageonline.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rotation/timelinerotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/constantrotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/fixedrotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/luarotation.cpp @@ -109,6 +111,9 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/scale/timedependentscale.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeinterval.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeunion.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translation/timelinetranslation.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index ead6089797..ba70bd6c2e 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -55,9 +55,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -131,6 +133,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { auto fTranslation = FactoryManager::ref().factory(); ghoul_assert(fTranslation, "Ephemeris factory was not created"); + fTranslation->registerClass("TimelineTranslation"); fTranslation->registerClass("LuaTranslation"); fTranslation->registerClass("StaticTranslation"); @@ -141,6 +144,8 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { fRotation->registerClass("FixedRotation"); fRotation->registerClass("LuaRotation"); fRotation->registerClass("StaticRotation"); + fRotation->registerClass("TimelineRotation"); + auto fScale = FactoryManager::ref().factory(); ghoul_assert(fScale, "Scale factory was not created"); @@ -198,6 +203,7 @@ std::vector BaseModule::documentations() const { FixedRotation::Documentation(), LuaRotation::Documentation(), StaticRotation::Documentation(), + TimelineRotation::Documentation(), LuaScale::Documentation(), StaticScale::Documentation(), @@ -205,6 +211,7 @@ std::vector BaseModule::documentations() const { LuaTranslation::Documentation(), StaticTranslation::Documentation(), + TimelineTranslation::Documentation(), TimeFrameInterval::Documentation(), TimeFrameUnion::Documentation(), diff --git a/modules/base/rotation/timelinerotation.cpp b/modules/base/rotation/timelinerotation.cpp new file mode 100644 index 0000000000..5fbc741833 --- /dev/null +++ b/modules/base/rotation/timelinerotation.cpp @@ -0,0 +1,118 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace { + constexpr const char* KeyType = "Type"; + constexpr const char* KeyKeyframes = "Keyframes"; +} // namespace + +namespace openspace { + +documentation::Documentation TimelineRotation::Documentation() { + using namespace documentation; + return { + "Timeline Rotation", + "base_transform_rotation_keyframe", + { + { + KeyType, + new StringEqualVerifier("TimelineRotation"), + Optional::No + }, + { + KeyKeyframes, + new TableVerifier({ + { "*", new TableVerifier(), Optional::No, "Any translation object" } + }), + Optional::No, + "A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS" + "and values that are valid Rotation objects." + } + } + }; +} + +TimelineRotation::TimelineRotation(const ghoul::Dictionary& dictionary) { + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "TimelineTranslation" + ); + + const ghoul::Dictionary& keyframes = + dictionary.value(KeyKeyframes); + + std::vector timeStrings = keyframes.keys(); + for (const std::string& timeString : timeStrings) { + const double t = Time::convertTime(timeString); + + std::unique_ptr rotation = + Rotation::createFromDictionary( + keyframes.value(timeString) + ); + + if (rotation) { + _timeline.addKeyframe(t, std::move(rotation)); + } + } +} + +glm::dmat3 TimelineRotation::matrix(const UpdateData& data) const { + const double now = data.time.j2000Seconds(); + using KeyframePointer = const Keyframe>*; + + KeyframePointer prev = _timeline.lastKeyframeBefore(now, true); + KeyframePointer next = _timeline.firstKeyframeAfter(now, true); + + if (!prev && !next) { + return glm::dmat3(0.0); + } + if (!prev) { + prev = next; + } + if (!next) { + next = prev; + } + const double prevTime = prev->timestamp; + const double nextTime = next->timestamp; + + double t = 0.0; + if (nextTime - prevTime > 0.0) { + t = (now - prevTime) / (nextTime - prevTime); + } + + const glm::dquat nextRot = glm::quat_cast(next->data->matrix(data)); + const glm::dquat prevRot = glm::quat_cast(prev->data->matrix(data)); + + return glm::dmat3(glm::slerp(prevRot, nextRot, t)); +} + +} // namespace openspace diff --git a/modules/base/rotation/timelinerotation.h b/modules/base/rotation/timelinerotation.h new file mode 100644 index 0000000000..a969341a89 --- /dev/null +++ b/modules/base/rotation/timelinerotation.h @@ -0,0 +1,49 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_BASE___TIMELINEROTATION___H__ +#define __OPENSPACE_MODULE_BASE___TIMELINEROTATION___H__ + +#include +#include + +namespace openspace { + +struct UpdateData; + +namespace documentation { struct Documentation; } + +class TimelineRotation : public Rotation { +public: + TimelineRotation(const ghoul::Dictionary& dictionary); + glm::dmat3 matrix(const UpdateData& data) const override; + static documentation::Documentation Documentation(); + +private: + Timeline> _timeline; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___TIMELINEROTATION___H__ diff --git a/modules/base/translation/timelinetranslation.cpp b/modules/base/translation/timelinetranslation.cpp new file mode 100644 index 0000000000..9796255d65 --- /dev/null +++ b/modules/base/translation/timelinetranslation.cpp @@ -0,0 +1,114 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace { + constexpr const char* KeyType = "Type"; + constexpr const char* KeyKeyframes = "Keyframes"; +} // namespace + +namespace openspace { + +documentation::Documentation TimelineTranslation::Documentation() { + using namespace documentation; + return { + "Timeline Translation", + "base_transform_translation_keyframe", + { + { + KeyType, + new StringEqualVerifier("TimelineTranslation"), + Optional::No + }, + { + KeyKeyframes, + new TableVerifier({ + { "*", new TableVerifier(), Optional::No, "Any translation object" } + }), + Optional::No, + "A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS" + "and values that are valid Translation objects." + } + } + }; +} + +TimelineTranslation::TimelineTranslation(const ghoul::Dictionary& dictionary) { + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "TimelineTranslation" + ); + + const ghoul::Dictionary& keyframes = + dictionary.value(KeyKeyframes); + + std::vector timeStrings = keyframes.keys(); + for (const std::string& timeString : timeStrings) { + const double t = Time::convertTime(timeString); + + std::unique_ptr translation = + Translation::createFromDictionary( + keyframes.value(timeString) + ); + + if (translation) { + _timeline.addKeyframe(t, std::move(translation)); + } + } +} + +glm::dvec3 TimelineTranslation::position(const UpdateData& data) const { + const double now = data.time.j2000Seconds(); + using KeyframePointer = const Keyframe>*; + + KeyframePointer prev = _timeline.lastKeyframeBefore(now, true); + KeyframePointer next = _timeline.firstKeyframeAfter(now, true); + + if (!prev && !next) { + return glm::dvec3(0.0); + } + if (!prev) { + prev = next; + } + if (!next) { + next = prev; + } + const double prevTime = prev->timestamp; + const double nextTime = next->timestamp; + + double t = 0.0; + if (nextTime - prevTime > 0.0) { + t = (now - prevTime) / (nextTime - prevTime); + } + return t * next->data->position(data) + (1.0 - t) * prev->data->position(data); +} + +} // namespace openspace diff --git a/modules/base/translation/timelinetranslation.h b/modules/base/translation/timelinetranslation.h new file mode 100644 index 0000000000..0d528d36a6 --- /dev/null +++ b/modules/base/translation/timelinetranslation.h @@ -0,0 +1,50 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_BASE___TIMELINETRANSLATION___H__ +#define __OPENSPACE_MODULE_BASE___TIMELINETRANSLATION___H__ + +#include +#include + +namespace openspace { + +struct UpdateData; + +namespace documentation { struct Documentation; } + +class TimelineTranslation : public Translation { +public: + TimelineTranslation(const ghoul::Dictionary& dictionary); + + glm::dvec3 position(const UpdateData& data) const override; + static documentation::Documentation Documentation(); + +private: + Timeline> _timeline; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___TIMELINETRANSLATION___H__ diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp index 86ab30d9e0..3b6dcbf462 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -173,9 +173,16 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { bool isEast = lon > 0.0; lon = std::abs(lon); - const double altitude = glm::length( + double altitude = glm::length( cameraPositionModelSpace - posHandle.centerToReferenceSurface ); + + if (glm::length(cameraPositionModelSpace) < + glm::length(posHandle.centerToReferenceSurface)) + { + altitude = -altitude; + } + std::pair dist = simplifyDistance(altitude); penPosition.y -= _font->height(); diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index cae9cc2381..560994bed4 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -58,20 +58,21 @@ namespace { "globe. The default value is 0.0" }; - constexpr openspace::properties::Property::PropertyInfo FixedAltitudeInfo = { - "FixedAltitude", - "Fixed Altitude", - "The altitude in meters of the location on the globe's surface. This value is " - "used if the 'UseFixedAltitude' property is 'true'. The default value is 10000km." + constexpr openspace::properties::Property::PropertyInfo AltitudeInfo = { + "Altitude", + "Altitude", + "The altitude in meters. " + "If the 'UseHeightmap' property is 'true', this is an offset from the actual " + "surface of the globe. If not, this is an offset from the reference ellipsoid." + "The default value is 0.0" }; - constexpr openspace::properties::Property::PropertyInfo UseFixedAltitudeInfo = { - "UseFixedAltitude", - "Use Fixed Altitude", - "If this value is 'true', the altitude specified in 'FixedAltitude' is used for " - "this translation. If it is 'false', the altitude will be computed based on the " - "height information that is available about the globe to which this translation " - "is attached. The default value is 'true'." + constexpr openspace::properties::Property::PropertyInfo UseHeightmapInfo = { + "UseHeightmap", + "Use Heightmap", + "If this value is 'true', the altitude specified in 'Altitude' will be treated " + "as an offset from the heightmap. Otherwise, it will be an offset from the " + "globe's reference ellipsoid. The default value is 'false'." }; } // namespace @@ -81,8 +82,8 @@ documentation::Documentation GlobeTranslation::Documentation() { using namespace openspace::documentation; return { - "Spice Translation", - "space_translation_spicetranslation", + "Globe Translation", + "space_translation_globetranslation", { { "Type", @@ -110,16 +111,16 @@ documentation::Documentation GlobeTranslation::Documentation() { LatitudeInfo.description, }, { - FixedAltitudeInfo.identifier, + AltitudeInfo.identifier, new DoubleVerifier, Optional::Yes, - FixedAltitudeInfo.description + AltitudeInfo.description }, { - UseFixedAltitudeInfo.identifier, + UseHeightmapInfo.identifier, new BoolVerifier, Optional::Yes, - UseFixedAltitudeInfo.description + UseHeightmapInfo.description } } }; @@ -129,8 +130,8 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) : _globe(GlobeInfo) , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) , _latitude(LatitudeInfo, 0.0, -90.0, 90.0) - , _fixedAltitude(FixedAltitudeInfo, 1e8, 0.0, 1e12) - , _useFixedAltitude(UseFixedAltitudeInfo, false) + , _altitude(AltitudeInfo, 0.0, 0.0, 1e12) + , _useHeightmap(UseHeightmapInfo, false) { documentation::testSpecificationAndThrow( Documentation(), @@ -145,11 +146,11 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) if (dictionary.hasKey(LatitudeInfo.identifier)) { _latitude = dictionary.value(LatitudeInfo.identifier); } - if (dictionary.hasKey(FixedAltitudeInfo.identifier)) { - _fixedAltitude = dictionary.value(FixedAltitudeInfo.identifier); + if (dictionary.hasKey(AltitudeInfo.identifier)) { + _altitude = dictionary.value(AltitudeInfo.identifier); } - if (dictionary.hasKey(UseFixedAltitudeInfo.identifier)) { - _useFixedAltitude = dictionary.value(UseFixedAltitudeInfo.identifier); + if (dictionary.hasKey(UseHeightmapInfo.identifier)) { + _useHeightmap = dictionary.value(UseHeightmapInfo.identifier); } _globe.onChange([this]() { @@ -159,13 +160,13 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) _longitude.onChange([this]() { _positionIsDirty = true; }); _latitude.onChange([this]() { _positionIsDirty = true; }); - _fixedAltitude.onChange([this]() { _positionIsDirty = true; }); - _useFixedAltitude.onChange([this]() { _positionIsDirty = true; }); + _altitude.onChange([this]() { _positionIsDirty = true; }); + _useHeightmap.onChange([this]() { _positionIsDirty = true; }); addProperty(_longitude); addProperty(_latitude); - addProperty(_fixedAltitude); - addProperty(_useFixedAltitude); + addProperty(_altitude); + addProperty(_useHeightmap); } void GlobeTranslation::fillAttachedNode() { @@ -195,8 +196,8 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { _positionIsDirty = true; } - if (!_useFixedAltitude) { - // If we don't use the fixed altitude, we have to compute the height every frame + if (_useHeightmap) { + // If we use the heightmap, we have to compute the height every frame _positionIsDirty = true; } @@ -204,33 +205,35 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { return _position; } - GlobeBrowsingModule& mod = *(global::moduleEngine.module()); - glm::vec3 pos = mod.cartesianCoordinatesFromGeo( - *_attachedNode, - _latitude, - _longitude, - _fixedAltitude - ); - - if (_useFixedAltitude) { - _position = glm::dvec3(pos); - _positionIsDirty = true; - - return _position; - } - else { - SurfacePositionHandle h = _attachedNode->calculateSurfacePositionHandle(pos); - - pos = mod.cartesianCoordinatesFromGeo( + if (_useHeightmap) { + glm::vec3 groundPos = mod.cartesianCoordinatesFromGeo( *_attachedNode, _latitude, _longitude, - h.heightToSurface + 0.0 ); - _position = glm::dvec3(pos); + SurfacePositionHandle h = + _attachedNode->calculateSurfacePositionHandle(groundPos); + + _position = mod.cartesianCoordinatesFromGeo( + *_attachedNode, + _latitude, + _longitude, + h.heightToSurface + _altitude + ); + return _position; + } + else { + _position = mod.cartesianCoordinatesFromGeo( + *_attachedNode, + _latitude, + _longitude, + _altitude + ); + _positionIsDirty = false; return _position; } } diff --git a/modules/globebrowsing/src/globetranslation.h b/modules/globebrowsing/src/globetranslation.h index 7fbd943b7b..91c0bdf61b 100644 --- a/modules/globebrowsing/src/globetranslation.h +++ b/modules/globebrowsing/src/globetranslation.h @@ -49,8 +49,8 @@ private: properties::StringProperty _globe; properties::DoubleProperty _longitude; properties::DoubleProperty _latitude; - properties::DoubleProperty _fixedAltitude; - properties::BoolProperty _useFixedAltitude; + properties::DoubleProperty _altitude; + properties::BoolProperty _useHeightmap; RenderableGlobe* _attachedNode = nullptr; diff --git a/modules/space/translation/horizonstranslation.cpp b/modules/space/translation/horizonstranslation.cpp index e50d284047..80dca66afe 100644 --- a/modules/space/translation/horizonstranslation.cpp +++ b/modules/space/translation/horizonstranslation.cpp @@ -179,7 +179,7 @@ void HorizonsTranslation::readHorizonsTextFile(const std::string& horizonsTextFi ); // Add position to stored timeline. - _timeline.addKeyframe(timeInJ2000, gPos); + _timeline.addKeyframe(timeInJ2000, std::move(gPos)); std::getline(fileStream, line); } From 277aee5c0c5a606f0bb6f6e5b2d72e3327f04633 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 17 Jul 2019 15:39:43 +0200 Subject: [PATCH 11/32] Make constructor of Time explicit Module breaking change --- include/openspace/util/time.h | 2 +- .../base/rendering/renderabletrailorbit.cpp | 14 +++++------ .../rendering/renderabletrailtrajectory.cpp | 4 ++-- .../renderablefieldlinessequence.cpp | 2 +- .../rendering/renderabletimevaryingvolume.cpp | 2 +- src/interaction/sessionrecording.cpp | 2 +- src/network/parallelpeer.cpp | 2 +- src/util/time_lua.inl | 8 +++---- src/util/timemanager.cpp | 23 ++++++++++--------- 9 files changed, 30 insertions(+), 29 deletions(-) diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index aa8cf2e4c0..d784ac2426 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -65,7 +65,7 @@ public: */ static double convertTime(const std::string& time); - Time(double secondsJ2000 = -1); + explicit Time(double secondsJ2000 = -1); Time(const Time& other) = default; /** diff --git a/modules/base/rendering/renderabletrailorbit.cpp b/modules/base/rendering/renderabletrailorbit.cpp index e00156ec72..f8a306a6d2 100644 --- a/modules/base/rendering/renderabletrailorbit.cpp +++ b/modules/base/rendering/renderabletrailorbit.cpp @@ -233,8 +233,8 @@ void RenderableTrailOrbit::update(const UpdateData& data) { // Write the current location into the floating position const glm::vec3 p = _translation->position({ {}, - data.time.j2000Seconds(), - 0.0, + data.time, + Time(0.0), false }); _vertexArray[_primaryRenderInformation.first] = { p.x, p.y, p.z }; @@ -412,8 +412,8 @@ RenderableTrailOrbit::UpdateReport RenderableTrailOrbit::updateTrails( // location const glm::vec3 p = _translation->position({ {}, - _lastPointTime, - 0.0, + Time(_lastPointTime), + Time(0.0), false }); _vertexArray[_primaryRenderInformation.first] = { p.x, p.y, p.z }; @@ -452,8 +452,8 @@ RenderableTrailOrbit::UpdateReport RenderableTrailOrbit::updateTrails( // location const glm::vec3 p = _translation->position({ {}, - _firstPointTime, - 0.0, + Time(_firstPointTime), + Time(0.0), false }); _vertexArray[_primaryRenderInformation.first] = { p.x, p.y, p.z }; @@ -496,7 +496,7 @@ void RenderableTrailOrbit::fullSweep(double time) { const double secondsPerPoint = _period / (_resolution - 1); // starting at 1 because the first position is a floating current one for (int i = 1; i < _resolution; ++i) { - const glm::vec3 p = _translation->position({ {}, time, 0.0, false }); + const glm::vec3 p = _translation->position({ {}, Time(time), Time(0.0), false }); _vertexArray[i] = { p.x, p.y, p.z }; time -= secondsPerPoint; diff --git a/modules/base/rendering/renderabletrailtrajectory.cpp b/modules/base/rendering/renderabletrailtrajectory.cpp index 54f51f1c27..ee019b8827 100644 --- a/modules/base/rendering/renderabletrailtrajectory.cpp +++ b/modules/base/rendering/renderabletrailtrajectory.cpp @@ -226,8 +226,8 @@ void RenderableTrailTrajectory::update(const UpdateData& data) { for (int i = 0; i < nValues; ++i) { const glm::vec3 p = _translation->position({ {}, - _start + i * totalSampleInterval, - 0.0, + Time(_start + i * totalSampleInterval), + Time(0.0), false }); _vertexArray[i] = { p.x, p.y, p.z }; diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp index 1afc04feab..0e108d525f 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp @@ -771,7 +771,7 @@ void RenderableFieldlinesSequence::definePropertyCallbackFunctions() { }); _pJumpToStartBtn.onChange([this] { - global::timeManager.setTimeNextFrame(_startTimes[0]); + global::timeManager.setTimeNextFrame(Time(_startTimes[0])); }); } diff --git a/modules/volume/rendering/renderabletimevaryingvolume.cpp b/modules/volume/rendering/renderabletimevaryingvolume.cpp index ffe7bd5034..d6a0ae9963 100644 --- a/modules/volume/rendering/renderabletimevaryingvolume.cpp +++ b/modules/volume/rendering/renderabletimevaryingvolume.cpp @@ -426,7 +426,7 @@ RenderableTimeVaryingVolume::Timestep* RenderableTimeVaryingVolume::timestepFrom void RenderableTimeVaryingVolume::jumpToTimestep(int target) { Timestep* t = timestepFromIndex(target); if (t) { - global::timeManager.setTimeNextFrame(t->metadata.time); + global::timeManager.setTimeNextFrame(Time(t->metadata.time)); } } diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 89b3707e89..b46206e6d7 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -848,7 +848,7 @@ void SessionRecording::playbackCamera() { pbFrame.followFocusNodeRotation = (rotationFollowing == "F"); } if (_setSimulationTimeWithNextCameraKeyframe) { - global::timeManager.setTimeNextFrame(timeSim); + global::timeManager.setTimeNextFrame(Time(timeSim)); _setSimulationTimeWithNextCameraKeyframe = false; _saveRenderingCurrentRecordedTime = timeRec; } diff --git a/src/network/parallelpeer.cpp b/src/network/parallelpeer.cpp index cef58ee498..684680b279 100644 --- a/src/network/parallelpeer.cpp +++ b/src/network/parallelpeer.cpp @@ -325,7 +325,7 @@ void ParallelPeer::dataMessageReceived(const std::vector& message) TimeKeyframeData timeKeyframeData; timeKeyframeData.delta = kfMessage._dt; timeKeyframeData.pause = kfMessage._paused; - timeKeyframeData.time = kfMessage._time; + timeKeyframeData.time = Time(kfMessage._time); timeKeyframeData.jump = kfMessage._requiresTimeJump; const double kfTimestamp = convertTimestamp(kfMessage._timestamp); diff --git a/src/util/time_lua.inl b/src/util/time_lua.inl index 9a197065e8..ac0115367e 100644 --- a/src/util/time_lua.inl +++ b/src/util/time_lua.inl @@ -333,12 +333,12 @@ int time_setTime(lua_State* L) { if (nArguments == 1) { if (isNumber) { double value = lua_tonumber(L, 1); - global::timeManager.setTimeNextFrame(value); + global::timeManager.setTimeNextFrame(Time(value)); return 0; } if (isString) { const char* time = lua_tostring(L, 1); - global::timeManager.setTimeNextFrame(Time::convertTime(time)); + global::timeManager.setTimeNextFrame(Time(Time::convertTime(time))); return 0; } ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); @@ -424,7 +424,7 @@ int time_interpolateTime(lua_State* L) { global::timeManager.interpolateTime(targetTime, duration); } else { - global::timeManager.setTimeNextFrame(targetTime); + global::timeManager.setTimeNextFrame(Time(targetTime)); } } return 0; @@ -486,7 +486,7 @@ int time_interpolateTimeRelative(lua_State* L) { } else { global::timeManager.setTimeNextFrame( - global::timeManager.time().j2000Seconds() + delta + Time(global::timeManager.time().j2000Seconds() + delta) ); } } diff --git a/src/util/timemanager.cpp b/src/util/timemanager.cpp index 4127db2012..d8e920d2a7 100644 --- a/src/util/timemanager.cpp +++ b/src/util/timemanager.cpp @@ -109,7 +109,7 @@ void TimeManager::interpolateTime(double targetTime, double durationSeconds) { const bool pause = isPaused(); const TimeKeyframeData current = { time(), deltaTime(), false, false }; - const TimeKeyframeData next = { targetTime, targetDeltaTime(), pause, false }; + const TimeKeyframeData next = { Time(targetTime), targetDeltaTime(), pause, false }; clearKeyframes(); addKeyframe(now, current); @@ -193,12 +193,12 @@ TimeKeyframeData TimeManager::interpolate(double applicationTime) { } else if (hasPastKeyframes) { // Extrapolate based on last past keyframe const double deltaApplicationTime = applicationTime - lastPastKeyframe->timestamp; - Time predictedTime = { + Time predictedTime( lastPastKeyframe->data.time.j2000Seconds() + deltaApplicationTime * (lastPastKeyframe->data.pause ? 0.0 : lastPastKeyframe->data.delta) - }; - return TimeKeyframeData{ + ); + return TimeKeyframeData { predictedTime, lastPastKeyframe->data.delta, false, @@ -206,7 +206,7 @@ TimeKeyframeData TimeManager::interpolate(double applicationTime) { }; } // As the last option, fall back on the current time. - return TimeKeyframeData{ _currentTime, _targetDeltaTime, _timePaused, false }; + return TimeKeyframeData { _currentTime, _targetDeltaTime, _timePaused, false }; } void TimeManager::progressTime(double dt) { @@ -316,7 +316,7 @@ TimeKeyframeData TimeManager::interpolate(const Keyframe& past deltaAppTime; TimeKeyframeData data { - interpolatedTime, + Time(interpolatedTime), interpolatedDeltaTime, past.data.pause, past.data.jump @@ -532,9 +532,9 @@ void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolation } const double now = global::windowDelegate.applicationTime(); - - Time newTime = time().j2000Seconds() + - (_deltaTime + newDeltaTime) * 0.5 * interpolationDuration; + Time newTime( + time().j2000Seconds() + (_deltaTime + newDeltaTime) * 0.5 * interpolationDuration + ); TimeKeyframeData currentKeyframe = { time(), _deltaTime, false, false }; TimeKeyframeData futureKeyframe = { newTime, newDeltaTime, false, false }; @@ -556,8 +556,9 @@ void TimeManager::interpolatePause(bool pause, double interpolationDuration) { const double now = global::windowDelegate.applicationTime(); double targetDelta = pause ? 0.0 : _targetDeltaTime; - Time newTime = time().j2000Seconds() + - (_deltaTime + targetDelta) * 0.5 * interpolationDuration; + Time newTime( + time().j2000Seconds() + (_deltaTime + targetDelta) * 0.5 * interpolationDuration + ); TimeKeyframeData currentKeyframe = { time(), _deltaTime, false, false }; TimeKeyframeData futureKeyframe = { newTime, _targetDeltaTime, pause, false }; From 66cd0413dd81df0d6df8b885740933eb0f04c83f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jul 2019 11:52:09 +0200 Subject: [PATCH 12/32] Cleanup of Wormhole application Updated Ghoul to fix commandline argument extraction bug --- apps/Wormhole/main.cpp | 57 ++++++++++++++++-------------------------- ext/ghoul | 2 +- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/apps/Wormhole/main.cpp b/apps/Wormhole/main.cpp index 029ee407cb..a988789255 100644 --- a/apps/Wormhole/main.cpp +++ b/apps/Wormhole/main.cpp @@ -22,43 +22,26 @@ * 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 namespace { - const std::string _loggerCat = "Wormhole"; -} + constexpr const char*_loggerCat = "Wormhole"; +} // namespace int main(int argc, char** argv) { using namespace openspace; + using namespace ghoul::cmdparser; std::vector arguments(argv, argv + argc); - ghoul::cmdparser::CommandlineParser commandlineParser( + CommandlineParser commandlineParser( "Wormhole", - ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes + CommandlineParser::AllowUnknownCommands::Yes ); std::stringstream defaultPassword; @@ -73,43 +56,43 @@ int main(int argc, char** argv) { std::chrono::system_clock::now().time_since_epoch().count() + 1 ) % 0xffffff); - std::string portString = ""; + std::string portString; commandlineParser.addCommand( std::make_unique>( portString, "--port", "-p", "Sets the port to listen on" - ) + ) ); - std::string password = ""; + std::string password; commandlineParser.addCommand( std::make_unique>( password, "--password", "-l", "Sets the password to use" - ) + ) ); - std::string changeHostPassword = ""; + std::string changeHostPassword; commandlineParser.addCommand( std::make_unique>( changeHostPassword, "--hostpassword", "-h", "Sets the host password to use" - ) + ) ); commandlineParser.setCommandLine(arguments); commandlineParser.execute(); - if (password == "") { + if (password.empty()) { password = defaultPassword.str(); } - if (changeHostPassword == "") { + if (changeHostPassword.empty()) { changeHostPassword = defaultChangeHostPassword.str(); } @@ -118,11 +101,11 @@ int main(int argc, char** argv) { int port = 25001; - if (portString != "") { + if (!portString.empty()) { try { port = std::stoi(portString); } - catch (...) { + catch (const std::invalid_argument&) { LERROR(fmt::format("Invalid port: {}", portString)); } } @@ -132,7 +115,9 @@ int main(int argc, char** argv) { server.setDefaultHostAddress("127.0.0.1"); LINFO(fmt::format("Server listening to port {}", port)); - while (std::cin.get() != 'q') {} + while (std::cin.get() != 'q') { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } server.stop(); LINFO("Server stopped"); diff --git a/ext/ghoul b/ext/ghoul index cf5b311dda..f30b8c1a04 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit cf5b311ddac167c8542914afc54a9f878c7a79ce +Subproject commit f30b8c1a04bd7dcbbe4e4b6bdc48e96a28d6c18c From 2fca9a2a2c0717617884944c51201fba70b8406c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jul 2019 12:10:49 +0200 Subject: [PATCH 13/32] Remove torrent-based synchronization --- .gitmodules | 3 - modules/sync/CMakeLists.txt | 46 --- modules/sync/ext/libtorrent | 1 - modules/sync/syncmodule.cpp | 30 +- modules/sync/syncmodule.h | 12 - modules/sync/syncs/torrentsynchronization.cpp | 197 ------------- modules/sync/syncs/torrentsynchronization.h | 77 ----- modules/sync/torrentclient.cpp | 271 ------------------ modules/sync/torrentclient.h | 125 -------- 9 files changed, 1 insertion(+), 761 deletions(-) delete mode 160000 modules/sync/ext/libtorrent delete mode 100644 modules/sync/syncs/torrentsynchronization.cpp delete mode 100644 modules/sync/syncs/torrentsynchronization.h delete mode 100644 modules/sync/torrentclient.cpp delete mode 100644 modules/sync/torrentclient.h diff --git a/.gitmodules b/.gitmodules index 1bdc897bbd..3e4cfb738b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "modules/touch/ext/libTUIO11"] path = modules/touch/ext/libTUIO11 url = https://github.com/mkalten/TUIO11_CPP -[submodule "modules/sync/ext/libtorrent"] - path = modules/sync/ext/libtorrent - url = https://github.com/OpenSpace/libtorrent.git [submodule "apps/OpenSpace-MinVR/ext/minvr"] path = apps/OpenSpace-MinVR/ext/minvr url = https://github.com/OpenSpace/minvr diff --git a/modules/sync/CMakeLists.txt b/modules/sync/CMakeLists.txt index 28fde9802a..a263e5498f 100644 --- a/modules/sync/CMakeLists.txt +++ b/modules/sync/CMakeLists.txt @@ -24,8 +24,6 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) -option(OPENSPACE_MODULE_SYNC_USE_LIBTORRENT "Use libtorrent" OFF) - set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/syncmodule.h ${CMAKE_CURRENT_SOURCE_DIR}/syncs/httpsynchronization.h @@ -42,48 +40,4 @@ set(SOURCE_FILES ) source_group("Source Files" FILES ${SOURCE_FILES}) -if (OPENSPACE_MODULE_SYNC_USE_LIBTORRENT) - set(HEADER_FILES - ${HEADER_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.h - ${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.h - ) - set(SOURCE_FILES - ${SOURCE_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.cpp - ) -endif () - - create_new_module("Sync" sync_module ${HEADER_FILES} ${SOURCE_FILES}) - -##### -# Libtorrent -##### - -if (OPENSPACE_MODULE_SYNC_USE_LIBTORRENT) - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(LIBTORRENT_encryption OFF CACHE BOOL "Use OpenSSL Encryption" FORCE) - set(LIBTORRENT_shared OFF CACHE BOOL "Use Libtorrent as shared library" FORCE) - - include_external_library( - ${sync_module} - torrent-rasterbar - ${CMAKE_CURRENT_SOURCE_DIR}/ext/libtorrent - ) - target_include_directories( - ${sync_module} - SYSTEM PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/ext/libtorrent/include - ) - - target_compile_definitions(openspace-module-sync PUBLIC SYNC_USE_LIBTORRENT) - - mark_as_advanced(LIBTORRENT_build_examples LIBTORRENT_build_tests - LIBTORRENT_deprecated-functions LIBTORRENT_dht LIBTORRENT_encryption - LIBTORRENT_exceptions LIBTORRENT_exceptions LIBTORRENT_libiconv - LIBTORRENT_logging LIBTORRENT_shared LIBTORRENT_static_runtime - ) -endif () # OPENSPACE_MODULE_SYNC_USE_LIBTORRENT \ No newline at end of file diff --git a/modules/sync/ext/libtorrent b/modules/sync/ext/libtorrent deleted file mode 160000 index 22477e7430..0000000000 --- a/modules/sync/ext/libtorrent +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 22477e7430a643fc64e55a669e2ad0e87a67647e diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index 791254a3cd..6f920b85d4 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -87,19 +86,6 @@ void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) { } ); -#ifdef SYNC_USE_LIBTORRENT - fSynchronization->registerClass( - "TorrentSynchronization", - [this](bool, const ghoul::Dictionary& dictionary) { - return new TorrentSynchronization( - dictionary, - _synchronizationRoot, - _torrentClient - ); - } - ); -#endif // SYNC_USE_LIBTORRENT - fSynchronization->registerClass( "UrlSynchronization", [this](bool, const ghoul::Dictionary& dictionary) { @@ -113,17 +99,6 @@ void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) { auto fTask = FactoryManager::ref().factory(); ghoul_assert(fTask, "No task factory existed"); fTask->registerClass("SyncAssetTask"); - -#ifdef SYNC_USE_LIBTORRENT - _torrentClient.initialize(); - global::callback::deinitialize.emplace_back([&]() { _torrentClient.deinitialize(); }); -#endif // SYNC_USE_LIBTORRENT -} - -void SyncModule::internalDeinitialize() { -#ifdef SYNC_USE_LIBTORRENT - _torrentClient.deinitialize(); -#endif // SYNC_USE_LIBTORRENT } std::string SyncModule::synchronizationRoot() const { @@ -140,10 +115,7 @@ std::vector SyncModule::httpSynchronizationRepositories() const { std::vector SyncModule::documentations() const { return { - HttpSynchronization::Documentation(), -#ifdef SYNC_USE_LIBTORRENT - TorrentSynchronization::Documentation() -#endif // SYNC_USE_LIBTORRENT + HttpSynchronization::Documentation() }; } diff --git a/modules/sync/syncmodule.h b/modules/sync/syncmodule.h index eef18e8b72..64cb7e412d 100644 --- a/modules/sync/syncmodule.h +++ b/modules/sync/syncmodule.h @@ -27,10 +27,6 @@ #include -#ifdef SYNC_USE_LIBTORRENT -#include -#endif // SYNC_USE_LIBTORRENT - namespace openspace { class SyncModule : public OpenSpaceModule { @@ -44,20 +40,12 @@ public: void addHttpSynchronizationRepository(std::string repository); std::vector httpSynchronizationRepositories() const; -#ifdef SYNC_USE_LIBTORRENT - TorrentClient& torrentClient(); -#endif // SYNC_USE_LIBTORRENT - std::vector documentations() const override; protected: void internalInitialize(const ghoul::Dictionary& configuration) override; - void internalDeinitialize() override; private: -#ifdef SYNC_USE_LIBTORRENT - TorrentClient _torrentClient; -#endif // SYNC_USE_LIBTORRENT std::vector _synchronizationRepositories; std::string _synchronizationRoot; }; diff --git a/modules/sync/syncs/torrentsynchronization.cpp b/modules/sync/syncs/torrentsynchronization.cpp deleted file mode 100644 index 2f3bfd1485..0000000000 --- a/modules/sync/syncs/torrentsynchronization.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const char* KeyIdentifier = "Identifier"; - constexpr const char* KeyMagnet = "Magnet"; -} // namespace - -namespace openspace { - -documentation::Documentation TorrentSynchronization::Documentation() { - using namespace openspace::documentation; - return { - "TorrentSynchronization", - "torrent_synchronization", - { - { - KeyIdentifier, - new StringVerifier, - Optional::No, - "A unique identifier for this torrent" - }, - { - KeyMagnet, - new StringVerifier, - Optional::No, - "A magnet link identifying the torrent" - } - } - }; -} - -TorrentSynchronization::TorrentSynchronization(const ghoul::Dictionary& dict, - std::string synchronizationRoot, - TorrentClient& torrentClient) - : ResourceSynchronization(dict) - , _synchronizationRoot(std::move(synchronizationRoot)) - , _torrentClient(torrentClient) -{ - documentation::testSpecificationAndThrow( - Documentation(), - dict, - "TorrentSynchronization" - ); - - _identifier = dict.value(KeyIdentifier); - _magnetLink = dict.value(KeyMagnet); -} - -TorrentSynchronization::~TorrentSynchronization() { - cancel(); -} - -std::string TorrentSynchronization::uniformResourceName() const { - const size_t begin = _magnetLink.find("=urn") + 1; - const size_t end = _magnetLink.find('&', begin); - std::string xs = _magnetLink.substr( - begin, - (end == std::string::npos) ? end : (end - begin) - ); - - std::transform( - xs.begin(), - xs.end(), - xs.begin(), - [](char x) { return (x == ':') ? '.' : x; } - ); - return xs; -} - -std::string TorrentSynchronization::directory() { - ghoul::filesystem::Directory d( - _synchronizationRoot + - ghoul::filesystem::FileSystem::PathSeparator + - "torrent" + - ghoul::filesystem::FileSystem::PathSeparator + - _identifier + - ghoul::filesystem::FileSystem::PathSeparator + - uniformResourceName() - ); - - return FileSys.absPath(d); -} - -void TorrentSynchronization::start() { - if (_enabled) { - return; - } - begin(); - - if (hasSyncFile()) { - resolve(); - } - - _enabled = true; - try { - _torrentId = _torrentClient.addMagnetLink( - _magnetLink, - directory(), - [this](TorrentClient::TorrentProgress p) { - updateTorrentProgress(p); - } - ); - } catch (const TorrentError& e) { - LERRORC(name(), e.message); - if (!isResolved()) { - reject(); - } - } -} - -void TorrentSynchronization::cancel() { - if (_enabled) { - _torrentClient.removeTorrent(_torrentId); - _enabled = false; - reset(); - } -} - -void TorrentSynchronization::clear() { - cancel(); - // TODO: Remove all files from directory. -} - -bool TorrentSynchronization::hasSyncFile() { - const std::string& path = directory() + ".ossync"; - return FileSys.fileExists(path); -} - -void TorrentSynchronization::createSyncFile() { - const std::string& directoryName = directory(); - const std::string& filepath = directoryName + ".ossync"; - - FileSys.createDirectory(directoryName, ghoul::filesystem::FileSystem::Recursive::Yes); - - std::ofstream syncFile(filepath, std::ofstream::out); - syncFile << "Synchronized"; - syncFile.close(); -} - -size_t TorrentSynchronization::nSynchronizedBytes() { - std::lock_guard g(_progressMutex); - return _progress.nDownloadedBytes; -} - -size_t TorrentSynchronization::nTotalBytes() { - std::lock_guard g(_progressMutex); - return _progress.nTotalBytes; -} - -bool TorrentSynchronization::nTotalBytesIsKnown() { - std::lock_guard g(_progressMutex); - return _progress.nTotalBytesKnown; -} - -void TorrentSynchronization::updateTorrentProgress( - TorrentClient::TorrentProgress progress) -{ - std::lock_guard g(_progressMutex); - _progress = progress; - if (progress.finished && (state() == State::Syncing)) { - createSyncFile(); - resolve(); - } -} - -} // namespace openspace diff --git a/modules/sync/syncs/torrentsynchronization.h b/modules/sync/syncs/torrentsynchronization.h deleted file mode 100644 index 98f9811f4e..0000000000 --- a/modules/sync/syncs/torrentsynchronization.h +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__ -#define __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__ - -#ifdef SYNC_USE_LIBTORRENT - -#include - -#include - -namespace openspace { - -class TorrentSynchronizationJob; - -class TorrentSynchronization : public ResourceSynchronization { -public: - TorrentSynchronization(const ghoul::Dictionary& dict, std::string synchronizationRoot, - TorrentClient& client); - - virtual ~TorrentSynchronization(); - - std::string directory() override; - void start() override; - void cancel() override; - void clear() override; - - size_t nSynchronizedBytes() override; - size_t nTotalBytes() override; - bool nTotalBytesIsKnown() override; - - static documentation::Documentation Documentation(); - -private: - void updateTorrentProgress(TorrentClient::TorrentProgress p); - std::string uniformResourceName() const; - bool hasSyncFile(); - void createSyncFile(); - - std::atomic_bool _enabled = false; - - TorrentClient::TorrentId _torrentId = 0; - TorrentClient::TorrentProgress _progress; - std::mutex _progressMutex; - std::string _identifier; - std::string _magnetLink; - std::string _synchronizationRoot; - TorrentClient& _torrentClient; -}; - -} // namespace openspace - -#endif // SYNC_USE_LIBTORRENT - -#endif // __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__ diff --git a/modules/sync/torrentclient.cpp b/modules/sync/torrentclient.cpp deleted file mode 100644 index e2379f9c67..0000000000 --- a/modules/sync/torrentclient.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include - -#ifdef SYNC_USE_LIBTORRENT -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable : 4265) -#pragma warning (disable : 4996) -#endif // _MSC_VER - -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - - -namespace { - constexpr const char* _loggerCat = "TorrentClient"; - constexpr const std::chrono::milliseconds PollInterval(1000); -} // namespace - -#endif // SYNC_USE_LIBTORRENT - -namespace openspace { - -TorrentError::TorrentError(std::string msg) - : RuntimeError(std::move(msg), "TorrentClient") -{} - -void TorrentClient::initialize() { -#ifdef SYNC_USE_LIBTORRENT - libtorrent::settings_pack settings; - settings.set_str( - libtorrent::settings_pack::user_agent, - "OpenSpace/" + std::string(OPENSPACE_VERSION_NUMBER) - ); - - settings.set_str( - libtorrent::settings_pack::listen_interfaces, - "0.0.0.0:6881,0.0.0.0:20280,0.0.0.0:20285,0.0.0.0:20290" - ); - settings.set_bool(libtorrent::settings_pack::allow_multiple_connections_per_ip, true); - settings.set_bool(libtorrent::settings_pack::enable_upnp, true); - //settings.set_bool(libtorrent::settings_pack::ignore_limits_on_local_network, true); - settings.set_int(libtorrent::settings_pack::connection_speed, 20); - settings.set_int(libtorrent::settings_pack::active_downloads, -1); - settings.set_int(libtorrent::settings_pack::active_seeds, -1); - settings.set_int(libtorrent::settings_pack::active_limit, 30); - - settings.set_str( - libtorrent::settings_pack::dht_bootstrap_nodes, - "router.utorrent.com,dht.transmissionbt.com,router.bittorrent.com,\ -router.bitcomet.com" - ); - settings.set_int(libtorrent::settings_pack::dht_announce_interval, 15); - - _session.apply_settings(settings); - - libtorrent::error_code ec; - - _isInitialized = true; - _isActive = true; - - _torrentThread = std::thread([this]() { - while (_isActive) { - pollAlerts(); - std::unique_lock lock(_abortMutex); - _abortNotifier.wait_for(lock, PollInterval); - } - }); -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::deinitialize() { -#ifdef SYNC_USE_LIBTORRENT - if (!_isActive) { - return; - } - - _isActive = false; - _abortNotifier.notify_all(); - if (_torrentThread.joinable()) { - _torrentThread.join(); - } - - const std::vector& handles = _session.get_torrents(); - for (const lt::torrent_handle& h : handles) { - _session.remove_torrent(h); - } - _torrents.clear(); - - _session.abort(); - _isInitialized = false; -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::pollAlerts() { -#ifdef SYNC_USE_LIBTORRENT - // Libtorrent does not seem to reliably generate alerts for all added torrents. - // To make sure that the program does not keep waiting for already finished - // downsloads, we go through the whole list of torrents when polling. - // However, in theory, the commented code below should be more efficient: - /* - std::vector alerts; - { - std::lock_guard guard(_mutex); - _session->pop_alerts(&alerts); - } - for (lt::alert* a : alerts) { - if (const lt::torrent_alert* alert = - dynamic_cast(a)) - { - notify(alert->handle.id()); - } - } - */ - std::vector handles; - { - std::lock_guard guard(_mutex); - handles = _session.get_torrents(); - } - for (const lt::torrent_handle& h : handles) { - notify(h.id()); - } -#endif // SYNC_USE_LIBTORRENT -} - -TorrentClient::TorrentId TorrentClient::addTorrentFile( - [[ maybe_unused ]] const std::string& torrentFile, - [[maybe_unused]] const std::string& destination, - [[maybe_unused]] TorrentProgressCallback cb) -{ -#ifdef SYNC_USE_LIBTORRENT - std::lock_guard guard(_mutex); - - if (!_isInitialized) { - LERROR("Torrent session not initialized when adding torrent"); - return -1; - } - - libtorrent::error_code ec; - libtorrent::add_torrent_params p; - p.save_path = destination; - p.ti = std::make_shared(torrentFile, ec); - if (ec) { - LERROR(fmt::format("{}: {}", torrentFile, ec.message())); - } - const libtorrent::torrent_handle h = _session.add_torrent(p, ec); - if (ec) { - LERROR(fmt::format("{}: {}", torrentFile, ec.message())); - } - - TorrentId id = h.id(); - _torrents.emplace(id, Torrent{ id, h, std::move(cb) }); - return id; -#else // SYNC_USE_LIBTORRENT - throw TorrentError("SyncModule is compiled without libtorrent support"); -#endif // SYNC_USE_LIBTORRENT -} - -TorrentClient::TorrentId TorrentClient::addMagnetLink( - [[maybe_unused]] const std::string& magnetLink, - [[maybe_unused]] const std::string& destination, - [[maybe_unused]] TorrentProgressCallback cb) -{ -#ifdef SYNC_USE_LIBTORRENT - std::lock_guard guard(_mutex); - - // TODO: register callback! - if (!_isInitialized) { - LERROR("Torrent session not initialized when adding torrent"); - return -1; - } - libtorrent::error_code ec; - libtorrent::add_torrent_params p = libtorrent::parse_magnet_uri(magnetLink, ec); - if (ec) { - LERROR(fmt::format("{}: {}", magnetLink, ec.message())); - } - p.save_path = destination; - p.storage_mode = libtorrent::storage_mode_allocate; - const libtorrent::torrent_handle h = _session.add_torrent(p, ec); - if (ec) { - LERROR(fmt::format("{}: {}", magnetLink, ec.message())); - } - - TorrentId id = h.id(); - _torrents.emplace(id, Torrent{ id, h, std::move(cb) }); - return id; -#else // SYNC_USE_LIBTORRENT - throw TorrentError("SyncModule is compiled without libtorrent support"); -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::removeTorrent([[maybe_unused]] TorrentId id) { -#ifdef SYNC_USE_LIBTORRENT - std::lock_guard guard(_mutex); - - const auto it = _torrents.find(id); - if (it == _torrents.end()) { - return; - } - - const libtorrent::torrent_handle h = it->second.handle; - _session.remove_torrent(h); - - _torrents.erase(it); -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::notify([[maybe_unused]] TorrentId id) { -#ifdef SYNC_USE_LIBTORRENT - TorrentProgressCallback callback; - TorrentProgress progress; - - { - std::lock_guard guard(_mutex); - - const auto it = _torrents.find(id); - if (it == _torrents.end()) { - return; - } - - const libtorrent::torrent_handle h = it->second.handle; - const libtorrent::torrent_status status = h.status(); - - progress.finished = status.is_finished; - progress.nTotalBytesKnown = status.total_wanted > 0; - progress.nTotalBytes = status.total_wanted; - progress.nDownloadedBytes = status.total_wanted_done; - - callback = it->second.callback; - } - - callback(progress); -#endif // SYNC_USE_LIBTORRENT -} - -} // namespace openspace diff --git a/modules/sync/torrentclient.h b/modules/sync/torrentclient.h deleted file mode 100644 index e633e24fdf..0000000000 --- a/modules/sync/torrentclient.h +++ /dev/null @@ -1,125 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__ -#define __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__ - -#ifdef SYNC_USE_LIBTORRENT - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef SYNC_USE_LIBTORRENT -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable : 4265) -#pragma warning (disable : 4996) -#endif // _MSC_VER - -// libtorrent defines a class with the name 'defer', which messes with out #define of the -// defer macro in ghoul/misc/defer.h -#undef defer - -#include -#include - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - - -#else // SYNC_USE_LIBTORRENT -// Dummy definition to make TorrentClient compile, these is not actually used if -// SYNC_USE_LIBTORRENT is FALSE -namespace libtorrent { - using torrent_handle = void*; - using session = void*; -} // namespace libtorrent - -#endif // SYNC_USE_LIBTORRENT - -namespace openspace { - -struct TorrentError : public ghoul::RuntimeError { - explicit TorrentError(std::string msg); -}; - -class TorrentClient { -public: - struct TorrentProgress { - bool finished = false; - bool nTotalBytesKnown = false; - size_t nTotalBytes = 0; - size_t nDownloadedBytes = 0; - }; - - using TorrentProgressCallback = std::function; - using TorrentId = int32_t; - - void initialize(); - void deinitialize(); - - TorrentId addTorrentFile(const std::string& torrentFile, - const std::string& destination, TorrentProgressCallback cb); - - TorrentId addMagnetLink(const std::string& magnetLink, const std::string& destination, - TorrentProgressCallback cb); - - void removeTorrent(TorrentId id); - -private: - struct Torrent { - TorrentId id; - libtorrent::torrent_handle handle; - TorrentProgressCallback callback; - }; - - void notify(TorrentId id); - void pollAlerts(); - -#ifdef SYNC_USE_LIBTORRENT - libtorrent::session _session; - bool _isInitialized = false; - std::atomic_bool _isActive = false; -#endif // SYNC_USE_LIBTORRENT - - std::thread _torrentThread; - std::condition_variable _abortNotifier; - std::mutex _abortMutex; - std::mutex _mutex; - - std::unordered_map _torrents; -}; - -} // namespace openspace - -#endif // SYNC_USE_LIBTORRENT - -#endif // __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__ From 2a30b499d81c7db60ab751ee78fb2d2df3d1aa88 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 18 Jul 2019 17:06:00 +0200 Subject: [PATCH 14/32] Update Apollo assets --- data/assets/apollo_sites.scene | 5 ++++- data/assets/scene/solarsystem/missions/apollo/apollo11.asset | 4 ++-- .../assets/scene/solarsystem/missions/apollo/lem_model.asset | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/data/assets/apollo_sites.scene b/data/assets/apollo_sites.scene index 8a487e3b25..09721fe7d6 100644 --- a/data/assets/apollo_sites.scene +++ b/data/assets/apollo_sites.scene @@ -5,10 +5,12 @@ local sceneHelper = asset.require('util/scene_helper') -- local station2 = asset.require('scene/solarsystem/missions/apollo/bouldersstation2') -- local station6 = asset.require('scene/solarsystem/missions/apollo/bouldersstation6') -- local station7 = asset.require('scene/solarsystem/missions/apollo/bouldersstation7') +asset.require('scene/solarsystem/missions/apollo/apollo8') asset.require('scene/solarsystem/missions/apollo/apollo11') asset.require('scene/solarsystem/missions/apollo/a17_lem') asset.require('scene/solarsystem/missions/apollo/apollo_globebrowsing') asset.require('scene/solarsystem/missions/apollo/apollo_11_lem_flipbook') +asset.require('scene/solarsystem/missions/apollo/insignias_map') local Keybindings = { { @@ -85,8 +87,9 @@ asset.onInitialize(function () "Apollo11", "Apollo11LunarLander", -- "Station_2_Boulder2", "Station_6_Fragment1" }) + + openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0); -- To enable both sites by default, uncomment these lines - -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0.000000); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_17.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_LEM.Enabled', true); diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo11.asset b/data/assets/scene/solarsystem/missions/apollo/apollo11.asset index e07492b1e1..ac1c6eb153 100644 --- a/data/assets/scene/solarsystem/missions/apollo/apollo11.asset +++ b/data/assets/scene/solarsystem/missions/apollo/apollo11.asset @@ -14,7 +14,7 @@ local kernelsFolder = asset.syncedResource({ }) local modelFolder = asset.syncedResource({ - Name = "Apollo Kernels", + Name = "Apollo Models", Type = "HttpSynchronization", Identifier = "apollo_11_models", Version = 1 @@ -194,7 +194,7 @@ local Apollo11LemDescentModel = { Type = "RenderableModel", Geometry = { Type = "MultiModelGeometry", - GeometryFile = model.modelFolder .. "/LM-2_ver2clean.obj" + GeometryFile = model.modelFolder .. "/lmremoved.obj" }, ColorTexture = model.modelFolder .. "/LM-2_ver2clean_u1_v1.jpeg", LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) diff --git a/data/assets/scene/solarsystem/missions/apollo/lem_model.asset b/data/assets/scene/solarsystem/missions/apollo/lem_model.asset index cd592de5e8..dbc9210394 100644 --- a/data/assets/scene/solarsystem/missions/apollo/lem_model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/lem_model.asset @@ -2,7 +2,7 @@ local modelFolder = asset.syncedResource({ Name = "Apollo Lem Models", Type = "HttpSynchronization", Identifier = "apollo_lem_model", - Version = 2 + Version = 3 }) asset.export('modelFolder', modelFolder) From fc28b98db99300852635d75ed048ca7cde1bb50c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 19 Jul 2019 09:55:41 +0200 Subject: [PATCH 15/32] Add basic instrumentation options to the renderengine and globebrowsing module Instrumentation is disabled on default, but can be enabled in CMake --- CMakeLists.txt | 5 ++ include/openspace/rendering/renderengine.h | 18 ++++- modules/globebrowsing/CMakeLists.txt | 5 ++ modules/globebrowsing/globebrowsingmodule.cpp | 80 +++++++++++++++++++ modules/globebrowsing/globebrowsingmodule.h | 25 ++++++ modules/globebrowsing/src/layer.cpp | 7 +- modules/globebrowsing/src/layer.h | 3 +- modules/globebrowsing/src/layergroup.cpp | 7 +- modules/globebrowsing/src/layergroup.h | 3 +- modules/globebrowsing/src/layermanager.cpp | 6 +- modules/globebrowsing/src/layermanager.h | 3 +- modules/globebrowsing/src/renderableglobe.cpp | 24 +++++- modules/globebrowsing/src/renderableglobe.h | 4 + modules/globebrowsing/src/tileprovider.cpp | 12 ++- modules/globebrowsing/src/tileprovider.h | 4 +- src/rendering/renderengine.cpp | 75 ++++++++++++++--- 16 files changed, 255 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc5a7104df..724729bcad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,11 @@ if (OPENSPACE_WITH_ABUFFER_RENDERER) target_compile_definitions(openspace-core PUBLIC "OPENSPACE_WITH_ABUFFER_RENDERER") endif () +option(OPENSPACE_WITH_INSTRUMENTATION "Add instrumentation options" OFF) +if (OPENSPACE_WITH_INSTRUMENTATION) + target_compile_definitions(openspace-core PUBLIC "OPENSPACE_WITH_INSTRUMENTATION") +endif () + # Just in case, create the bin directory add_custom_command( diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 779e6cf926..3ab7b9baaf 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -187,7 +187,21 @@ private: properties::TriggerProperty _takeScreenshot; bool _shouldTakeScreenshot = false; properties::BoolProperty _applyWarping; - properties::BoolProperty _showFrameNumber; + properties::BoolProperty _showFrameInformation; +#ifdef OPENSPACE_WITH_INSTRUMENTATION + struct FrameInfo { + uint64_t iFrame; + double deltaTime; + double avgDeltaTime; + }; + + struct { + std::vector frames; + uint64_t lastSavedFrame = 0; + uint16_t saveEveryNthFrame = 2048; + } _frameInfo; + properties::BoolProperty _saveFrameInformation; +#endif // OPENSPACE_WITH_INSTRUMENTATION properties::BoolProperty _disableMasterRendering; properties::FloatProperty _globalBlackOutFactor; @@ -205,7 +219,7 @@ private: std::vector _programs; - std::shared_ptr _fontBig; + std::shared_ptr _fontFrameInfo; std::shared_ptr _fontInfo; std::shared_ptr _fontDate; std::shared_ptr _fontLog; diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 5d2bbafadf..7d46e40e1a 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -109,6 +109,11 @@ create_new_module( ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) +option(OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION "Instrumentation for GlobeBrowsing Performance" OFF) +if (OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION) + target_compile_definitions(openspace-module-globebrowsing INTERFACE "OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION") +endif () + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/gdal_data DESTINATION modules/globebrowsing) if (WIN32) diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index e5cc4fd5f4..081fedebdc 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -101,6 +101,14 @@ namespace { "The maximum size of the MemoryAwareTileCache, on the CPU and GPU." }; +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + constexpr const openspace::properties::Property::PropertyInfo InstrumentationInfo = { + "SaveInstrumentationInfo", + "Save Instrumentation Info", + "If enabled, the instrumentation data is saved to disk at the end of the frame." + }; +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + openspace::GlobeBrowsingModule::Capabilities parseSubDatasets(char** subDatasets, int nSubdatasets) @@ -163,12 +171,24 @@ GlobeBrowsingModule::GlobeBrowsingModule() , _wmsCacheLocation(WMSCacheLocationInfo, "${BASE}/cache_gdal") , _wmsCacheSizeMB(WMSCacheSizeInfo, 1024) , _tileCacheSizeMB(TileCacheSizeInfo, 1024) +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + , _saveInstrumentation(InstrumentationInfo, false) +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION { addProperty(_wmsCacheEnabled); addProperty(_offlineMode); addProperty(_wmsCacheLocation); addProperty(_wmsCacheSizeMB); addProperty(_tileCacheSizeMB); + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _saveInstrumentation.onChange([&]() { + if (_saveInstrumentation) { + _frameInfo.lastSavedFrame = global::renderEngine.frameNumber(); + } + }); + addProperty(_saveInstrumentation); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION } void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { @@ -235,6 +255,43 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { // Render global::callback::render.emplace_back([&]() { _tileCache->update(); }); + // Postdraw +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + global::callback::postDraw.emplace_back([&]() { + // >= as we might have multiple frames per postDraw call (stereo rendering, + // fisheye, etc) + const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame; + const bool shouldSave = _saveInstrumentation && + global::renderEngine.frameNumber() >= next; + if (shouldSave) { + using K = const globebrowsing::RenderableGlobe*; + using V = std::vector; + for (const std::pair& i : _frameInfo.frames) { + std::string filename = fmt::format( + "_inst_globebrowsing_{}_{}_{}.txt", + i.first->owner()->identifier(), // Owner of the renderable has a name + _frameInfo.lastSavedFrame, + _frameInfo.saveEveryNthFrame + ); + std::ofstream file(absPath("${BIN}/" + filename)); + for (const FrameInfo& f : i.second) { + std::string line = fmt::format( + "{}\t{}\t{}\t{}", + f.iFrame, + f.nTilesRenderedLocal, + f.nTilesRenderedGlobal, + f.nTilesUploaded + ); + file << line << '\n'; + } + } + + _frameInfo.frames.clear(); + _frameInfo.lastSavedFrame = global::renderEngine.frameNumber(); + } + }); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + // Deinitialize global::callback::deinitialize.emplace_back([&]() { GdalWrapper::destroy(); }); @@ -729,4 +786,27 @@ uint64_t GlobeBrowsingModule::wmsCacheSize() const { return size * 1024 * 1024; } +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION +void GlobeBrowsingModule::addFrameInfo(globebrowsing::RenderableGlobe* globe, + uint32_t nTilesRenderedLocal, + uint32_t nTilesRenderedGlobal, + uint32_t nTilesUploaded) +{ + auto it = _frameInfo.frames.find(globe); + if (it == _frameInfo.frames.end()) { + _frameInfo.frames[globe] = std::vector(); + _frameInfo.frames[globe].reserve(_frameInfo.saveEveryNthFrame); + } + else { + it->second.push_back({ + global::renderEngine.frameNumber(), + nTilesRenderedLocal, + nTilesRenderedGlobal, + nTilesUploaded + }); + } +} + +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index fc96cd91c4..89e397d8ab 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -93,6 +93,11 @@ public: std::string wmsCacheLocation() const; uint64_t wmsCacheSize() const; // bytes +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + void addFrameInfo(globebrowsing::RenderableGlobe* globe, uint32_t nTilesRenderedLocal, + uint32_t nTilesRenderedGlobal, uint32_t nTilesUploaded); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + protected: void internalInitialize(const ghoul::Dictionary&) override; @@ -134,6 +139,26 @@ private: std::map _capabilitiesMap; std::multimap _urlList; + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + struct FrameInfo { + uint64_t iFrame = 0; + uint32_t nTilesRenderedLocal = 0; + uint32_t nTilesRenderedGlobal = 0; + uint32_t nTilesUploaded = 0; + }; + + struct { + std::unordered_map< + globebrowsing::RenderableGlobe*, + std::vector + > frames; + + uint64_t lastSavedFrame = 0; + const uint16_t saveEveryNthFrame = 2048; + } _frameInfo; + properties::BoolProperty _saveInstrumentation; +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION }; } // namespace openspace diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index 52e69b7731..e07f632bbb 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -341,9 +341,12 @@ void Layer::onChange(std::function callback) { _onChangeCallback = std::move(callback); } -void Layer::update() { +int Layer::update() { if (_tileProvider) { - tileprovider::update(*_tileProvider); + return tileprovider::update(*_tileProvider); + } + else { + return 0; } } diff --git a/modules/globebrowsing/src/layer.h b/modules/globebrowsing/src/layer.h index 4658468b90..908217611f 100644 --- a/modules/globebrowsing/src/layer.h +++ b/modules/globebrowsing/src/layer.h @@ -64,7 +64,8 @@ public: void onChange(std::function callback); - void update(); + // Return: number of tiles that were updated + int update(); glm::ivec2 tilePixelStartOffset() const; glm::ivec2 tilePixelSizeDifference() const; diff --git a/modules/globebrowsing/src/layergroup.cpp b/modules/globebrowsing/src/layergroup.cpp index f6088e8869..e0aff6f0af 100644 --- a/modules/globebrowsing/src/layergroup.cpp +++ b/modules/globebrowsing/src/layergroup.cpp @@ -91,15 +91,18 @@ void LayerGroup::deinitialize() { } } -void LayerGroup::update() { +int LayerGroup::update() { + int res = 0; _activeLayers.clear(); for (const std::unique_ptr& layer : _layers) { if (layer->enabled()) { - layer->update(); + res += layer->update(); _activeLayers.push_back(layer.get()); } } + + return res; } Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { diff --git a/modules/globebrowsing/src/layergroup.h b/modules/globebrowsing/src/layergroup.h index 923cef7011..7db9a718de 100644 --- a/modules/globebrowsing/src/layergroup.h +++ b/modules/globebrowsing/src/layergroup.h @@ -48,7 +48,8 @@ struct LayerGroup : public properties::PropertyOwner { void deinitialize(); /// Updates all layers tile providers within this group - void update(); + /// Return: Number of tiles that were updated + int update(); Layer* addLayer(const ghoul::Dictionary& layerDict); void deleteLayer(const std::string& layerName); diff --git a/modules/globebrowsing/src/layermanager.cpp b/modules/globebrowsing/src/layermanager.cpp index 0f442d8bcf..ae677ada58 100644 --- a/modules/globebrowsing/src/layermanager.cpp +++ b/modules/globebrowsing/src/layermanager.cpp @@ -111,10 +111,12 @@ std::array LayerManager::layerGroups( return res; } -void LayerManager::update() { +int LayerManager::update() { + int res = 0; for (std::unique_ptr& layerGroup : _layerGroups) { - layerGroup->update(); + res += layerGroup->update(); } + return res; } void LayerManager::reset(bool includeDisabled) { diff --git a/modules/globebrowsing/src/layermanager.h b/modules/globebrowsing/src/layermanager.h index de7fbb4c62..36de309488 100644 --- a/modules/globebrowsing/src/layermanager.h +++ b/modules/globebrowsing/src/layermanager.h @@ -63,7 +63,8 @@ public: std::array layerGroups() const; - void update(); + // Return: Number of tiles updated + int update(); void reset(bool includeDisabled = false); void onChange(std::function callback); diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 4cccfedacd..51c263d9c3 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -47,6 +47,13 @@ #include #include +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION +#include +#include +openspace::GlobeBrowsingModule* _module = nullptr; + +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + namespace { // Global flags to modify the RenderableGlobe constexpr const bool LimitLevelByAvailableData = true; @@ -595,10 +602,13 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) if (dictionary.hasKeyAndValue(KeyLabels)) { _labelsDictionary = dictionary.value(KeyLabels); } + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _module = global::moduleEngine.module(); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION } void RenderableGlobe::initializeGL() { - if (!_labelsDictionary.empty()) { _globeLabelsComponent.initialize(_labelsDictionary, this); addPropertySubOwner(_globeLabelsComponent); @@ -745,7 +755,11 @@ void RenderableGlobe::update(const UpdateData& data) { _layerManager.reset(); _debugProperties.resetTileProviders = false; } +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _nUploadedTiles = _layerManager.update(); +#else _layerManager.update(); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION if (_nLayersIsDirty) { std::array lgs = @@ -1034,6 +1048,14 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) { } _localRenderer.program->deactivate(); +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _module->addFrameInfo( + this, + std::min(localCount, ChunkBufferSize), + std::min(globalCount, ChunkBufferSize), + _nUploadedTiles + ); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION if (_debugProperties.showChunkBounds || _debugProperties.showChunkAABB) { for (int i = 0; i < std::min(globalCount, ChunkBufferSize); ++i) { diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index 93022b532c..7886c0d3e2 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -274,6 +274,10 @@ private: // Labels GlobeLabelsComponent _globeLabelsComponent; ghoul::Dictionary _labelsDictionary; + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + int _nUploadedTiles = 0; +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/src/tileprovider.cpp b/modules/globebrowsing/src/tileprovider.cpp index addef1e23a..ad72426685 100644 --- a/modules/globebrowsing/src/tileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider.cpp @@ -162,15 +162,17 @@ void initAsyncTileDataReader(DefaultTileProvider& t, TileTextureInitData initDat ); } -void initTexturesFromLoadedData(DefaultTileProvider& t) { +bool initTexturesFromLoadedData(DefaultTileProvider& t) { if (t.asyncTextureDataProvider) { std::optional tile = t.asyncTextureDataProvider->popFinishedRawTile(); if (tile) { const cache::ProviderTileKey key = { tile->tileIndex, t.uniqueIdentifier }; ghoul_assert(!t.tileCache->exist(key), "Tile must not be existing in cache"); t.tileCache->createTileAndPut(key, std::move(tile.value())); + return true; } } + return false; } @@ -1073,7 +1075,7 @@ TileDepthTransform depthTransform(TileProvider& tp) { -void update(TileProvider& tp) { +int update(TileProvider& tp) { switch (tp.type) { case Type::DefaultTileProvider: { DefaultTileProvider& t = static_cast(tp); @@ -1082,7 +1084,7 @@ void update(TileProvider& tp) { } t.asyncTextureDataProvider->update(); - initTexturesFromLoadedData(t); + bool hasUploaded = initTexturesFromLoadedData(t); if (t.asyncTextureDataProvider->shouldBeDeleted()) { t.asyncTextureDataProvider = nullptr; @@ -1091,6 +1093,9 @@ void update(TileProvider& tp) { tileTextureInitData(t.layerGroupID, t.padTiles, t.tilePixelSize) ); } + if (hasUploaded) { + return 1; + } break; } case Type::SingleImageTileProvider: @@ -1132,6 +1137,7 @@ void update(TileProvider& tp) { default: throw ghoul::MissingCaseException(); } + return 0; } diff --git a/modules/globebrowsing/src/tileprovider.h b/modules/globebrowsing/src/tileprovider.h index c367638374..c7e3cd5196 100644 --- a/modules/globebrowsing/src/tileprovider.h +++ b/modules/globebrowsing/src/tileprovider.h @@ -222,8 +222,10 @@ TileDepthTransform depthTransform(TileProvider& tp); /** * This method should be called once per frame. Here, TileProviders * are given the opportunity to update their internal state. + * + * \return The number of tiles that have been updated in this call */ -void update(TileProvider& tp); +int update(TileProvider& tp); /** * Provides a uniform way of all TileProviders to reload or diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 4498e1f9cf..cbdb090ad0 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -144,11 +144,20 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo ShowFrameNumberInfo = { - "ShowFrameNumber", - "Show Frame Number", - "If this value is enabled, the current frame number is rendered into the window." + "ShowFrameInformation", + "Show Frame Information", + "If this value is enabled, the current frame number and frame times are rendered " + "into the window." }; +#ifdef OPENSPACE_WITH_INSTRUMENTATION + constexpr openspace::properties::Property::PropertyInfo SaveFrameInfo = { + "SaveFrameInformation", + "Save Frame Information", + "Saves the frame information to disk" + }; +#endif // OPENSPACE_WITH_INSTRUMENTATION + constexpr openspace::properties::Property::PropertyInfo DisableMasterInfo = { "DisableMasterRendering", "Disable Master Rendering", @@ -239,7 +248,10 @@ RenderEngine::RenderEngine() , _showCameraInfo(ShowCameraInfo, true) , _takeScreenshot(TakeScreenshotInfo) , _applyWarping(ApplyWarpingInfo, false) - , _showFrameNumber(ShowFrameNumberInfo, false) + , _showFrameInformation(ShowFrameNumberInfo, false) +#ifdef OPENSPACE_WITH_INSTRUMENTATION + , _saveFrameInformation(SaveFrameInfo, false) +#endif // OPENSPACE_WITH_INSTRUMENTATION , _disableMasterRendering(DisableMasterInfo, false) , _globalBlackOutFactor(GlobalBlackoutFactorInfo, 1.f, 0.f, 1.f) , _nAaSamples(AaSamplesInfo, 4, 1, 8) @@ -317,7 +329,15 @@ RenderEngine::RenderEngine() _takeScreenshot.onChange([this](){ _shouldTakeScreenshot = true; }); addProperty(_takeScreenshot); - addProperty(_showFrameNumber); + addProperty(_showFrameInformation); +#ifdef OPENSPACE_WITH_INSTRUMENTATION + _saveFrameInformation.onChange([&]() { + if (_saveFrameInformation) { + _frameInfo.lastSavedFrame = frameNumber(); + } + }); + addProperty(_saveFrameInformation); +#endif // OPENSPACE_WITH_INSTRUMENTATION addProperty(_globalRotation); addProperty(_screenSpaceRotation); @@ -415,12 +435,12 @@ void RenderEngine::initializeGL() { // development global::windowDelegate.setNearFarClippingPlane(0.001f, 1000.f); - //Set horizontal FOV value with whatever the field of view (in degrees) is of the + // Set horizontal FOV value with whatever the field of view (in degrees) is of the // initialized window _horizFieldOfView = static_cast(global::windowDelegate.getHorizFieldOfView()); - constexpr const float FontSizeBig = 50.f; - _fontBig = global::fontManager.font(KeyFontMono, FontSizeBig); + constexpr const float FontSizeFrameinfo = 32.f; + _fontFrameInfo = global::fontManager.font(KeyFontMono, FontSizeFrameinfo); constexpr const float FontSizeTime = 15.f; _fontDate = global::fontManager.font(KeyFontMono, FontSizeTime); constexpr const float FontSizeMono = 10.f; @@ -582,13 +602,18 @@ void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMat ); } - if (_showFrameNumber) { + if (_showFrameInformation) { glm::vec2 penPosition = glm::vec2( fontResolution().x / 2 - 50, fontResolution().y / 3 ); - RenderFont(*_fontBig, penPosition, std::to_string(_frameNumber)); + std::string fn = std::to_string(_frameNumber); + std::string dt = std::to_string(global::windowDelegate.deltaTime()); + std::string avgDt = std::to_string(global::windowDelegate.averageDeltaTime()); + + std::string res = "Frame: " + fn + '\n' + "Dt: " + dt + '\n' + "Avg Dt: " + avgDt; + RenderFont(*_fontFrameInfo, penPosition, res); } ++_frameNumber; @@ -794,6 +819,36 @@ void RenderEngine::postDraw() { scene()->allSceneGraphNodes() ); } + + if (_saveFrameInformation) { + _frameInfo.frames.push_back({ + frameNumber(), + global::windowDelegate.deltaTime(), + global::windowDelegate.averageDeltaTime() + }); + } + + +#ifdef OPENSPACE_WITH_INSTRUMENTATION + const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame; + const bool shouldSave = _saveFrameInformation && frameNumber() >= next; + if (shouldSave) { + std::string filename = fmt::format( + "_inst_renderengine_{}_{}.txt", + _frameInfo.lastSavedFrame, _frameInfo.saveEveryNthFrame + ); + std::ofstream file(absPath("${BIN}/" + filename)); + for (const FrameInfo& i : _frameInfo.frames) { + std::string line = fmt::format( + "{}\t{}\t{}", i.iFrame, i.deltaTime, i.avgDeltaTime + ); + file << line << '\n'; + } + + _frameInfo.frames.clear(); + _frameInfo.lastSavedFrame = frameNumber(); + } +#endif // OPENSPACE_WITH_INSTRUMENTATION } Scene* RenderEngine::scene() { From 852115e3091bc802d403c434dce2fafa74e3c342 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 19 Jul 2019 11:08:07 +0200 Subject: [PATCH 16/32] Compile fix if instrumentation is disabled --- src/rendering/renderengine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index cbdb090ad0..58f99450a0 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -820,6 +820,7 @@ void RenderEngine::postDraw() { ); } +#ifdef OPENSPACE_WITH_INSTRUMENTATION if (_saveFrameInformation) { _frameInfo.frames.push_back({ frameNumber(), @@ -828,8 +829,6 @@ void RenderEngine::postDraw() { }); } - -#ifdef OPENSPACE_WITH_INSTRUMENTATION const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame; const bool shouldSave = _saveFrameInformation && frameNumber() >= next; if (shouldSave) { From 9934fc03b9cdc9821f74fd6d323844dcc5b6209e Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 19 Jul 2019 11:09:04 +0200 Subject: [PATCH 17/32] Fix scaling issue with screenspace renderables (#939) --- .../openspace/rendering/screenspacerenderable.h | 4 +--- modules/base/rendering/screenspacedashboard.cpp | 1 - .../base/rendering/screenspaceframebuffer.cpp | 16 +++++++++------- modules/base/shaders/screenspace_fs.glsl | 2 -- modules/webbrowser/src/screenspacebrowser.cpp | 2 -- src/rendering/screenspacerenderable.cpp | 13 +++---------- 6 files changed, 13 insertions(+), 25 deletions(-) diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index e846f76de9..d5dfabef94 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -106,10 +106,8 @@ protected: properties::TriggerProperty _delete; glm::ivec2 _objectSize; - UniformCache(occlusionDepth, alpha, modelTransform, viewProj, texture) _uniformCache; + UniformCache(alpha, modelTransform, viewProj, texture) _uniformCache; std::unique_ptr _shader; - - glm::vec2 _originalViewportSize; }; } // namespace openspace diff --git a/modules/base/rendering/screenspacedashboard.cpp b/modules/base/rendering/screenspacedashboard.cpp index 9f271d350c..d86376d06f 100644 --- a/modules/base/rendering/screenspacedashboard.cpp +++ b/modules/base/rendering/screenspacedashboard.cpp @@ -212,7 +212,6 @@ void ScreenSpaceDashboard::update() { if (global::windowDelegate.windowHasResized()) { const glm::ivec2 size = global::windowDelegate.currentWindowResolution(); _size = { 0.f, 0.f, size.x, size.y }; - _originalViewportSize = size; createFramebuffer(); } } diff --git a/modules/base/rendering/screenspaceframebuffer.cpp b/modules/base/rendering/screenspaceframebuffer.cpp index 28ba4d80e0..5a94669b99 100644 --- a/modules/base/rendering/screenspaceframebuffer.cpp +++ b/modules/base/rendering/screenspaceframebuffer.cpp @@ -106,15 +106,15 @@ void ScreenSpaceFramebuffer::render() { const glm::vec2& resolution = global::windowDelegate.currentWindowResolution(); const glm::vec4& size = _size.value(); - const float xratio = _originalViewportSize.x / (size.z - size.x); - const float yratio = _originalViewportSize.y / (size.w - size.y);; + const float xratio = resolution.x / (size.z - size.x); + const float yratio = resolution.y / (size.w - size.y);; if (!_renderFunctions.empty()) { glViewport( static_cast(-size.x * xratio), static_cast(-size.y * yratio), - static_cast(_originalViewportSize.x * xratio), - static_cast(_originalViewportSize.y * yratio) + static_cast(resolution.x * xratio), + static_cast(resolution.y * yratio) ); GLint defaultFBO = _framebuffer->getActiveObject(); _framebuffer->activate(); @@ -170,14 +170,16 @@ void ScreenSpaceFramebuffer::removeAllRenderFunctions() { } void ScreenSpaceFramebuffer::createFramebuffer() { + glm::vec2 resolution = global::windowDelegate.currentWindowResolution(); + _framebuffer = std::make_unique(); _framebuffer->activate(); _texture = std::make_unique(glm::uvec3( - _originalViewportSize.x, - _originalViewportSize.y, + resolution.x, + resolution.y, 1 )); - _objectSize = glm::ivec2(_originalViewportSize); + _objectSize = glm::ivec2(resolution); _texture->uploadTexture(); _texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); diff --git a/modules/base/shaders/screenspace_fs.glsl b/modules/base/shaders/screenspace_fs.glsl index 6d4e66856c..9dc5fd70ad 100644 --- a/modules/base/shaders/screenspace_fs.glsl +++ b/modules/base/shaders/screenspace_fs.glsl @@ -29,10 +29,8 @@ in vec2 vs_st; in vec4 vs_position; uniform sampler2D texture1; -uniform float OcclusionDepth; uniform float Alpha; - Fragment getFragment() { Fragment frag; diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 075c375f5c..965a693965 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -113,7 +113,6 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) } bool ScreenSpaceBrowser::initialize() { - _originalViewportSize = global::windowDelegate.currentWindowSize(); _renderHandler->setTexture(*_texture); createShaders(); @@ -164,7 +163,6 @@ void ScreenSpaceBrowser::update() { if (_isDimensionsDirty) { _browserInstance->reshape(_dimensions.value()); - _originalViewportSize = _dimensions.value(); _isDimensionsDirty = false; } } diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 10c1b6726b..d8aa117073 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -42,8 +42,8 @@ namespace { constexpr const char* KeyType = "Type"; constexpr const char* KeyTag = "Tag"; - constexpr const std::array UniformNames = { - "OcclusionDepth", "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" + constexpr const std::array UniformNames = { + "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" }; constexpr openspace::properties::Property::PropertyInfo EnabledInfo = { @@ -451,7 +451,6 @@ bool ScreenSpaceRenderable::initialize() { } bool ScreenSpaceRenderable::initializeGL() { - _originalViewportSize = global::windowDelegate.currentWindowResolution(); createShaders(); return isReady(); } @@ -523,15 +522,9 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { float textureRatio = static_cast(_objectSize.y) / static_cast(_objectSize.x); - float scalingRatioX = _originalViewportSize.x / resolution.x; - float scalingRatioY = _originalViewportSize.y / resolution.y; glm::mat4 scale = glm::scale( glm::mat4(1.f), - glm::vec3( - _scale * scalingRatioX, - _scale * scalingRatioY * textureRatio, - 1.f - ) + glm::vec3(_scale, _scale * textureRatio, 1.f) ); // Simulate orthographic projection by distance to plane. From 134468b0d51cc39730d5b1ca36c0ec789f4cda5a Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 19 Jul 2019 11:31:58 +0200 Subject: [PATCH 18/32] Add missing asset file --- .../missions/apollo/insignias_map.asset | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 data/assets/scene/solarsystem/missions/apollo/insignias_map.asset diff --git a/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset b/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset new file mode 100644 index 0000000000..7aa0159960 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset @@ -0,0 +1,120 @@ +-- Apollo mission insignias on their locations on the Lunar surface. +-- The insignias are invisible by default, but can be enabled using shown or hidden using +-- the exported functions `showInsignias(interpolationDuration)` and `hideInsignias(interpolationDuration)`. + +local assetHelper = asset.require('util/asset_helper') + +local insigniasPath = asset.syncedResource({ + Name = "Apollo Insignias", + Type = "HttpSynchronization", + Identifier = "apollo_insignias", + Version = 1 +}) +local moon = asset.require('scene/solarsystem/planets/earth/moon/moon') + +local landingData = { + { + Identifier = "Apollo11", + Name = "Apollo 11", + Name = "Apollo 11", + Texture = "apollo11.png", + LunarModule = {0.67409, 23.47298, 0.0}, + }, + { + Identifier = "Apollo12", + Name = "Apollo 12", + Texture = "apollo12.png", + LunarModule = {-3.01381, -23.41930, 0.0} + }, + { + Identifier = "Apollo14", + Name = "Apollo 14", + Texture = "apollo14.png", + LunarModule = {-3.64544, -17.47139, 0.0} + }, + { + Identifier = "Apollo15", + Name = "Apollo 15", + Texture = "apollo15.png", + LunarModule = {26.13224, 3.63400, 0.0} + }, + { + Identifier = "Apollo16", + Name = "Apollo 16", + Texture = "apollo16.png", + LunarModule = {-8.97341, 15.49859, 0.0} + }, + { + Identifier = "Apollo17", + Name = "Apollo 17", + Texture = "apollo17.png", + LunarModule = {20.18809, 30.77475, 0.0} + } +} + +local nodes = {} +local size = 100000; + +for i = 1, #landingData do + local entry = landingData[i] + nodes[i] = { + Identifier = entry.Identifier .. "Insignia", + Parent = moon.Moon.Identifier, + Transform = { + Translation = { + Type = "GlobeTranslation", + Globe = moon.Moon.Identifier, + Latitude = entry.LunarModule[1], + Longitude = entry.LunarModule[2], + Altitude = entry.LunarModule[3] + size * 1.1, + UseHeightmap = false + }, + }, + Renderable = { + Type = "RenderablePlaneImageLocal", + Size = size, + Origin = "Center", + Billboard = true, + Texture = insigniasPath .. "/" .. entry.Texture, + Opacity = 0.0 + }, + GUI = { + Path = "/Other/Labels", + Name = entry.Name .. " Insignia" + } + } +end + +asset.onInitialize(function () + openspace.bindShortcut( + 'Show Apollo Landing Labels', + 'openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 1, 0.5)', + 'Show patches of the Apollo missions on their respective landing sites', + '/Missions/Apollo' + ) + + openspace.bindShortcut( + 'Hide Apollo Landing Labels', + 'openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 0, 0.5)', + 'Hide patches of the Apollo missions on their respective landing sites', + '/Missions/Apollo' + ) +end) + +asset.export('showInsignia', function (missinNumber, interpolationDuration) + openspace.setPropertyValue("Scene.Apollo" .. missionNumber .. "Insignia.Renderable.Opacity", 1, interpolationDuration) +end) + +asset.export('hideInsignia', function (missinNumber, interpolationDuration) + openspace.setPropertyValue("Scene.Apollo" .. missionNumber .. "Insignia.Renderable.Opacity", 0, interpolationDuration) +end) + +asset.export('showInsignias', function (interpolationDuration) + openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 1, interpolationDuration) +end) + +asset.export('hideInsignias', function (interpolationDuration) + openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 0, interpolationDuration) +end) + +assetHelper.registerSceneGraphNodesAndExport(asset, nodes) \ No newline at end of file From 5079f3fc60f809820fb8d781baa080d49cfec385 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 19 Jul 2019 16:49:54 +0200 Subject: [PATCH 19/32] Feature/multiple endpoints (#938) * Add support for multiple endpoints for webserver * Add support for a default endpoint (redirect) in webgui * Always serve prod gui * Update webgui deps --- data/assets/util/static_server.asset | 21 +++ data/assets/util/webgui.asset | 52 ++++--- modules/cefwebgui/cefwebguimodule.cpp | 16 +- modules/cefwebgui/cefwebguimodule.h | 4 + .../server/src/topics/setpropertytopic.cpp | 24 ++- modules/webgui/webguimodule.cpp | 140 ++++++++++++++++-- modules/webgui/webguimodule.h | 18 ++- 7 files changed, 231 insertions(+), 44 deletions(-) create mode 100644 data/assets/util/static_server.asset diff --git a/data/assets/util/static_server.asset b/data/assets/util/static_server.asset new file mode 100644 index 0000000000..94759f5936 --- /dev/null +++ b/data/assets/util/static_server.asset @@ -0,0 +1,21 @@ +local backendHash = "7ca0a34e9c4c065b7bfad0623db0e322bf3e0af9" +local dataProvider = "data.openspaceproject.com/files/webgui" + +local backend = asset.syncedResource({ + Identifier = "WebGuiBackend", + Name = "Web Gui Backend", + Type = "UrlSynchronization", + Url = dataProvider .. "/backend/" .. backendHash .. "/backend.zip" +}) + +asset.onInitialize(function () + -- Unzip the server bundle + dest = backend .. "/backend" + if not openspace.directoryExists(dest) then + openspace.unzipFile(backend .. "/backend.zip", dest, true) + end + + openspace.setPropertyValueSingle( + "Modules.WebGui.ServerProcessEntryPoint", backend .. "/backend/backend.js" + ) +end) \ No newline at end of file diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index d4d54451c5..b51a582660 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -1,18 +1,11 @@ +asset.require('./static_server') + local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "c603ad07d1407a7d3def43f1e203244cee1c06f6" -local backendHash = "84737f9785f12efbb12d2de9d511154c6215fe9c" - +local frontendHash = "2d1bb8d8d8478b6ed025ccc6f1e0ceacf04b6114" local dataProvider = "data.openspaceproject.com/files/webgui" -local backend = asset.syncedResource({ - Identifier = "WebGuiBackend", - Name = "Web Gui Backend", - Type = "UrlSynchronization", - Url = dataProvider .. "/backend/" .. backendHash .. "/backend.zip" -}) - local frontend = asset.syncedResource({ Identifier = "WebGuiFrontend", Name = "Web Gui Frontend", @@ -27,22 +20,21 @@ asset.onInitialize(function () openspace.unzipFile(frontend .. "/frontend.zip", dest, true) end - -- Unzip the frontend bundle - dest = backend .. "/backend" - if not openspace.directoryExists(dest) then - openspace.unzipFile(backend .. "/backend.zip", dest, true) - end + -- Serve the production GUI: + local directories = openspace.getPropertyValue("Modules.WebGui.Directories") + directories[#directories + 1] = "frontend" + directories[#directories + 1] = frontend .. '/frontend' + openspace.setPropertyValueSingle("Modules.WebGui.Directories", directories) + openspace.setPropertyValueSingle("Modules.WebGui.DefaultEndpoint", "frontend") - -- Do not serve the files if we are in webgui development mode. - -- In that case, you have to serve the webgui manually, using `npm start`. - if not guiCustomization.webguiDevelopmentMode then + if guiCustomization.webguiDevelopmentMode then + -- Route CEF to the deveopment version of the GUI. + -- This must be manually served using `npm start` + -- in the OpenSpace-WebGuiFrontend repository. openspace.setPropertyValueSingle( - "Modules.WebGui.ServerProcessEntryPoint", backend .. "/backend/backend.js" + "Modules.CefWebGui.GuiUrl", + "http://127.0.0.1:4690/frontend/#/onscreen" ) - openspace.setPropertyValueSingle( - "Modules.WebGui.WebDirectory", frontend .. "/frontend" - ) - openspace.setPropertyValueSingle("Modules.WebGui.ServerProcessEnabled", true) end -- The GUI contains date and simulation increment, @@ -54,5 +46,17 @@ asset.onInitialize(function () end) asset.onDeinitialize(function () - openspace.setPropertyValueSingle("Modules.WebGui.ServerProcessEnabled", false) + -- Remove the frontend endpoint + local directories = openspace.getPropertyValue("Modules.WebGui.Directories") + local newDirectories; + + openspace.setPropertyValueSingle("Modules.WebGui.DefaultEndpoint", "") + + for i = 0, #directories, 2 do + if (string.find(directories[i], "frontend") == nil) then + newDirectories[#newDirectories + 1] = directories[i] + newDirectories[#newDirectories + 1] = directories[i + 1] + end + end + openspace.setPropertyValueSingle("Modules.WebGui.Directories", newDirectories) end) diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index ecdbfc46b1..4a69090acf 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -166,7 +165,15 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } else { WebGuiModule* webGuiModule = global::moduleEngine.module(); _url = "http://127.0.0.1:" + - std::to_string(webGuiModule->port()) + "/#/onscreen"; + std::to_string(webGuiModule->port()) + "/frontend/#/onscreen"; + + _endpointCallback = webGuiModule->addEndpointChangeCallback( + [this](const std::string& endpoint, bool exists) { + if (exists && endpoint == "frontend" && _instance) { + _instance->reloadBrowser(); + } + } + ); } if (configuration.hasValue(GuiScaleInfo.identifier)) { @@ -204,6 +211,11 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) }); global::callback::deinitializeGL.emplace_back([this]() { + if (_endpointCallback != -1) { + WebGuiModule* webGuiModule = global::moduleEngine.module(); + webGuiModule->removeEndpointChangeCallback(_endpointCallback); + _endpointCallback = -1; + } _enabled = false; startOrStopGui(); }); diff --git a/modules/cefwebgui/cefwebguimodule.h b/modules/cefwebgui/cefwebguimodule.h index 81bf8231f4..d822b838a5 100644 --- a/modules/cefwebgui/cefwebguimodule.h +++ b/modules/cefwebgui/cefwebguimodule.h @@ -27,6 +27,8 @@ #include +#include + #include #include #include @@ -53,6 +55,8 @@ private: properties::StringProperty _url; properties::FloatProperty _guiScale; std::unique_ptr _instance; + + WebGuiModule::CallbackHandle _endpointCallback = -1; }; } // namespace openspace diff --git a/modules/server/src/topics/setpropertytopic.cpp b/modules/server/src/topics/setpropertytopic.cpp index 584f8c2fe8..2e40e4d99d 100644 --- a/modules/server/src/topics/setpropertytopic.cpp +++ b/modules/server/src/topics/setpropertytopic.cpp @@ -41,15 +41,29 @@ namespace { std::string escapedLuaString(const std::string& str) { std::string luaString; + for (const char& c : str) { switch (c) { - case '\'': - luaString += "\'"; - break; - default: - luaString += c; + case '\t': + luaString += "\\t"; // Replace tab with \t. + break; + case '"': + luaString += "\\\""; // Replace " with \". + break; + case '\\': + luaString += "\\\\"; // Replace \ with \\. + break; + case '\n': + luaString += "\\\\n"; // Replace newline with \n. + break; + case '\r': + luaString += "\\r"; // Replace carriage return with \r. + break; + default: + luaString += c; } } + return luaString; } diff --git a/modules/webgui/webguimodule.cpp b/modules/webgui/webguimodule.cpp index 47f9ea7672..706c50a703 100644 --- a/modules/webgui/webguimodule.cpp +++ b/modules/webgui/webguimodule.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -67,11 +68,34 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo - WebDirectoryInfo = + DirectoriesInfo = { - "WebDirectory", - "Web Directory", - "Directory from which to to serve static content", + "Directories", + "Directories", + "Directories from which to to serve static content, as a string list " + "with entries expressed as pairs, where every odd is the endpoint name and every " + "even is the directory.", + }; + + constexpr openspace::properties::Property::PropertyInfo + DefaultEndpointInfo = + { + "DefaultEndpoint", + "Default Endpoint", + "The 'default' endpoint. " + "The server will redirect http requests from / to /", + }; + + + constexpr openspace::properties::Property::PropertyInfo + ServedDirectoriesInfo = + { + "ServedDirectories", + "ServedDirectories", + "Directories that are currently served. This value is set by the server process, " + "as a verification of the actually served directories. For example, an onChange " + "callback can be registered to this, to reload browsers when the server is ready." + "Manual changes to this property have no effect." }; constexpr const char* DefaultAddress = "localhost"; @@ -82,16 +106,20 @@ namespace openspace { WebGuiModule::WebGuiModule() : OpenSpaceModule(WebGuiModule::Name) - , _enabled(ServerProcessEnabledInfo, false) + , _enabled(ServerProcessEnabledInfo, true) , _entryPoint(ServerProcessEntryPointInfo) - , _webDirectory(WebDirectoryInfo) + , _directories(DirectoriesInfo) + , _servedDirectories(ServedDirectoriesInfo) + , _defaultEndpoint(DefaultEndpointInfo) , _port(PortInfo, DefaultPort) , _address(AddressInfo, DefaultAddress) , _webSocketInterface(WebSocketInterfaceInfo, "") { addProperty(_enabled); addProperty(_entryPoint); - addProperty(_webDirectory); + addProperty(_directories); + addProperty(_servedDirectories); + addProperty(_defaultEndpoint); addProperty(_address); addProperty(_port); } @@ -104,6 +132,30 @@ std::string WebGuiModule::address() const { return _address; } +WebGuiModule::CallbackHandle WebGuiModule::addEndpointChangeCallback(EndpointCallback cb) +{ + CallbackHandle handle = _nextCallbackHandle++; + _endpointChangeCallbacks.push_back({ handle, std::move(cb) }); + return handle; +} + +void WebGuiModule::removeEndpointChangeCallback(CallbackHandle handle) { + const auto it = std::find_if( + _endpointChangeCallbacks.begin(), + _endpointChangeCallbacks.end(), + [handle](const std::pair& cb) { + return cb.first == handle; + } + ); + + ghoul_assert( + it != _deltaTimeChangeCallbacks.end(), + "handle must be a valid callback handle" + ); + + _endpointChangeCallbacks.erase(it); +} + void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { if (configuration.hasValue(PortInfo.identifier)) { _port = configuration.value(PortInfo.identifier); @@ -119,7 +171,7 @@ void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { } auto startOrStop = [this]() { - if (_enabled) { + if (_enabled && !_entryPoint.value().empty()) { startProcess(); } else { stopProcess(); @@ -135,12 +187,46 @@ void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { _enabled.onChange(startOrStop); _entryPoint.onChange(restartIfEnabled); - _webDirectory.onChange(restartIfEnabled); + _directories.onChange(restartIfEnabled); + _defaultEndpoint.onChange(restartIfEnabled); + _servedDirectories.onChange([this]() { + std::unordered_map newEndpoints; + std::vector list = _servedDirectories.value(); + for (int i = 0; i < list.size() - 1; i += 2) { + newEndpoints[list[i]] = newEndpoints[list[i + 1]]; + } + for (const std::pair& e : _endpoints) { + if (newEndpoints.find(e.first) == newEndpoints.end()) { + // This endpoint existed before but does not exist anymore. + notifyEndpointListeners(e.first, false); + } + } + for (const std::pair& e : newEndpoints) { + if (_endpoints.find(e.first) == _endpoints.end() || + newEndpoints[e.first] != e.second) + { + // This endpoint exists now but did not exist before, + // or the directory has changed. + notifyEndpointListeners(e.first, true); + } + } + _endpoints = newEndpoints; + }); _port.onChange(restartIfEnabled); startOrStop(); } +void WebGuiModule::notifyEndpointListeners(const std::string& endpoint, bool exists) { + using K = CallbackHandle; + using V = EndpointCallback; + for (const std::pair& it : _endpointChangeCallbacks) { + it.second(endpoint, exists); + } +} + void WebGuiModule::startProcess() { + _endpoints.clear(); + ServerModule* serverModule = global::moduleEngine.module(); const ServerInterface* serverInterface = serverModule->serverInterfaceByIdentifier(_webSocketInterface); @@ -157,25 +243,55 @@ void WebGuiModule::startProcess() { const std::string nodePath = absPath("${MODULE_WEBGUI}/ext/nodejs/node"); #endif + std::string formattedDirectories = "["; + + std::vector directories = _directories.value(); + bool first = true; + + for (const std::string& str : directories) { + if (!first) { + formattedDirectories += ","; + } + first = false; + + // Escape twice: First json, and then bash (which needs same escape sequences) + formattedDirectories += "\\\"" + escapedJson(escapedJson(str)) + "\\\""; + } + formattedDirectories += "]"; + + const std::string defaultEndpoint = _defaultEndpoint.value().empty() ? + "" : + " --redirect \"" + _defaultEndpoint.value() + "\""; + const std::string command = "\"" + nodePath + "\" " + "\"" + absPath(_entryPoint.value()) + "\"" + - " --directory \"" + absPath(_webDirectory.value()) + "\"" + + " --directories \"" + formattedDirectories + "\"" + + defaultEndpoint + " --http-port \"" + std::to_string(_port.value()) + "\" " + " --ws-address \"" + _address.value() + "\"" + - " --ws-port \"" + std::to_string(webSocketPort) + "\"" + + " --ws-port " + std::to_string(webSocketPort) + " --auto-close --local"; _process = std::make_unique( command, - _webDirectory.value(), + absPath("${BIN}"), [](const char* data, size_t n) { const std::string str(data, n); LDEBUG(fmt::format("Web GUI server output: {}", str)); + }, + [](const char* data, size_t n) { + const std::string str(data, n); + LERROR(fmt::format("Web GUI server error: {}", str)); } ); } void WebGuiModule::stopProcess() { + for (const auto& e : _endpoints) { + notifyEndpointListeners(e.first, false); + } + _endpoints.clear(); + if (_process) { _process->kill(); } diff --git a/modules/webgui/webguimodule.h b/modules/webgui/webguimodule.h index 1f721b0193..7419d1b44e 100644 --- a/modules/webgui/webguimodule.h +++ b/modules/webgui/webguimodule.h @@ -28,19 +28,27 @@ #include #include +#include #include #include #include #include +#include +#include namespace openspace { class WebGuiModule : public OpenSpaceModule { public: + using CallbackHandle = int; + using EndpointCallback = std::function; + static constexpr const char* Name = "WebGui"; WebGuiModule(); int port() const; std::string address() const; + CallbackHandle addEndpointChangeCallback(EndpointCallback cb); + void removeEndpointChangeCallback(CallbackHandle); protected: void internalInitialize(const ghoul::Dictionary&) override; @@ -48,15 +56,23 @@ protected: private: void startProcess(); void stopProcess(); + void notifyEndpointListeners(const std::string& endpoint, bool exists); std::unique_ptr _process; properties::BoolProperty _enabled; properties::StringProperty _entryPoint; - properties::StringProperty _webDirectory; + properties::StringListProperty _directories; + properties::StringListProperty _servedDirectories; + properties::StringProperty _defaultEndpoint; + + std::unordered_map _endpoints; properties::IntProperty _port; properties::StringProperty _address; properties::StringProperty _webSocketInterface; + + std::vector> _endpointChangeCallbacks; + int _nextCallbackHandle = 0; }; } // namespace openspace From 14d9bbe58be8c8cba64e29e1fe5dcbfc2b7df91e Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 19 Jul 2019 16:51:52 +0200 Subject: [PATCH 20/32] Fix crash related to deinitialization of screenspacebrowser --- .../webbrowser/include/screenspacebrowser.h | 6 +++-- modules/webbrowser/src/screenspacebrowser.cpp | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index fbfc5073d3..be83f58c71 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -63,9 +63,11 @@ class WebKeyboardHandler; class ScreenSpaceBrowser : public ScreenSpaceRenderable { public: ScreenSpaceBrowser(const ghoul::Dictionary& dictionary); + virtual ~ScreenSpaceBrowser() = default; + + bool initializeGL() override; + bool deinitializeGL() override; - bool initialize() override; - bool deinitialize() override; void render() override; void update() override; bool isReady() const override; diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 965a693965..1c69bb0b4c 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -87,10 +87,6 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) glm::vec2 windowDimensions = global::windowDelegate.currentSubwindowSize(); _dimensions = windowDimensions; - _texture = std::make_unique( - glm::uvec3(windowDimensions, 1.0f) - ); - _renderHandler = new ScreenSpaceRenderHandler(); _keyboardHandler = new WebKeyboardHandler(); _browserInstance = std::make_unique( @@ -112,7 +108,11 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) } } -bool ScreenSpaceBrowser::initialize() { +bool ScreenSpaceBrowser::initializeGL() { + _texture = std::make_unique( + glm::uvec3(_dimensions.value(), 1.0f) + ); + _renderHandler->setTexture(*_texture); createShaders(); @@ -122,7 +122,10 @@ bool ScreenSpaceBrowser::initialize() { return isReady(); } -bool ScreenSpaceBrowser::deinitialize() { +bool ScreenSpaceBrowser::deinitializeGL() { + _renderHandler->setTexture(0); + _texture = nullptr; + std::string urlString; _url.getStringValue(urlString); LDEBUG(fmt::format("Deinitializing ScreenSpaceBrowser: {}", urlString)); @@ -133,11 +136,12 @@ bool ScreenSpaceBrowser::deinitialize() { if (webBrowser) { webBrowser->removeBrowser(_browserInstance.get()); _browserInstance.reset(); - return true; + } + else { + LWARNING("Could not find WebBrowserModule"); } - LWARNING("Could not find WebBrowserModule"); - return false; + return ScreenSpaceRenderable::deinitializeGL(); } void ScreenSpaceBrowser::render() { From ce15381fb29f3c8e72cc86e1e69f906e9cfd865d Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 19 Jul 2019 22:16:13 +0200 Subject: [PATCH 21/32] Fix browser mask bug introduced when flipping y axis --- modules/webbrowser/src/webrenderhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/webbrowser/src/webrenderhandler.cpp b/modules/webbrowser/src/webrenderhandler.cpp index 364855bd2e..204dea11c5 100644 --- a/modules/webbrowser/src/webrenderhandler.cpp +++ b/modules/webbrowser/src/webrenderhandler.cpp @@ -151,7 +151,7 @@ bool WebRenderHandler::hasContent(int x, int y) { if (_browserBuffer.empty()) { return false; } - int index = x + (_browserBufferSize.x * y); + int index = x + _browserBufferSize.x * (_browserBufferSize.y - y - 1); index = glm::clamp(index, 0, static_cast(_browserBuffer.size() - 1)); return _browserBuffer[index].a; } From 8f112fa219e7d9e77a959a5dacd4aced640413da Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 22 Jul 2019 14:14:12 +0200 Subject: [PATCH 22/32] Compile and runtime fixes when running in Debug Do not crash if ScreenSpaceLocalImage does not exist Add ability to specify identifier/name when adding screenspace items in the UI --- .../base/rendering/screenspaceimagelocal.cpp | 29 ++++++- modules/imgui/src/gui.cpp | 76 +++++++++++++++---- modules/webgui/webguimodule.cpp | 2 +- src/engine/openspaceengine.cpp | 1 - 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/modules/base/rendering/screenspaceimagelocal.cpp b/modules/base/rendering/screenspaceimagelocal.cpp index a0751cf9f0..392a8952d0 100644 --- a/modules/base/rendering/screenspaceimagelocal.cpp +++ b/modules/base/rendering/screenspaceimagelocal.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -96,11 +97,30 @@ ScreenSpaceImageLocal::ScreenSpaceImageLocal(const ghoul::Dictionary& dictionary setGuiName("ScreenSpaceImageLocal " + std::to_string(iIdentifier)); } - _texturePath.onChange([this]() { _textureIsDirty = true; }); + _texturePath.onChange([this]() { + if (!FileSys.fileExists(FileSys.absolutePath(_texturePath))) { + LWARNINGC( + "ScreenSpaceImageLocal", + fmt::format("Image {} did not exist for {}", _texturePath, _identifier) + ); + } + else { + _textureIsDirty = true; + } + }); addProperty(_texturePath); if (dictionary.hasKey(TexturePathInfo.identifier)) { - _texturePath = dictionary.value(TexturePathInfo.identifier); + std::string path = dictionary.value(TexturePathInfo.identifier); + if (!FileSys.fileExists(FileSys.absolutePath(path))) { + LWARNINGC( + "ScreenSpaceImageLocal", + fmt::format("Image {} did not exist for {}", path, _identifier) + ); + } + else { + _texturePath = path; + } } } @@ -130,12 +150,13 @@ void ScreenSpaceImageLocal::update() { _objectSize = _texture->dimensions(); _textureIsDirty = false; } - } } void ScreenSpaceImageLocal::bindTexture() { - _texture->bind(); + if (_texture) { + _texture->bind(); + } } } // namespace openspace diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index 51088e6abf..0767a812a4 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -53,32 +53,69 @@ namespace { constexpr const std::array UniformNames = { "tex", "ortho" }; - void addScreenSpaceRenderableLocal(std::string texturePath) { + void addScreenSpaceRenderableLocal(std::string identifier, std::string texturePath) { if (!FileSys.fileExists(absPath(texturePath))) { LWARNING(fmt::format("Could not find image '{}'", texturePath)); return; } - openspace::global::scriptEngine.queueScript( - fmt::format( + std::string script; + if (identifier.empty()) { + script = fmt::format( "openspace.addScreenSpaceRenderable({{\ Type = 'ScreenSpaceImageLocal',\ TexturePath = openspace.absPath('{}')\ }});", - std::move(texturePath) - ), + texturePath + ); + } + else { + script = fmt::format( + "openspace.addScreenSpaceRenderable({{\ + Type = 'ScreenSpaceImageLocal',\ + TexturePath = openspace.absPath('{}'),\ + Identifier = '{}',\ + Name = '{}'\ + }});", + texturePath, + identifier, + identifier + ); + } + + openspace::global::scriptEngine.queueScript( + script, openspace::scripting::ScriptEngine::RemoteScripting::Yes ); } - void addScreenSpaceRenderableOnline(std::string texturePath) { - openspace::global::scriptEngine.queueScript( - fmt::format( + void addScreenSpaceRenderableOnline(std::string identifier, std::string texturePath) { + std::string script; + if (identifier.empty()) { + script = fmt::format( "openspace.addScreenSpaceRenderable({{\ - Type = 'ScreenSpaceImageOnline', URL = '{}'\ + Type = 'ScreenSpaceImageOnline',\ + URL = '{}'\ }});", - std::move(texturePath) - ), + texturePath + ); + } + else { + script = fmt::format( + "openspace.addScreenSpaceRenderable({{\ + Type = 'ScreenSpaceImageOnline',\ + URL = '{}',\ + Identifier = '{}',\ + Name = '{}'\ + }});", + texturePath, + identifier, + identifier + ); + } + + openspace::global::scriptEngine.queueScript( + script, openspace::scripting::ScriptEngine::RemoteScripting::Yes ); } @@ -616,9 +653,16 @@ void GUI::render() { renderAndUpdatePropertyVisibility(); static const int addImageBufferSize = 256; + static char identifierBuffer[addImageBufferSize]; static char addImageLocalBuffer[addImageBufferSize]; static char addImageOnlineBuffer[addImageBufferSize]; + ImGui::InputText( + "Identifier for Local/Online Images", + identifierBuffer, + addImageBufferSize + ); + bool addImageLocal = ImGui::InputText( "Add Local Image", addImageLocalBuffer, @@ -626,7 +670,10 @@ void GUI::render() { ImGuiInputTextFlags_EnterReturnsTrue ); if (addImageLocal) { - addScreenSpaceRenderableLocal(std::string(addImageLocalBuffer)); + addScreenSpaceRenderableLocal( + std::string(identifierBuffer), + std::string(addImageLocalBuffer) + ); } bool addImageOnline = ImGui::InputText( @@ -637,7 +684,10 @@ void GUI::render() { ); if (addImageOnline) { - addScreenSpaceRenderableOnline(std::string(addImageOnlineBuffer)); + addScreenSpaceRenderableOnline( + std::string(identifierBuffer), + std::string(addImageOnlineBuffer) + ); } bool addDashboard = ImGui::Button("Add New Dashboard"); diff --git a/modules/webgui/webguimodule.cpp b/modules/webgui/webguimodule.cpp index 706c50a703..41a7f4c49f 100644 --- a/modules/webgui/webguimodule.cpp +++ b/modules/webgui/webguimodule.cpp @@ -149,7 +149,7 @@ void WebGuiModule::removeEndpointChangeCallback(CallbackHandle handle) { ); ghoul_assert( - it != _deltaTimeChangeCallbacks.end(), + it != _endpointChangeCallbacks.end(), "handle must be a valid callback handle" ); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index b1473854a8..4bebd18ff7 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -811,7 +811,6 @@ void OpenSpaceEngine::deinitialize() { ghoul::logging::LogManager::deinitialize(); - ghoul::deinitialize(); LTRACE("deinitialize(end)"); From c45e5de33a2e189f395bea9bca21a25dd8fc65a4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 22 Jul 2019 14:19:11 +0200 Subject: [PATCH 23/32] Update copyright header Update Ghoul --- ext/ghoul | 2 +- src/openspace.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index f30b8c1a04..526b27cb65 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit f30b8c1a04bd7dcbbe4e4b6bdc48e96a28d6c18c +Subproject commit 526b27cb653fe9befc324278debc701297694207 diff --git a/src/openspace.cpp b/src/openspace.cpp index 439608d025..343b49c480 100644 --- a/src/openspace.cpp +++ b/src/openspace.cpp @@ -29,7 +29,7 @@ namespace openspace { std::string licenseText() { return "OpenSpace\n\ \n\ -Copyright (c) 2014-2018\n\ +Copyright (c) 2014-2019\n\ \n\ Permission is hereby granted, free of charge, to any person obtaining a copy of this\n\ software and associated documentation files (the \"Software\"), to deal in the Software\n\ From f7fafa5255a17c01e2ec1a3327b1fc720e3daf7f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 29 Jul 2019 13:13:16 +0200 Subject: [PATCH 24/32] Add scripts to manipulate the camera Add example asset using the new scripts for an IPAC --- data/assets/util/ipac.asset | 18 +++ .../openspace/interaction/orbitalnavigator.h | 5 + .../interaction/scriptcamerastates.h | 54 ++++++++ src/CMakeLists.txt | 2 + src/interaction/navigationhandler.cpp | 35 ++++++ src/interaction/navigationhandler_lua.inl | 71 +++++++++++ src/interaction/orbitalnavigator.cpp | 43 +++++-- src/interaction/scriptcamerastates.cpp | 118 ++++++++++++++++++ 8 files changed, 337 insertions(+), 9 deletions(-) create mode 100644 data/assets/util/ipac.asset create mode 100644 include/openspace/interaction/scriptcamerastates.h create mode 100644 src/interaction/scriptcamerastates.cpp diff --git a/data/assets/util/ipac.asset b/data/assets/util/ipac.asset new file mode 100644 index 0000000000..5d9140d4eb --- /dev/null +++ b/data/assets/util/ipac.asset @@ -0,0 +1,18 @@ +asset.onInitialize(function() + openspace.clearKeys() + openspace.bindKey("RIGHT", "openspace.navigation.addGlobalRotation(-5.0, 0.0)"); + openspace.bindKey("LEFT", "openspace.navigation.addGlobalRotation(5.0, 0.0)"); + openspace.bindKey("UP", "openspace.navigation.addGlobalRotation(0.0, 5.0)"); + openspace.bindKey("DOWN", "openspace.navigation.addGlobalRotation(0.0, -5.0)"); + + openspace.bindKey("CTRL+RIGHT", "openspace.navigation.addLocalRotation(-5.0, 0.0)"); + openspace.bindKey("CTRL+LEFT", "openspace.navigation.addLocalRotation(5.0, 0.0)"); + openspace.bindKey("CTRL+UP", "openspace.navigation.addLocalRotation(0.0, 5.0)"); + openspace.bindKey("CTRL+DOWN", "openspace.navigation.addLocalRotation(0.0, -5.0)"); + + openspace.bindKey("ALT+UP", "openspace.navigation.addTruckMovement(0.0, 5.0)"); + openspace.bindKey("ALT+DOWN", "openspace.navigation.addTruckMovement(0.0, -5.0)"); + + openspace.bindKey("SPACE", "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Moon');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);") + openspace.bindKey("Z", "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);") +end) diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h index 0eff98c64c..6478126dda 100644 --- a/include/openspace/interaction/orbitalnavigator.h +++ b/include/openspace/interaction/orbitalnavigator.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,9 @@ public: JoystickCameraStates& joystickStates(); const JoystickCameraStates& joystickStates() const; + ScriptCameraStates& scriptStates(); + const ScriptCameraStates& scriptStates() const; + bool followingNodeRotation() const; const SceneGraphNode* anchorNode() const; const SceneGraphNode* aimNode() const; @@ -146,6 +150,7 @@ private: MouseCameraStates _mouseStates; JoystickCameraStates _joystickStates; + ScriptCameraStates _scriptStates; const SceneGraphNode* _anchorNode = nullptr; const SceneGraphNode* _aimNode = nullptr; diff --git a/include/openspace/interaction/scriptcamerastates.h b/include/openspace/interaction/scriptcamerastates.h new file mode 100644 index 0000000000..2153dee497 --- /dev/null +++ b/include/openspace/interaction/scriptcamerastates.h @@ -0,0 +1,54 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___SCRIPTCAMERASTATES___H__ +#define __OPENSPACE_CORE___SCRIPTCAMERASTATES___H__ + +#include + +namespace openspace::interaction { + +class ScriptCameraStates : public CameraInteractionStates { +public: + ScriptCameraStates(); + + void updateStateFromInput(const InputState& inputState, double deltaTime) override; + + void addLocalRotation(const glm::dvec2& delta); + void addGlobalRotation(const glm::dvec2& delta); + void addTruckMovement(const glm::dvec2& delta); + void addLocalRoll(const glm::dvec2& delta); + void addGlobalRoll(const glm::dvec2& delta); + +private: + glm::dvec2 _localRotation; + glm::dvec2 _globalRotation; + glm::dvec2 _truckMovement; + glm::dvec2 _localRoll; + glm::dvec2 _globalRoll; +}; + +} // namespace openspace::interaction + +#endif // __OPENSPACE_CORE___SCRIPTCAMERASTATES___H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 223d5e4e8d..0fd7b64f35 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl ${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp ${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/scriptcamerastates.cpp ${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp ${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording.cpp ${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording_lua.inl @@ -236,6 +237,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/externinteraction.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/scriptcamerastates.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.inl ${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp index f4f0c21dc9..ee711393f7 100644 --- a/src/interaction/navigationhandler.cpp +++ b/src/interaction/navigationhandler.cpp @@ -635,6 +635,41 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() { "int", "Returns the script that is currently bound to be executed when the " "provided button is pressed" + }, + { + "addGlobalRotation", + &luascriptfunctions::addGlobalRotation, + {}, + "double, double", + "Directly adds to the global rotation of the camera" + }, + { + "addLocalRotation", + &luascriptfunctions::addLocalRotation, + {}, + "double, double", + "Directly adds to the local rotation of the camera" + }, + { + "addTruckMovement", + &luascriptfunctions::addTruckMovement, + {}, + "double, double", + "Directly adds to the truck movement of the camera" + }, + { + "addLocalRoll", + &luascriptfunctions::addLocalRoll, + {}, + "double, double", + "Directly adds to the local roll of the camera" + }, + { + "addGlobalRoll", + &luascriptfunctions::addGlobalRoll, + {}, + "double, double", + "Directly adds to the global roll of the camera" } } }; diff --git a/src/interaction/navigationhandler_lua.inl b/src/interaction/navigationhandler_lua.inl index 899859c36e..dcbb407878 100644 --- a/src/interaction/navigationhandler_lua.inl +++ b/src/interaction/navigationhandler_lua.inl @@ -23,6 +23,7 @@ ****************************************************************************************/ #include +#include namespace openspace::luascriptfunctions { @@ -250,4 +251,74 @@ int joystickButton(lua_State* L) { return 1; } +int addGlobalRotation(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRotation"); + + const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); + const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + + global::navigationHandler.orbitalNavigator().scriptStates().addGlobalRotation( + glm::dvec2(v1, v2) + ); + + lua_settop(L, 0); + return 0; +} + +int addLocalRotation(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRotation"); + + const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); + const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + + global::navigationHandler.orbitalNavigator().scriptStates().addLocalRotation( + glm::dvec2(v1, v2) + ); + + lua_settop(L, 0); + return 0; +} + +int addTruckMovement(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTruckMovement"); + + const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); + const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + + global::navigationHandler.orbitalNavigator().scriptStates().addTruckMovement( + glm::dvec2(v1, v2) + ); + + lua_settop(L, 0); + return 0; +} + +int addLocalRoll(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRoll"); + + const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); + const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + + global::navigationHandler.orbitalNavigator().scriptStates().addLocalRoll( + glm::dvec2(v1, v2) + ); + + lua_settop(L, 0); + return 0; +} + +int addGlobalRoll(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRoll"); + + const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); + const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + + global::navigationHandler.orbitalNavigator().scriptStates().addGlobalRoll( + glm::dvec2(v1, v2) + ); + + lua_settop(L, 0); + return 0; +} + } // namespace openspace::luascriptfunctions diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index 2ec2474bf9..8077f7e8e9 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -348,6 +348,7 @@ glm::quat OrbitalNavigator::anchorNodeToCameraRotation() const { void OrbitalNavigator::resetVelocities() { _mouseStates.resetVelocities(); _joystickStates.resetVelocities(); + _scriptStates.resetVelocities(); } void OrbitalNavigator::updateStatesFromInput(const InputState& inputState, @@ -355,6 +356,7 @@ void OrbitalNavigator::updateStatesFromInput(const InputState& inputState, { _mouseStates.updateStateFromInput(inputState, deltaTime); _joystickStates.updateStateFromInput(inputState, deltaTime); + _scriptStates.updateStateFromInput(inputState, deltaTime); } void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { @@ -871,7 +873,8 @@ glm::dquat OrbitalNavigator::roll(double deltaTime, { const glm::dquat mouseRollQuat = glm::angleAxis( _mouseStates.localRollVelocity().x * deltaTime + - _joystickStates.localRollVelocity().x * deltaTime, + _joystickStates.localRollVelocity().x * deltaTime + + _scriptStates.localRollVelocity().x * deltaTime, glm::dvec3(0.0, 0.0, 1.0) ); return localCameraRotation * mouseRollQuat; @@ -892,8 +895,15 @@ glm::dquat OrbitalNavigator::rotateLocally(double deltaTime, 0.0 ) * deltaTime); + const glm::dquat scriptRotationDiff = glm::dquat(glm::dvec3( + _scriptStates.localRotationVelocity().y, + _scriptStates.localRotationVelocity().x, + 0.0 + ) * deltaTime); - return localCameraRotation * joystickRotationDiff * mouseRotationDiff; + + return localCameraRotation * joystickRotationDiff * mouseRotationDiff * + scriptRotationDiff; } glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime, const glm::dquat& localCameraRotation) @@ -1061,19 +1071,24 @@ glm::dvec3 OrbitalNavigator::translateHorizontally(double deltaTime, const glm::dquat mouseRotationDiffCamSpace = glm::dquat(glm::dvec3( -_mouseStates.globalRotationVelocity().y * deltaTime, -_mouseStates.globalRotationVelocity().x * deltaTime, - 0) * speedScale); + 0.0) * speedScale); const glm::dquat joystickRotationDiffCamSpace = glm::dquat(glm::dvec3( -_joystickStates.globalRotationVelocity().y * deltaTime, -_joystickStates.globalRotationVelocity().x * deltaTime, - 0) * speedScale + 0.0) * speedScale + ); + + const glm::dquat scriptRotationDiffCamSpace = glm::dquat(glm::dvec3( + -_scriptStates.globalRotationVelocity().y * deltaTime, + -_scriptStates.globalRotationVelocity().x * deltaTime, + 0.0) * speedScale ); // Transform to world space const glm::dquat rotationDiffWorldSpace = globalCameraRotation * - joystickRotationDiffCamSpace * - mouseRotationDiffCamSpace * - glm::inverse(globalCameraRotation); + joystickRotationDiffCamSpace * scriptRotationDiffCamSpace * + mouseRotationDiffCamSpace * glm::inverse(globalCameraRotation); // Rotate and find the difference vector const glm::dvec3 rotationDiffVec3 = @@ -1134,7 +1149,8 @@ glm::dvec3 OrbitalNavigator::translateVertically(double deltaTime, const glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface; const double totalVelocity = _joystickStates.truckMovementVelocity().y + - _mouseStates.truckMovementVelocity().y; + _mouseStates.truckMovementVelocity().y + + _scriptStates.truckMovementVelocity().y; return cameraPosition - actualSurfaceToCamera * totalVelocity * deltaTime; } @@ -1153,7 +1169,8 @@ glm::dquat OrbitalNavigator::rotateHorizontally(double deltaTime, const glm::dquat mouseCameraRollRotation = glm::angleAxis( _mouseStates.globalRollVelocity().x * deltaTime + - _joystickStates.globalRollVelocity().x * deltaTime, + _joystickStates.globalRollVelocity().x * deltaTime + + _scriptStates.globalRollVelocity().x * deltaTime, directionFromSurfaceToCamera ); return mouseCameraRollRotation * globalCameraRotation; @@ -1239,4 +1256,12 @@ const JoystickCameraStates& OrbitalNavigator::joystickStates() const { return _joystickStates; } +ScriptCameraStates& OrbitalNavigator::scriptStates() { + return _scriptStates; +} + +const ScriptCameraStates& OrbitalNavigator::scriptStates() const { + return _scriptStates; +} + } // namespace openspace::interaction diff --git a/src/interaction/scriptcamerastates.cpp b/src/interaction/scriptcamerastates.cpp new file mode 100644 index 0000000000..ef018796d1 --- /dev/null +++ b/src/interaction/scriptcamerastates.cpp @@ -0,0 +1,118 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace { + const double SENSITIVITY_ADJUSTMENT_INCREASE = 8.0; + const double SENSITIVITY_ADJUSTMENT_DECREASE = 0.5; +} + +namespace openspace::interaction { + +ScriptCameraStates::ScriptCameraStates() : CameraInteractionStates(1.0, 1.0) {} + +void ScriptCameraStates::updateStateFromInput(const InputState& inputState, + double deltaTime) +{ + if (_localRotation != glm::dvec2(0.0)) { + _localRotationState.velocity.set( + _localRotation * _sensitivity, + deltaTime + ); + _localRotation = glm::dvec2(0.0); + } + else { + _localRotationState.velocity.decelerate(deltaTime); + } + + if (_globalRotation != glm::dvec2(0.0)) { + _globalRotationState.velocity.set( + _globalRotation * _sensitivity, + deltaTime + ); + _globalRotation = glm::dvec2(0.0); + } + else { + _globalRotationState.velocity.decelerate(deltaTime); + } + + if (_truckMovement != glm::dvec2(0.0)) { + _truckMovementState.velocity.set( + _truckMovement * _sensitivity, + deltaTime + ); + _truckMovement = glm::dvec2(0.0); + } + else { + _truckMovementState.velocity.decelerate(deltaTime); + } + + if (_localRoll != glm::dvec2(0.0)) { + _localRollState.velocity.set( + _localRoll * _sensitivity, + deltaTime + ); + _localRoll = glm::dvec2(0.0); + } + else { + _localRollState.velocity.decelerate(deltaTime); + } + + if (_globalRoll != glm::dvec2(0.0)) { + _globalRollState.velocity.set( + _globalRoll * _sensitivity, + deltaTime + ); + _globalRoll = glm::dvec2(0.0); + } + else { + _globalRollState.velocity.decelerate(deltaTime); + } +} + +void ScriptCameraStates::addLocalRotation(const glm::dvec2& delta) { + _localRotation += delta; +} + +void ScriptCameraStates::addGlobalRotation(const glm::dvec2& delta) { + _globalRotation += delta; +} + +void ScriptCameraStates::addTruckMovement(const glm::dvec2& delta) { + _truckMovement += delta; +} + +void ScriptCameraStates::addLocalRoll(const glm::dvec2& delta) { + _localRoll += delta; +} + +void ScriptCameraStates::addGlobalRoll(const glm::dvec2& delta) { + _globalRoll += delta; +} + + +} // namespace openspace::interaction From 4a070c939fdfdeaafc864ffd437228e838919261 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Jul 2019 14:28:23 +0200 Subject: [PATCH 25/32] Add the ability to query and rearrange globebrowsing layers at runtime --- include/openspace/properties/propertyowner.h | 1 - modules/globebrowsing/globebrowsingmodule.cpp | 21 ++++++ .../globebrowsing/globebrowsingmodule_lua.inl | 72 +++++++++++++++++++ modules/globebrowsing/src/layergroup.cpp | 27 +++++++ modules/globebrowsing/src/layergroup.h | 1 + modules/globebrowsing/src/layermanager.cpp | 4 ++ modules/globebrowsing/src/layermanager.h | 1 + 7 files changed, 126 insertions(+), 1 deletion(-) diff --git a/include/openspace/properties/propertyowner.h b/include/openspace/properties/propertyowner.h index 8844726c53..d7134b9c54 100644 --- a/include/openspace/properties/propertyowner.h +++ b/include/openspace/properties/propertyowner.h @@ -303,7 +303,6 @@ protected: /// The description for this PropertyOwner std::string _description; -private: /// The owner of this PropertyOwner PropertyOwner* _owner = nullptr; /// A list of all registered Property's diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 081fedebdc..c1d976da57 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -385,6 +385,27 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { "any of " + listLayerGroups + ". The third argument is the dictionary" "defining the layer." }, + { + "getLayers", + &globebrowsing::luascriptfunctions::getLayers, + {}, + "string, string", + "Returns the list of layers for the scene graph node specified in the first " + "parameter. The second parameter specifies which layer type should be " + "queried." + }, + { + "moveLayer", + &globebrowsing::luascriptfunctions::moveLayer, + {}, + "string, string, number, number", + "Rearranges the order of a single layer in a scene graph node. The first " + "parameter specifies the scene graph node, the second parameter specifies " + "the name of the layer group, the third parameter is the original position " + "of the layer that should be moved and the last parameter is the new " + "position. The new position may be -1 to place the layer at the top or any " + "large number bigger than the number of layers to place it at the bottom." + }, { "goToChunk", &globebrowsing::luascriptfunctions::goToChunk, diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index 0c6479b211..3c5d4677ff 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -127,6 +128,77 @@ int deleteLayer(lua_State* L) { return 0; } +int getLayers(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::getLayers"); + + const std::string& globeIdentifier = ghoul::lua::value(L, 1); + const std::string& layer = ghoul::lua::value(L, 2); + lua_pop(L, 2); + + SceneGraphNode* n = sceneGraphNode(globeIdentifier); + if (!n) { + return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + } + + const RenderableGlobe* globe = dynamic_cast(n->renderable()); + if (!globe) { + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + } + + globebrowsing::layergroupid::GroupID group = + ghoul::from_string(layer); + if (group == globebrowsing::layergroupid::GroupID::Unknown) { + return ghoul::lua::luaError(L, "Unknown layer groupd: " + layer); + } + + const globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group); + std::vector layers = lg.layers(); + + lua_newtable(L); + int key = 1; + for (globebrowsing::Layer* l : layers) { + ghoul::lua::push(L, key, l->identifier()); + lua_settable(L, -3); + key++; + } + return 1; +} + +int moveLayer(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::moveLayer"); + + const std::string& globeIdentifier = ghoul::lua::value(L, 1); + const std::string& layer = ghoul::lua::value(L, 2); + int oldPosition = ghoul::lua::value(L, 3); + int newPosition = ghoul::lua::value(L, 4); + lua_pop(L, 4); + + if (oldPosition == newPosition) { + return 0; + } + + SceneGraphNode* n = sceneGraphNode(globeIdentifier); + if (!n) { + return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + } + + RenderableGlobe* globe = dynamic_cast(n->renderable()); + if (!globe) { + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + } + + globebrowsing::layergroupid::GroupID group = + ghoul::from_string(layer); + if (group == globebrowsing::layergroupid::GroupID::Unknown) { + return ghoul::lua::luaError(L, "Unknown layer groupd: " + layer); + } + + globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group); + lg.moveLayers(oldPosition, newPosition); + + return 0; +} + int goToChunk(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::goToChunk"); diff --git a/modules/globebrowsing/src/layergroup.cpp b/modules/globebrowsing/src/layergroup.cpp index e0aff6f0af..df012f3a9f 100644 --- a/modules/globebrowsing/src/layergroup.cpp +++ b/modules/globebrowsing/src/layergroup.cpp @@ -155,6 +155,33 @@ void LayerGroup::deleteLayer(const std::string& layerName) { LERROR("Could not find layer " + layerName); } +void LayerGroup::moveLayers(int oldPosition, int newPosition) { + oldPosition = std::max(0, oldPosition); + newPosition = std::min(newPosition, static_cast(_layers.size())); + + // We need to adjust the new position as we first delete the old position, if this + // position is before the new position we have reduced the size of the vector by 1 and + // need to adapt where we want to put the value in + if (oldPosition < newPosition) { + newPosition -= 1; + } + + // There are two synchronous vectors that we have to update here. The _layers vector + // is used to determine the order while rendering, the _subowners is the order in + // which the layers are shown in the UI + auto oldPosLayers = _layers.begin() + oldPosition; + std::unique_ptr v = std::move(*oldPosLayers); + _layers.erase(oldPosLayers); + auto newPosLayers = _layers.begin() + newPosition; + _layers.insert(newPosLayers, std::move(v)); + + auto oldPosOwner = _subOwners.begin() + oldPosition; + PropertyOwner* owner = std::move(*oldPosOwner); + _subOwners.erase(oldPosOwner); + auto newPosOwner = _subOwners.begin() + newPosition; + _subOwners.insert(newPosOwner, std::move(owner)); +} + std::vector LayerGroup::layers() const { std::vector res; res.reserve(_layers.size()); diff --git a/modules/globebrowsing/src/layergroup.h b/modules/globebrowsing/src/layergroup.h index 7db9a718de..f02fd0d80a 100644 --- a/modules/globebrowsing/src/layergroup.h +++ b/modules/globebrowsing/src/layergroup.h @@ -53,6 +53,7 @@ struct LayerGroup : public properties::PropertyOwner { Layer* addLayer(const ghoul::Dictionary& layerDict); void deleteLayer(const std::string& layerName); + void moveLayers(int oldPosition, int newPosition); /// @returns const vector of all layers std::vector layers() const; diff --git a/modules/globebrowsing/src/layermanager.cpp b/modules/globebrowsing/src/layermanager.cpp index ae677ada58..825f465fa7 100644 --- a/modules/globebrowsing/src/layermanager.cpp +++ b/modules/globebrowsing/src/layermanager.cpp @@ -88,6 +88,10 @@ void LayerManager::deleteLayer(layergroupid::GroupID id, const std::string& laye _layerGroups[id]->deleteLayer(layerName); } +LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) { + return *_layerGroups[groupId]; +} + const LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) const { return *_layerGroups[groupId]; } diff --git a/modules/globebrowsing/src/layermanager.h b/modules/globebrowsing/src/layermanager.h index 36de309488..bd504210c1 100644 --- a/modules/globebrowsing/src/layermanager.h +++ b/modules/globebrowsing/src/layermanager.h @@ -57,6 +57,7 @@ public: const ghoul::Dictionary& layerDict); void deleteLayer(layergroupid::GroupID groupId, const std::string& layerName); + LayerGroup& layerGroup(layergroupid::GroupID); const LayerGroup& layerGroup(layergroupid::GroupID) const; bool hasAnyBlendingLayersEnabled() const; From fbeec151db91151ec07c6ad5c4b21e5a25db85a5 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Jul 2019 15:01:34 +0200 Subject: [PATCH 26/32] Set correct interaction sensitivity factor when adjusting joystick sensitivity (closes #815) --- src/interaction/orbitalnavigator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index 8077f7e8e9..573a918039 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -308,7 +308,7 @@ OrbitalNavigator::OrbitalNavigator() _mouseStates.setSensitivity(_mouseSensitivity * pow(10.0, -4)); }); _joystickSensitivity.onChange([&]() { - _joystickStates.setSensitivity(_joystickSensitivity * pow(10.0, -4)); + _joystickStates.setSensitivity(_joystickSensitivity * 0.1); }); addPropertySubOwner(_friction); From 042636757252085d99ec98b351f4b459006a3d64 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Jul 2019 15:22:31 +0200 Subject: [PATCH 27/32] Allow the user to abort the loading screen through ESC (closes #668) --- include/openspace/engine/openspaceengine.h | 1 + src/engine/openspaceengine.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index f0d8523264..fb0ad85061 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -109,6 +109,7 @@ private: std::unique_ptr _scene; std::unique_ptr _assetManager; + bool _shouldAbortLoading = false; std::unique_ptr _loadingScreen; std::unique_ptr _versionChecker; diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 4bebd18ff7..3650eabd58 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -708,6 +708,10 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { bool loading = true; while (loading) { + if (_shouldAbortLoading) { + global::windowDelegate.terminate(); + break; + } _loadingScreen->render(); _assetManager->update(); @@ -750,6 +754,10 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { } } } + if (_shouldAbortLoading) { + _loadingScreen = nullptr; + return; + } _loadingScreen->setPhase(LoadingScreen::Phase::Initialization); @@ -1183,6 +1191,16 @@ void OpenSpaceEngine::postDraw() { } void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction action) { + if (_loadingScreen) { + // If the loading screen object exists, we are currently loading and want key + // presses to behave differently + if (key == Key::Escape) { + _shouldAbortLoading = true; + } + + return; + } + using F = std::function; for (const F& func : global::callback::keyboard) { const bool isConsumed = func(key, mod, action); From 566fe7f43480ec2de6d736555a5226854c800024 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Jul 2019 17:48:43 +0200 Subject: [PATCH 28/32] Adding documentation to RenderableGlobe and layers (closes #651) Fix mars after detecting that identifiers were missing --- .../scene/solarsystem/planets/mars/mars.asset | 2 + .../openspace/documentation/documentation.h | 1 - modules/globebrowsing/globebrowsingmodule.cpp | 13 ++ modules/globebrowsing/globebrowsingmodule.h | 2 + modules/globebrowsing/src/layer.cpp | 114 +++++++++++++++++- modules/globebrowsing/src/layer.h | 4 + modules/globebrowsing/src/layeradjustment.cpp | 38 ++++++ modules/globebrowsing/src/layeradjustment.h | 4 + modules/globebrowsing/src/layergroup.cpp | 9 ++ modules/globebrowsing/src/layermanager.cpp | 18 +++ modules/globebrowsing/src/layermanager.h | 4 + modules/globebrowsing/src/renderableglobe.cpp | 53 ++++++++ modules/globebrowsing/src/renderableglobe.h | 4 + src/documentation/documentation.cpp | 2 - 14 files changed, 264 insertions(+), 4 deletions(-) diff --git a/data/assets/scene/solarsystem/planets/mars/mars.asset b/data/assets/scene/solarsystem/planets/mars/mars.asset index ce0b6a175c..3d2d7e3f10 100644 --- a/data/assets/scene/solarsystem/planets/mars/mars.asset +++ b/data/assets/scene/solarsystem/planets/mars/mars.asset @@ -25,6 +25,7 @@ local color_layers = { FilePath = mapServiceConfigs .. "/Utah/Mars_Color.wms", Enabled = true, Fallback = { + Identifier = "Mars_Texture", Name = "Mars Texture", FilePath = textures .. "/mars.jpg", Enabled = true @@ -35,6 +36,7 @@ local color_layers = { Name = "MOC WA Color [Sweden]", FilePath = mapServiceConfigs .. "/LiU/Color.wms", Fallback = { + Identifier = "Mars_Texture", Name = "Mars Texture", FilePath = textures .. "/mars.jpg", Enabled = true diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 089e19d776..6dc9432799 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -57,7 +57,6 @@ struct TestResult { */ enum class Reason { MissingKey, ///< The offending key that was requested was not found - ExtraKey, ///< The exhaustive documentation contained an extra key WrongType, ///< The key's value was not of the expected type Verification, ///< The value did not pass a necessary non-type verifier UnknownIdentifier ///< The identifier for a ReferencingVerifier did not exist diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index c1d976da57..bbd35e3acf 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -28,7 +28,11 @@ #include #include #include +#include #include +#include +#include +#include #include #include #include @@ -482,6 +486,15 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { return res; } +std::vector GlobeBrowsingModule::documentations() const { + return { + globebrowsing::Layer::Documentation(), + globebrowsing::LayerAdjustment::Documentation(), + globebrowsing::LayerManager::Documentation(), + GlobeLabelsComponent::Documentation() + }; +} + void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe, int x, int y, int level) { diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 89e397d8ab..8f9367a0fd 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -65,6 +65,8 @@ public: globebrowsing::cache::MemoryAwareTileCache* tileCache(); scripting::LuaLibrary luaLibrary() const override; + std::vector documentations() const override; + const globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe(); struct Layer { diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index e07f632bbb..b176825333 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -24,6 +24,8 @@ #include +#include +#include #include #include #include @@ -93,6 +95,114 @@ namespace { }; } // namespace +documentation::Documentation Layer::Documentation() { + using namespace documentation; + return { + "Layer", + "globebrowsing_layer", + { + { + KeyIdentifier, + new StringVerifier, + Optional::No, + "The unique identifier for this layer. May not contain '.' or spaces." + }, + { + KeyName, + new StringVerifier, + Optional::Yes, + "A human-readable name for the user interface. If this is omitted, the " + "identifier is used instead." + }, + { + KeyDesc, + new StringVerifier, + Optional::Yes, + "A human-readable description of the layer to be used in informational " + "texts presented to the user." + }, + { + "Type", + new StringInListVerifier({ + "DefaultTileLayer", "SingleImageTileLayer", "SizeReferenceTileLayer", + "TemporalTileLayer", "TileIndexTileLayer", "ByIndexTileLayer", + "ByLevelTileLayer", "SolidColor" + }), + Optional::Yes, + "Specifies the type of layer that is to be added. If this value is not " + "specified, the layer is a DefaultTileLayer." + }, + { + EnabledInfo.identifier, + new BoolVerifier, + Optional::Yes, + "Determine whether the layer is enabled or not. If this value is not " + "specified, the layer is disabled." + }, + { + KeyPadTiles, + new BoolVerifier, + Optional::Yes, + "Determines whether the downloaded tiles should have a padding added to " + "the borders." + }, + { + KeySettings, + new TableVerifier({ + { + KeyOpacity, + new DoubleInRangeVerifier(0.0, 1.0), + Optional::Yes, + "The opacity value of the layer." + }, + { + KeyGamma, + new DoubleVerifier, + Optional::Yes, + "The gamma value that is applied to each pixel of the layer." + }, + { + KeyMultiplier, + new DoubleVerifier, + Optional::Yes, + "The multiplicative factor that is applied to each pixel of the " + "layer." + }, + { + KeyOffset, + new DoubleVerifier, + Optional::Yes, + "An additive offset that is applied to each pixel of the layer." + } + }), + Optional::Yes, + "Specifies the render settings that should be applied to this layer." + }, + { + KeyAdjustment, + new ReferencingVerifier("globebrowsing_layeradjustment"), + Optional::Yes, + "" + }, + { + BlendModeInfo.identifier, + new StringInListVerifier({ + "Normal", "Multiply", "Add", "Subtract", "Color" + }), + Optional::Yes, + "Sets the blend mode of this layer to determine how it interacts with " + "other layers on top of this." + }, + { + "Fallback", + new ReferencingVerifier("globebrowsing_layer"), + Optional::Yes, + "If the primary layer creation fails, this layer is used as a fallback" + } + } + }; +} + Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, LayerGroup& parent) : properties::PropertyOwner({ @@ -109,13 +219,15 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, , _solidColor(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) , _layerGroupId(id) { + documentation::testSpecificationAndThrow(Documentation(), layerDict, "Layer"); + layergroupid::TypeID typeID; if (layerDict.hasKeyAndValue("Type")) { const std::string& typeString = layerDict.value("Type"); typeID = ghoul::from_string(typeString); } else { - typeID = layergroupid::TypeID::DefaultTileLayer; + typeID = layergroupid::TypeID::DefaultTileLayer; } if (typeID == layergroupid::TypeID::Unknown) { throw ghoul::RuntimeError("Unknown layer type!"); diff --git a/modules/globebrowsing/src/layer.h b/modules/globebrowsing/src/layer.h index 908217611f..fb8f30dfd4 100644 --- a/modules/globebrowsing/src/layer.h +++ b/modules/globebrowsing/src/layer.h @@ -34,6 +34,8 @@ #include #include +namespace openspace::documentation { struct Documentation; } + namespace openspace::globebrowsing { struct LayerGroup; @@ -72,6 +74,8 @@ public: glm::vec2 tileUvToTextureSamplePosition(const TileUvTransform& uvTransform, const glm::vec2& tileUV, const glm::uvec2& resolution); + static documentation::Documentation Documentation(); + private: void initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict); void addVisibleProperties(); diff --git a/modules/globebrowsing/src/layeradjustment.cpp b/modules/globebrowsing/src/layeradjustment.cpp index e529c544ed..3317133bb0 100644 --- a/modules/globebrowsing/src/layeradjustment.cpp +++ b/modules/globebrowsing/src/layeradjustment.cpp @@ -24,6 +24,9 @@ #include +#include +#include + namespace { constexpr const char* KeyType = "Type"; constexpr const char* KeyChromaKeyColor = "ChromaKeyColor"; @@ -51,6 +54,35 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation LayerAdjustment::Documentation() { + using namespace documentation; + return { + "LayerAdjustment", + "globebrowsing_layeradjustment", + { + { + KeyType, + new StringInListVerifier({ "None", "ChromaKey", "TransferFunction" }), + Optional::Yes, + "Specifies the type of the adjustment that is applied" + }, + { + KeyChromaKeyColor, + new DoubleVector3Verifier, + Optional::Yes, + "Specifies the chroma key used when selecting 'ChromaKey' for the 'Type'." + }, + { + KeyChromaKeyTolerance, + new DoubleVerifier, + Optional::Yes, + "Specifies the tolerance to match the color to the chroma key when the " + "'ChromaKey' type is selected for the 'Type'." + } + } + }; +} + LayerAdjustment::LayerAdjustment() : properties::PropertyOwner({ "adjustment" }) , _chromaKeyColor(ChromaKeyColorInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f)) @@ -89,6 +121,12 @@ LayerAdjustment::LayerAdjustment() } void LayerAdjustment::setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict) { + documentation::testSpecificationAndThrow( + Documentation(), + adjustmentDict, + "LayerAdjustment" + ); + if (adjustmentDict.hasKeyAndValue(KeyType)) { std::string dictType = adjustmentDict.value(KeyType); _typeOption = static_cast( diff --git a/modules/globebrowsing/src/layeradjustment.h b/modules/globebrowsing/src/layeradjustment.h index eefa79c047..07c7c9460c 100644 --- a/modules/globebrowsing/src/layeradjustment.h +++ b/modules/globebrowsing/src/layeradjustment.h @@ -32,6 +32,8 @@ #include #include +namespace openspace::documentation { struct Documentation; } + namespace openspace::globebrowsing { namespace tileprovider { struct TileProvider; } @@ -50,6 +52,8 @@ public: void onChange(std::function callback); + static documentation::Documentation Documentation(); + private: void addVisibleProperties(); diff --git a/modules/globebrowsing/src/layergroup.cpp b/modules/globebrowsing/src/layergroup.cpp index df012f3a9f..909eb3dae4 100644 --- a/modules/globebrowsing/src/layergroup.cpp +++ b/modules/globebrowsing/src/layergroup.cpp @@ -25,6 +25,7 @@ #include #include +#include #include namespace { @@ -106,6 +107,14 @@ int LayerGroup::update() { } Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { + documentation::TestResult res = documentation::testSpecification( + Layer::Documentation(), + layerDict + ); + if (!res.success) { + LERROR("Error adding layer. " + ghoul::to_string(res)); + } + if (!layerDict.hasKeyAndValue("Identifier")) { LERROR("'Identifier' must be specified for layer."); return nullptr; diff --git a/modules/globebrowsing/src/layermanager.cpp b/modules/globebrowsing/src/layermanager.cpp index 825f465fa7..18b91da259 100644 --- a/modules/globebrowsing/src/layermanager.cpp +++ b/modules/globebrowsing/src/layermanager.cpp @@ -28,10 +28,28 @@ #include #include #include +#include +#include #include namespace openspace::globebrowsing { +documentation::Documentation LayerManager::Documentation() { + using namespace documentation; + return { + "LayerManager", + "globebrowsing_layermanager", + { + { + "*", + new ReferencingVerifier("globebrowsing_layer"), + Optional::Yes, + "Specifies an individual layer" + } + } + }; +} + LayerManager::LayerManager() : properties::PropertyOwner({ "Layers" }) {} void LayerManager::initialize(const ghoul::Dictionary& layerGroupsDict) { diff --git a/modules/globebrowsing/src/layermanager.h b/modules/globebrowsing/src/layermanager.h index bd504210c1..3052f8f4ee 100644 --- a/modules/globebrowsing/src/layermanager.h +++ b/modules/globebrowsing/src/layermanager.h @@ -35,6 +35,8 @@ namespace ghoul { class Dictionary; } +namespace openspace::documentation { struct Documentation; } + namespace openspace::globebrowsing { class Layer; @@ -70,6 +72,8 @@ public: void onChange(std::function callback); + static documentation::Documentation Documentation(); + private: std::array, NumLayerGroups> _layerGroups; }; diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 51c263d9c3..285c19c13a 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -424,6 +426,57 @@ Chunk::Chunk(const TileIndex& ti) , status(Status::DoNothing) {} +documentation::Documentation RenderableGlobe::Documentation() { + using namespace documentation; + return { + "RenderableGlobe", + "globebrowsing_renderableglobe", + { + { + "Type", + new StringEqualVerifier("RenderableGlobe"), + Optional::No, + "" + }, + { + KeyRadii, + new OrVerifier({ new DoubleVector3Verifier, new DoubleVerifier }), + Optional::Yes, + "Specifies the radii for this planet. If the Double version of this is " + "used, all three radii are assumed to be equal." + }, + { + "PerformShading", + new BoolVerifier, + Optional::Yes, + "Specifies whether the planet should be shaded by the primary light " + "source or not. If it is disabled, all parts of the planet are " + "illuminated." + }, + { + KeyLayers, + new TableVerifier({ + { + "*", + new ReferencingVerifier("globebrowsing_layermanager"), + Optional::Yes, + "Descriptions of the individual layer groups" + } + }), + Optional::Yes, + "A list of all the layers that should be added" + }, + { + KeyLabels, + new ReferencingVerifier("globebrowsing_globelabelscomponent"), + Optional::Yes, + "Specifies information about planetary labels that can be rendered on " + "the object's surface." + } + } + }; +} + RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _debugProperties({ diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index 7886c0d3e2..26cd45573c 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -41,6 +41,8 @@ #include #include +namespace openspace::documentation { struct Documentation; } + namespace openspace::globebrowsing { class GPULayerGroup; @@ -111,6 +113,8 @@ public: LayerManager& layerManager(); const glm::dmat4& modelTransform() const; + static documentation::Documentation Documentation(); + private: constexpr static const int MinSplitDepth = 2; constexpr static const int MaxSplitDepth = 22; diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index cfd5e5db9c..9f42f6d3c8 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -94,8 +94,6 @@ template <> std::string to_string(const openspace::documentation::TestResult::Offense::Reason& value) { switch (value) { - case openspace::documentation::TestResult::Offense::Reason::ExtraKey: - return "Extra key"; case openspace::documentation::TestResult::Offense::Reason::MissingKey: return "Missing key"; case openspace::documentation::TestResult::Offense::Reason::UnknownIdentifier: From 0e1bc9950d4ca3ac533173208947712407d8fc96 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 31 Jul 2019 10:12:33 +0200 Subject: [PATCH 29/32] Update SGCT to fix contrast/brightness issue --- apps/OpenSpace/ext/sgct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 8f2ed18481..25c8d30bde 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 8f2ed184813a04d635c3ecfcf2efc6174594da23 +Subproject commit 25c8d30bde216066840d197e4443def196c70e17 From f2a0cb18b08ce83e8b0d1f4ade9d862eba6a1219 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 31 Jul 2019 11:07:25 +0200 Subject: [PATCH 30/32] Feature/websocketnavigation (#882) * Upgrade JSON Library * Added support for navigation based on websocket communication --- ext/json/json.hpp | 22555 +++++++++++----- include/openspace/engine/globals.h | 4 + include/openspace/interaction/inputstate.h | 8 + .../openspace/interaction/navigationhandler.h | 11 +- .../openspace/interaction/orbitalnavigator.h | 8 +- .../interaction/websocketcamerastates.h | 117 + .../interaction/websocketinputstate.h | 125 + .../util/fieldlinesstate.cpp | 1 + modules/server/CMakeLists.txt | 2 + .../include/topics/flightcontrollertopic.h | 79 + modules/server/src/connection.cpp | 7 +- .../src/topics/flightcontrollertopic.cpp | 438 + src/CMakeLists.txt | 5 +- src/engine/globals.cpp | 6 + src/engine/openspaceengine.cpp | 3 +- src/interaction/inputstate.cpp | 30 +- src/interaction/navigationhandler.cpp | 14 + src/interaction/orbitalnavigator.cpp | 50 +- src/interaction/websocketcamerastates.cpp | 260 + src/interaction/websocketinputstate.cpp | 97 + 20 files changed, 16449 insertions(+), 7371 deletions(-) create mode 100644 include/openspace/interaction/websocketcamerastates.h create mode 100644 include/openspace/interaction/websocketinputstate.h create mode 100644 modules/server/include/topics/flightcontrollertopic.h create mode 100644 modules/server/src/topics/flightcontrollertopic.cpp create mode 100644 src/interaction/websocketcamerastates.cpp create mode 100644 src/interaction/websocketinputstate.cpp diff --git a/ext/json/json.hpp b/ext/json/json.hpp index 6dfc1831fa..5003a4fa2d 100644 --- a/ext/json/json.hpp +++ b/ext/json/json.hpp @@ -1,11 +1,12 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.6.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . -Copyright (c) 2013-2017 Niels Lohmann . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,45 +27,445 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ -#include // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform -#include // array +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 6 +#define NLOHMANN_JSON_VERSION_PATCH 1 + +#include // all_of, find, for_each #include // assert -#include // isdigit #include // and, not, or -#include // isfinite, labs, ldexp, signbit #include // nullptr_t, ptrdiff_t, size_t -#include // int64_t, uint64_t -#include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull -#include // strlen -#include // forward_list -#include // function, hash, less +#include // hash, less #include // initializer_list -#include // setw -#include // istream, ostream -#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator -#include // numeric_limits -#include // locale -#include // map -#include // addressof, allocator, allocator_traits, unique_ptr +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr #include // accumulate -#include // stringstream -#include // domain_error, invalid_argument, out_of_range -#include // getline, stoi, string, to_string -#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type -#include // declval, forward, make_pair, move, pair, swap +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap #include // vector +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + // exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif #endif #endif @@ -89,17 +490,333 @@ SOFTWARE. #define JSON_DEPRECATED #endif +// allow for portable nodiscard warnings +#if defined(__has_cpp_attribute) + #if __has_cpp_attribute(nodiscard) + #define JSON_NODISCARD [[nodiscard]] + #elif __has_cpp_attribute(gnu::warn_unused_result) + #define JSON_NODISCARD [[gnu::warn_unused_result]] + #else + #define JSON_NODISCARD + #endif +#else + #define JSON_NODISCARD +#endif + // allow to disable exceptions -#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) #else + #include #define JSON_THROW(exception) std::abort() #define JSON_TRY if(true) #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) #endif +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(x, 1) + #define JSON_UNLIKELY(x) __builtin_expect(x, 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template