/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2021 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include "skybrowsermodule_lua.inl" #include #include #include // For atan2 #include // For printing glm data #include namespace { struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters { }; #include "skybrowsermodule_codegen.cpp" } // namespace namespace openspace { scripting::LuaLibrary SkyBrowserModule::luaLibrary() const { scripting::LuaLibrary res; res.name = "skybrowser"; res.functions = { { "create", &skybrowser::luascriptfunctions::createBrowser, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, { "move", &skybrowser::luascriptfunctions::moveBrowser, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, { "follow", &skybrowser::luascriptfunctions::followCamera, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, { "loadCollection", &skybrowser::luascriptfunctions::loadImgCollection, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, { "adjustCamera", & skybrowser::luascriptfunctions::adjustCamera, {}, "string or list of strings", "Add one or multiple exoplanet systems to the scene, as specified by the " "input. An input string should be the name of the system host star" }, }; return res; } SkyBrowserModule::SkyBrowserModule() : OpenSpaceModule(SkyBrowserModule::Name) , _mouseOnObject(nullptr) , currentlyResizingBrowser(false) , currentlyDraggingObject(false) , resizeVector(0.f, 0.f) , shouldInitialize(true) , changeViewWithinBrowser(false) { global::callback::mousePosition->emplace_back( [&](double x, double y) { // Quick fix to make all renderables find its corresponding partner if (shouldInitialize) { std::for_each(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { if (to_target(obj)) { to_target(obj)->setConnectedBrowser(); } else if (to_browser(obj)) { to_browser(obj)->setConnectedTarget(); } }); shouldInitialize = false; } glm::vec2 pos = glm::vec2(static_cast(x), static_cast(y)); _mousePosition = getMousePositionInScreenSpaceCoords(pos); if (currentlyDraggingObject) { glm::dvec2 move = _mousePosition - startDragMousePos; // Change view within the browser and move target accordingly to mousedrag movement if (changeViewWithinBrowser) { // WWT FOV double WWTVerticalFOV = to_browser(_mouseOnObject)->fieldOfView(); glm::dvec2 browserDim = to_browser(_mouseOnObject)->getScreenSpaceDimensions(); double browserRatio = browserDim.x / browserDim.y; glm::dvec2 WWTFOV = glm::dvec2(WWTVerticalFOV * browserRatio, WWTVerticalFOV); // OpenSpace FOV glm::dvec2 windowDim = global::windowDelegate->currentWindowSize(); double windowRatio = windowDim.y / windowDim.x; double OpenSpaceHorizontalFOV = global::windowDelegate->getHorizFieldOfView(); glm::dvec2 OpenSpaceFOV = glm::dvec2(OpenSpaceHorizontalFOV, OpenSpaceHorizontalFOV * windowRatio); glm::dvec2 angleResult = WWTFOV * (move / browserDim); glm::dvec2 OSresult = angleResult / OpenSpaceFOV; // Calculate translation in ScreenSpaceCoordinates glm::dvec2 screenSpaceCoord{ (2 / windowRatio), 2.f }; glm::dvec2 result = screenSpaceCoord * OSresult; to_browser(_mouseOnObject)->getSkyTarget()->translate(-result, startDragObjectPos); } // Move browser or target else _mouseOnObject->translate(move, startDragObjectPos); } else if (currentlyResizingBrowser) { // Calculate scaling factor glm::vec2 mouseDragVector = (_mousePosition - startDragMousePos); glm::vec2 scalingVector = mouseDragVector * resizeVector; glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize; // Scale the browser to_browser(_mouseOnObject)->scale(newSizeRelToOld); // For dragging functionality, translate so it looks like the browser isn't moving // Make sure the browser doesn't move in directions it's not supposed to _mouseOnObject->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPos); } // If there is no dragging or resizing, look for new objects else { // Save old selection for removing highlight ScreenSpaceRenderable* lastObj = _mouseOnObject; // Find and save what mouse is currently hovering on auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) { return obj->coordIsInsideCornersScreenSpace(_mousePosition); }); _mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr; // Selection has changed if (lastObj != _mouseOnObject) { glm::ivec3 highlightAddition{ 35, 35, 35 }; // Remove highlight if (to_browser(lastObj)) { to_browser(lastObj)->setBorderColor(to_browser(lastObj)->getColor() - highlightAddition); } else if (to_target(lastObj)) { to_target(lastObj)->setBorderColor(to_target(lastObj)->getColor() - highlightAddition); } // Add highlight if (to_browser(_mouseOnObject)) { to_browser(_mouseOnObject)->setBorderColor(to_browser(_mouseOnObject)->getColor() + highlightAddition); } else if (to_target(_mouseOnObject)) { to_target(_mouseOnObject)->setBorderColor(to_target(_mouseOnObject)->getColor() + highlightAddition); } } } } ); global::callback::mouseScrollWheel->emplace_back( [&](double, double scroll) -> bool { // If mouse is on browser, apply zoom if (to_browser(_mouseOnObject)) { to_browser(_mouseOnObject)->scrollZoom(scroll); return true; } else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) { to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(scroll); } return false; } ); global::callback::mouseButton->emplace_back( [&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool { if (action == MouseAction::Press) { if (_mouseOnObject && button == MouseButton::Left) { startDragMousePos = _mousePosition; startDragObjectPos = _mouseOnObject->getScreenSpacePosition(); // If current object is browser, check for resizing if (to_browser(_mouseOnObject)) { // Resize browser if mouse is over resize button resizeVector = to_browser(_mouseOnObject)->coordIsOnResizeArea(_mousePosition); if (resizeVector != glm::vec2{ 0 }) { to_browser(_mouseOnObject)->saveResizeStartSize(); startResizeBrowserSize = to_browser(_mouseOnObject)->getScreenSpaceDimensions(); currentlyResizingBrowser = true; return true; } } currentlyDraggingObject = true; return true; } else if (to_browser(_mouseOnObject) && button == MouseButton::Right) { // Change view (by moving target) within browser if right mouse click on browser startDragMousePos = _mousePosition; startDragObjectPos = to_browser(_mouseOnObject)->getSkyTarget()->getScreenSpacePosition(); changeViewWithinBrowser = true; currentlyDraggingObject = true; return true; } } else if (action == MouseAction::Release) { if (currentlyDraggingObject) { currentlyDraggingObject = false; changeViewWithinBrowser = false; return true; } if (currentlyResizingBrowser) { currentlyResizingBrowser = false; to_browser(_mouseOnObject)->updateBrowserSize(); return true; } } return false; } ); } void SkyBrowserModule::internalDeinitialize() { delete dataHandler; } void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); // register ScreenSpaceBrowser auto fScreenSpaceRenderable = FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); fScreenSpaceRenderable->registerClass("ScreenSpaceSkyBrowser"); // register ScreenSpaceTarget ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); fScreenSpaceRenderable->registerClass("ScreenSpaceSkyTarget"); dataHandler = new WWTDataHandler(); } glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) { glm::vec2 size = global::windowDelegate->currentWindowSize(); // Change origin to middle of the window glm::vec2 screenSpacePos = glm::vec2((mousePos - (size / 2.0f))); // Ensure the upper right corner is positive on the y axis screenSpacePos *= glm::vec2(1.0f, -1.0f); // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio] screenSpacePos /= (0.5f*size.y); return screenSpacePos; } void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) { renderables.push_back(object); // Sort on z coordinate, objects closer to camera are in beginning of list std::sort(renderables.begin(), renderables.end()); } ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) { return dynamic_cast(ptr); } WWTDataHandler* SkyBrowserModule::getWWTDataHandler() { return dataHandler; } glm::dvec2 SkyBrowserModule::convertGalacticToCelestial(glm::dvec3 rGal) const { // Used the math from this website: https://gea.esac.esa.int/archive/documentation/GD --> // R2/Data_processing/chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 const glm::dmat3 conversionMatrix = glm::dmat3({ -0.0548755604162154, 0.4941094278755837, -0.8676661490190047, // col 0 -0.8734370902348850, -0.4448296299600112, -0.1980763734312015, // col 1 -0.4838350155487132, 0.7469822444972189, 0.4559837761750669 // col 2 }); glm::dvec3 rICRS = glm::transpose(conversionMatrix) * rGal; float ra = atan2(rICRS[1], rICRS[0]); float dec = atan2(rICRS[2], glm::sqrt((rICRS[0] * rICRS[0]) + (rICRS[1] * rICRS[1]))); ra = ra > 0 ? ra : ra + (2 * glm::pi()); return glm::dvec2(glm::degrees(ra), glm::degrees(dec)); } /* std::vector SkyBrowserModule::documentations() const { return { ExoplanetsDataPreparationTask::documentation(), RenderableOrbitDisc::Documentation() }; } */ } // namespace openspace