#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr const char _loggerCat[] = "SkyBrowserModule"; } // namespace namespace openspace::skybrowser::luascriptfunctions { int selectImage(lua_State* L) { // Load image ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()]; if (selectedBrowser) { ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget(); ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Load image, if the image has not been loaded yet if (resultImage.id == ImageData::NO_ID) { LINFO("Loading image " + resultImage.name); selectedBrowser->addImage(resultImage); } // If the image has coordinates, move the target if (resultImage.hasCelestCoords) { // Animate the target to the image coord position if (selectedTarget) { selectedTarget->unlock(); selectedTarget->startAnimation(resultImage.celestCoords, resultImage.fov); glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); float r = windowRatio.x / windowRatio.y; // Check if image coordinate is within current FOV bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0); bool coordIsBehindCamera = imgCoordsOnScreen.z > 0; // If the coordinate is not in view, rotate camera if (!coordIsWithinView || coordIsBehindCamera) { module->startRotation(resultImage.celestCoords); } } } } else { LINFO("No browser selected!"); } return 0; } int moveCircleToHoverImage(lua_State* L) { // Load image ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::moveCircleToHoverImage"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i]; // Only move and show circle if the image has coordinates if (resultImage.hasCelestCoords) { // Make circle visible ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(true); // Calculate coords for the circle and translate glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(resultImage.celestCoords); hoverCircle->property("CartesianPosition")->set(imageCoordsScreenSpace); } return 0; } int disableHoverCircle(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableHoverCircle"); ScreenSpaceImageLocal* hoverCircle = dynamic_cast(global::renderEngine->screenSpaceRenderable("HoverCircle")); hoverCircle->property("Enabled")->set(false); return 0; } int lockTarget(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::lockTarget"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); std::vector browsers = module->getSkyBrowsers(); ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (i < browsers.size()) { ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (target) { target->lock(); } } return 0; } int unlockTarget(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unlockTarget"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); std::vector browsers = module->getSkyBrowsers(); if (i < browsers.size()) { ScreenSpaceSkyTarget* target = browsers[i]->getSkyTarget(); if (target) { target->unlock(); } } return 0; } int loadImagesToWWT(lua_State* L) { // Load images from url ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::loadImagesToWWT"); SkyBrowserModule* module = global::moduleEngine->module(); // Load the collections here because here we know that the browser can execute javascript std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) { if (!browser->hasLoadedCollections()) { browser->sendMessageToWWT(wwtmessage::loadCollection(root)); browser->setHasLoadedCollections(true); } } return 0; } int getListOfImages(lua_State* L) { // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages"); SkyBrowserModule* module = global::moduleEngine->module(); std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml"; std::string hubble = "http://www.worldwidetelescope.org/wwtweb/catalog.aspx?W=hubble"; std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/"); // If no data has been loaded yet, download the data from the web! if (module->getWWTDataHandler()->getLoadedImages().size() == 0) { module->loadImages(root, directory); } // Create Lua table to send to the GUI const std::vector& images = module->getWWTDataHandler()->getLoadedImages(); lua_newtable(L); for (int i = 0; i < images.size(); i++) { std::string name = images[i].name != "" ? images[i].name : "undefined"; std::string thumbnail = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined"; glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestCoords); std::vector cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z }; glm::dvec3 position = images[i].position3d; std::vector position3d = { position.x, position.y, position.z }; // Index for current ImageData ghoul::lua::push(L, i + 1); lua_newtable(L); // Push ("Key", value) ghoul::lua::push(L, "name", name); lua_settable(L, -3); ghoul::lua::push(L, "thumbnail", thumbnail); lua_settable(L, -3); ghoul::lua::push(L, "ra", images[i].celestCoords.x); lua_settable(L, -3); ghoul::lua::push(L, "dec", images[i].celestCoords.y); lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", cartCoordsVec); lua_settable(L, -3); ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestCoords); lua_settable(L, -3); ghoul::lua::push(L, "credits", images[i].credits); lua_settable(L, -3); ghoul::lua::push(L, "creditsUrl", images[i].creditsUrl); lua_settable(L, -3); ghoul::lua::push(L, "identifier", std::to_string(i)); lua_settable(L, -3); ghoul::lua::push(L, "has3dCoords", images[i].has3dCoords); lua_settable(L, -3); ghoul::lua::push(L, "position3d", position3d); lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); } return 1; } int getTargetData(lua_State* L) { // Send image list to GUI ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getTargetData"); SkyBrowserModule* module = global::moduleEngine->module(); lua_newtable(L); int index = 1; // Add the window data for OpenSpace ghoul::lua::push(L, index); index++; lua_newtable(L); // Get the view direction of the screen in cartesian J2000 coordinates glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3(); constexpr double infinity = std::numeric_limits::max(); glm::dvec3 galCoord = camPos + (infinity * global::navigationHandler->camera()->viewDirectionWorldSpace()); glm::dvec3 cartesianJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(galCoord); glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000); // Convert to vector so ghoul can read it std::vector viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z }; // Calculate the smallest FOV of vertical and horizontal float HFOV = global::windowDelegate->getHorizFieldOfView(); glm::vec2 windowRatio = global::windowDelegate->currentWindowSize(); float VFOV = HFOV * (windowRatio.y / windowRatio.x); double FOV = std::min(HFOV, VFOV); // Push window data ghoul::lua::push(L, "windowHFOV", FOV); lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec); lua_settable(L, -3); ghoul::lua::push(L, "ra", sphericalJ2000.x); lua_settable(L, -3); ghoul::lua::push(L, "dec", sphericalJ2000.y); lua_settable(L, -3); ghoul::lua::push(L, "selectedBrowserIndex", module->getSelectedBrowserIndex()); lua_settable(L, -3); // Set table for the current ImageData lua_settable(L, -3); // Pass data for all the browsers and the corresponding targets std::vector browsers = module->getSkyBrowsers(); for (ScreenSpaceSkyBrowser* browser : browsers) { // Only add browsers that have an initialized target ScreenSpaceSkyTarget* target = browser->getSkyTarget(); if (target) { glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial(); glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical); std::vector celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z }; // Convert color to vector so ghoul can read it glm::ivec3 color = browser->_borderColor.value(); std::vector colorVec = { color.r, color.g, color.b }; ghoul::lua::push(L, index); index++; lua_newtable(L); // Push ("Key", value) ghoul::lua::push(L, "FOV", browser->fieldOfView()); lua_settable(L, -3); ghoul::lua::push(L, "cartesianDirection", celestialCartVec); lua_settable(L, -3); ghoul::lua::push(L, "ra", celestialSpherical.x); lua_settable(L, -3); ghoul::lua::push(L, "dec", celestialSpherical.y); lua_settable(L, -3); ghoul::lua::push(L, "color", colorVec); lua_settable(L, -3); // Set table for the current target lua_settable(L, -3); } } return 1; } int adjustCamera(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->getSkyBrowsers().size() > i) { module->startRotation(module->getSkyBrowsers()[i]->getSkyTarget()->getTargetDirectionCelestial()); } return 0; } int setSelectedBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setSelectedBrowser"); const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); if (module->getSkyBrowsers().size() < i) { module->setSelectedBrowser(i); } return 0; } int create3dSkyBrowser(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::create3dSkyBrowser"); // Image index to place in 3D const int i = ghoul::lua::value(L, 1); SkyBrowserModule* module = global::moduleEngine->module(); ImageData image = module->getWWTDataHandler()->getLoadedImages()[i]; // If the image has a 3D position, add it to the scene graph if (image.has3dCoords) { std::string id = "SkyBrowser" + std::to_string(i); glm::dvec3 position = image.position3d * distanceconstants::Parsec; std::string translation = ghoul::to_string(position); std::string guiPath = "/SkyBrowser"; // Calculate the size of the plane with trigonometry // Calculate in equatorial coordinate system since the FOV is from Earth // /| // /_| Adjacent is the horizontal line, opposite the vertical // \ | Calculate for half the triangle first, then multiply with 2 // \| glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position); double adjacent = glm::length(j2000); double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5)); // Calculate rotation to make the plane face the solar system barycenter glm::dvec3 normal = glm::normalize(-position); glm::dvec3 newRight = glm::normalize( glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal) ); glm::dvec3 newUp = glm::cross(normal, newRight); glm::dmat3 originOrientedRotation = glm::dmat3(1.0); originOrientedRotation[0] = newRight; originOrientedRotation[1] = newUp; originOrientedRotation[2] = normal; const std::string browser = "{" "Identifier = '" + id + "'," "Parent = 'SolarSystemBarycenter'," "Renderable = {" "Type = 'RenderableSkyBrowser'," "Size = " + std::to_string(opposite) +"," "Origin = 'Center'," "Billboard = false," "Url = 'http://localhost:8000'" "}," "Transform = {" "Translation = {" "Type = 'StaticTranslation'," "Position = " + translation + "" "}," "Rotation = {" "Type = 'StaticRotation'," "Rotation = " + ghoul::to_string(originOrientedRotation) + "" "}" "}," "GUI = {" "Name = '" + image.name + "'," "Path = '" + guiPath + "'" "}" "}"; LINFO(browser); openspace::global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + browser + ");", scripting::ScriptEngine::RemoteScripting::Yes ); } else { LINFO("Image has no 3D coordinate!"); } return 0; } }