Add functionality for 3D browser: wwt messages and function to create an instance in lua api

This commit is contained in:
Ylva Selling
2021-05-19 12:01:20 +02:00
parent d2871392d7
commit 19d24e90d7
11 changed files with 400 additions and 268 deletions

View File

@@ -50,6 +50,10 @@ namespace openspace {
void update(const UpdateData& data) override;
void executeJavascript(std::string script) const;
bool sendMessageToWWT(const ghoul::Dictionary& msg);
protected:
properties::Vec2Property _dimensions;

View File

@@ -20,17 +20,7 @@ namespace openspace {
// Communication with the webpage and WWT
void executeJavascript(std::string script) const;
ghoul::Dictionary createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly = true) const;
ghoul::Dictionary createMessageForPausingWWTTime() const;
ghoul::Dictionary createMessageForLoadingWWTImgColl(const std::string& url) const;
ghoul::Dictionary createMessageForSettingForegroundWWT(const std::string& name) const;
ghoul::Dictionary createMessageForSettingForegroundOpacityWWT(double val) const;
ghoul::Dictionary createMessageForAddingImageLayerWWT(ImageData& url);
ghoul::Dictionary createMessageForRemovingImageLayerWWT(const std::string& id) const;
ghoul::Dictionary createMessageForSettingOpacityLayerWWT(const ImageData& id, double opacity) const;
bool sendMessageToWWT(const ghoul::Dictionary& msg);
void sendMouseEvent(CefStructBase<CefMouseEventTraits> event, int x, int y) const;
void WWTfollowCamera();
float fieldOfView() const;
void setVerticalFieldOfView(float fov);
@@ -38,6 +28,7 @@ namespace openspace {
ScreenSpaceSkyTarget* getSkyTarget();
bool hasLoadedCollections();
void setHasLoadedCollections(bool isLoaded);
void addImage(ImageData& image);
// Translation
//void translate(glm::vec2 translation);

View File

@@ -1,3 +1,4 @@
#include <modules/skybrowser/include/wwtdatahandler.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/engine/globals.h>
#include <openspace/util/camera.h>
@@ -7,34 +8,51 @@
#include <math.h>
namespace openspace::skybrowser {
const double SCREENSPACE_Z = -2.1;
const double RAD_TO_DEG = 180.0 / M_PI;
const double DEG_TO_RAD = M_PI / 180.0;
const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 };
constexpr double infinity = std::numeric_limits<float>::max();
namespace openspace {
namespace skybrowser {
const double SCREENSPACE_Z = -2.1;
const double RAD_TO_DEG = 180.0 / M_PI;
const double DEG_TO_RAD = M_PI / 180.0;
const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 };
constexpr double infinity = std::numeric_limits<float>::max();
// Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1
const glm::dmat3 conversionMatrix = glm::dmat3({
-0.054875539390, 0.494109453633, -0.867666135681, // col 0
-0.873437104725, -0.444829594298, -0.198076389622, // col 1
-0.483834991775, 0.746982248696, 0.455983794523 // col 2
});
// Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1
const glm::dmat3 conversionMatrix = glm::dmat3({
-0.054875539390, 0.494109453633, -0.867666135681, // col 0
-0.873437104725, -0.444829594298, -0.198076389622, // col 1
-0.483834991775, 0.746982248696, 0.455983794523 // col 2
});
// J2000 to galactic conversion and vice versa
glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords);
glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords);
glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal);
glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal);
glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords);
glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance = infinity);
glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance = infinity);
// Convert J2000, spherical or Cartesian, to screen space
glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords);
glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords);
glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord);
// J2000 to galactic conversion and vice versa
glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords);
glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords);
glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal);
glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal);
glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords);
glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords,
double distance = infinity);
glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords,
double distance = infinity);
// Convert J2000, spherical or Cartesian, to screen space
glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords);
glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords);
glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord);
}
namespace wwtmessage {
// WWT messages
ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords,
const double fov, const bool moveInstantly = true);
ghoul::Dictionary loadCollection(const std::string& url);
ghoul::Dictionary setForeground(const std::string& name);
ghoul::Dictionary createImageLayer(ImageData& image, int id = 0);
ghoul::Dictionary removeImageLayer(const std::string& id);
ghoul::Dictionary setLayerOpacity(const ImageData& image,
double opacity);
ghoul::Dictionary setForegroundOpacity(double val);
}
}

View File

@@ -62,8 +62,9 @@ namespace openspace {
std::string creditsUrl;
glm::dvec2 celestCoords;
std::string collection;
float zoomLevel;
bool hasCoords;
float fov;
bool hasCelestCoords{ false };
bool has3dCoords{ false };
glm::dvec3 position3d;
int id{ NO_ID };
};

View File

@@ -34,6 +34,7 @@
#include <openspace/engine/windowdelegate.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/scene/scene.h>
#include <openspace/util/factorymanager.h>
@@ -144,6 +145,14 @@ namespace openspace {
"Add one or multiple exoplanet systems to the scene, as specified by the "
"input. An input string should be the name of the system host star"
},
{
"create3dSkyBrowser",
&skybrowser::luascriptfunctions::create3dSkyBrowser,
{},
"string or list of strings",
"Add one or multiple exoplanet systems to the scene, as specified by the "
"input. An input string should be the name of the system host star"
},
};
return res;
@@ -391,6 +400,10 @@ void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) {
}
}
void SkyBrowserModule::add3dBrowser(SceneGraphNode* node) {
browsers3d.push_back(node);
}
ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) {
return dynamic_cast<ScreenSpaceSkyBrowser*>(ptr);
}
@@ -468,9 +481,10 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir
dataHandler->loadSpeckData(speckOpenClusters);
int nLoadedImages;
// Read from disc
bool loadedImages = dataHandler->loadWTMLCollectionsFromDirectory(directory);
// Reading from url if there is no directory
if (loadedImages) {
LINFO("Loading images from directory");

View File

@@ -44,6 +44,7 @@ class ScreenSpaceSkyTarget;
class RenderableSkyBrowser;
class ScreenSpaceRenderable;
class WWTDataHandler;
class SceneGraphNode;
class SkyBrowserModule : public OpenSpaceModule {
@@ -64,6 +65,7 @@ public:
void setSelectedBrowser(int i);
int getSelectedBrowserIndex();
int loadImages(const std::string& root, const std::string& directory);
void add3dBrowser(SceneGraphNode* node);
scripting::LuaLibrary luaLibrary() const override;
//std::vector<documentation::Documentation> documentations() const override;
@@ -81,6 +83,7 @@ protected:
// Renderable vector and ptr to where mouse is
std::vector<ScreenSpaceRenderable*> renderables;
std::vector<ScreenSpaceSkyBrowser*> browsers;
std::vector<SceneGraphNode*> browsers3d;
ScreenSpaceRenderable* _mouseOnObject;
// Dragging
glm::vec2 startDragMousePos;

View File

@@ -2,28 +2,29 @@
#include <openspace/documentation/documentation.h>
#include <modules/skybrowser/skybrowsermodule.h>
#include <modules/skybrowser/include/utility.h>
#include <modules/skybrowser/include/screenspaceskybrowser.h>
#include <modules/skybrowser/include/screenspaceskytarget.h>
#include <modules/skybrowser/include/renderableskybrowser.h>
#include <modules/base/rendering/screenspaceimagelocal.h>
#include <modules/base/rendering/renderableplaneimagelocal.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/util/camera.h>
#include <openspace/util/distanceconstants.h>
#include <ghoul/misc/dictionaryluaformatter.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/fmt.h>
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <fstream>
#include <sstream>
#include <modules/skybrowser/include/screenspaceskybrowser.h>
#include <modules/skybrowser/include/screenspaceskytarget.h>
#include <modules/skybrowser/include/renderableskybrowser.h>
#include <modules/base/rendering/screenspaceimagelocal.h>
#include <modules/base/rendering/renderableplaneimagelocal.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/util/camera.h>
#include <thread>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <fstream>
#include <sstream>
#include <thread>
#include <limits>
namespace {
@@ -39,36 +40,39 @@ namespace openspace::skybrowser::luascriptfunctions {
const int i = ghoul::lua::value<int>(L, 1);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
ScreenSpaceSkyBrowser* selectedBrowser = module->getSkyBrowsers()[module->getSelectedBrowserIndex()];
ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget();
ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i];
if (selectedBrowser) {
ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget();
// Load image, if the image has not been loaded yet
if (resultImage.id == ImageData::NO_ID) {
LINFO("Loading image " + resultImage.name);
selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForAddingImageLayerWWT(resultImage));
selectedBrowser->sendMessageToWWT(selectedBrowser->createMessageForSettingOpacityLayerWWT(resultImage, 1.0));
}
// If the image has coordinates, move the target
if (resultImage.hasCoords) {
// Animate the target to the image coord position
// In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6
if (selectedTarget) {
selectedTarget->unlock();
selectedTarget->startAnimation(resultImage.celestCoords, resultImage.zoomLevel / 6);
glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords);
glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
float r = windowRatio.x / windowRatio.y;
// Check if image coordinate is within current FOV
bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0);
bool coordIsBehindCamera = imgCoordsOnScreen.z > 0;
// If the coordinate is not in view, rotate camera
if (!coordIsWithinView || coordIsBehindCamera) {
module->startRotation(resultImage.celestCoords);
ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i];
// Load image, if the image has not been loaded yet
if (resultImage.id == ImageData::NO_ID) {
LINFO("Loading image " + resultImage.name);
selectedBrowser->addImage(resultImage);
}
// If the image has coordinates, move the target
if (resultImage.hasCelestCoords) {
// Animate the target to the image coord position
if (selectedTarget) {
selectedTarget->unlock();
selectedTarget->startAnimation(resultImage.celestCoords, resultImage.fov);
glm::dvec3 imgCoordsOnScreen = J2000SphericalToScreenSpace(resultImage.celestCoords);
glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
float r = windowRatio.x / windowRatio.y;
// Check if image coordinate is within current FOV
bool coordIsWithinView = (abs(imgCoordsOnScreen.x) < r && abs(imgCoordsOnScreen.y) < 1.f && imgCoordsOnScreen.z < 0);
bool coordIsBehindCamera = imgCoordsOnScreen.z > 0;
// If the coordinate is not in view, rotate camera
if (!coordIsWithinView || coordIsBehindCamera) {
module->startRotation(resultImage.celestCoords);
}
}
}
}
}
else {
LINFO("No browser selected!");
}
return 0;
}
@@ -81,7 +85,7 @@ namespace openspace::skybrowser::luascriptfunctions {
const ImageData& resultImage = module->getWWTDataHandler()->getLoadedImages()[i];
// Only move and show circle if the image has coordinates
if (resultImage.hasCoords) {
if (resultImage.hasCelestCoords) {
// Make circle visible
ScreenSpaceImageLocal* hoverCircle = dynamic_cast<ScreenSpaceImageLocal*>(global::renderEngine->screenSpaceRenderable("HoverCircle"));
hoverCircle->property("Enabled")->set(true);
@@ -139,7 +143,7 @@ namespace openspace::skybrowser::luascriptfunctions {
std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml";
for (ScreenSpaceSkyBrowser* browser : module->getSkyBrowsers()) {
if (!browser->hasLoadedCollections()) {
browser->sendMessageToWWT(browser->createMessageForLoadingWWTImgColl(root));
browser->sendMessageToWWT(wwtmessage::loadCollection(root));
browser->setHasLoadedCollections(true);
}
}
@@ -167,36 +171,42 @@ namespace openspace::skybrowser::luascriptfunctions {
for (int i = 0; i < images.size(); i++) {
std::string name = images[i].name != "" ? images[i].name : "undefined";
std::string url = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined";
std::string thumbnail = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined";
glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestCoords);
std::vector<double> cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z };
glm::dvec3 position = images[i].position3d;
std::vector<double> position3d = { position.x, position.y, position.z };
// Index for current ImageData
ghoul::lua::push(L, i + 1);
lua_newtable(L);
// Push ("Key", value)
ghoul::lua::push(L, "Name", name);
ghoul::lua::push(L, "name", name);
lua_settable(L, -3);
ghoul::lua::push(L, "Thumbnail", url);
ghoul::lua::push(L, "thumbnail", thumbnail);
lua_settable(L, -3);
ghoul::lua::push(L, "RA", images[i].celestCoords.x);
ghoul::lua::push(L, "ra", images[i].celestCoords.x);
lua_settable(L, -3);
ghoul::lua::push(L, "Dec", images[i].celestCoords.y);
ghoul::lua::push(L, "dec", images[i].celestCoords.y);
lua_settable(L, -3);
ghoul::lua::push(L, "CartesianDirection", cartCoordsVec);
ghoul::lua::push(L, "cartesianDirection", cartCoordsVec);
lua_settable(L, -3);
ghoul::lua::push(L, "HasCoords", images[i].hasCoords);
ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestCoords);
lua_settable(L, -3);
ghoul::lua::push(L, "Credits", images[i].credits);
ghoul::lua::push(L, "credits", images[i].credits);
lua_settable(L, -3);
ghoul::lua::push(L, "CreditsUrl", images[i].creditsUrl);
ghoul::lua::push(L, "creditsUrl", images[i].creditsUrl);
lua_settable(L, -3);
ghoul::lua::push(L, "Index", i);
ghoul::lua::push(L, "identifier", std::to_string(i));
lua_settable(L, -3);
ghoul::lua::push(L, "has3dCoords", images[i].has3dCoords);
lua_settable(L, -3);
ghoul::lua::push(L, "position3d", position3d);
lua_settable(L, -3);
// Set table for the current ImageData
lua_settable(L, -3);
}
return 1;
}
@@ -229,15 +239,15 @@ namespace openspace::skybrowser::luascriptfunctions {
float VFOV = HFOV * (windowRatio.y / windowRatio.x);
double FOV = std::min(HFOV, VFOV);
// Push window data
ghoul::lua::push(L, "WindowHFOV", FOV);
ghoul::lua::push(L, "windowHFOV", FOV);
lua_settable(L, -3);
ghoul::lua::push(L, "CartesianDirection", viewDirCelestVec);
ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec);
lua_settable(L, -3);
ghoul::lua::push(L, "RA", sphericalJ2000.x);
ghoul::lua::push(L, "ra", sphericalJ2000.x);
lua_settable(L, -3);
ghoul::lua::push(L, "Dec", sphericalJ2000.y);
ghoul::lua::push(L, "dec", sphericalJ2000.y);
lua_settable(L, -3);
ghoul::lua::push(L, "SelectedBrowserIndex", module->getSelectedBrowserIndex());
ghoul::lua::push(L, "selectedBrowserIndex", module->getSelectedBrowserIndex());
lua_settable(L, -3);
// Set table for the current ImageData
lua_settable(L, -3);
@@ -262,13 +272,13 @@ namespace openspace::skybrowser::luascriptfunctions {
// Push ("Key", value)
ghoul::lua::push(L, "FOV", browser->fieldOfView());
lua_settable(L, -3);
ghoul::lua::push(L, "CartesianDirection", celestialCartVec);
ghoul::lua::push(L, "cartesianDirection", celestialCartVec);
lua_settable(L, -3);
ghoul::lua::push(L, "RA", celestialSpherical.x);
ghoul::lua::push(L, "ra", celestialSpherical.x);
lua_settable(L, -3);
ghoul::lua::push(L, "Dec", celestialSpherical.y);
ghoul::lua::push(L, "dec", celestialSpherical.y);
lua_settable(L, -3);
ghoul::lua::push(L, "Color", colorVec);
ghoul::lua::push(L, "color", colorVec);
lua_settable(L, -3);
// Set table for the current target
@@ -299,6 +309,81 @@ namespace openspace::skybrowser::luascriptfunctions {
}
return 0;
}
int create3dSkyBrowser(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::create3dSkyBrowser");
// Image index to place in 3D
const int i = ghoul::lua::value<int>(L, 1);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
ImageData image = module->getWWTDataHandler()->getLoadedImages()[i];
// If the image has a 3D position, add it to the scene graph
if (image.has3dCoords) {
std::string id = "SkyBrowser" + std::to_string(i);
glm::dvec3 position = image.position3d * distanceconstants::Parsec;
std::string translation = ghoul::to_string(position);
std::string guiPath = "/SkyBrowser";
// Calculate the size of the plane with trigonometry
// Calculate in equatorial coordinate system since the FOV is from Earth
// /|
// /_| Adjacent is the horizontal line, opposite the vertical
// \ | Calculate for half the triangle first, then multiply with 2
// \|
glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position);
double adjacent = glm::length(j2000);
double opposite = 2 * adjacent * glm::tan(image.fov * 0.5);
// Calculate rotation to make the plane face the solar system barycenter
glm::dvec3 normal = glm::normalize(-position);
glm::dvec3 newRight = glm::normalize(
glm::cross(glm::dvec3(0.0, 0.0, 1.0), normal)
);
glm::dvec3 newUp = glm::cross(normal, newRight);
glm::dmat3 originOrientedRotation = glm::dmat3(1.0);
originOrientedRotation[0] = newRight;
originOrientedRotation[1] = newUp;
originOrientedRotation[2] = normal;
const std::string browser = "{"
"Identifier = '" + id + "',"
"Parent = 'SolarSystemBarycenter',"
"Renderable = {"
"Type = 'RenderableSkyBrowser',"
"Size = " + std::to_string(opposite) +","
"Origin = 'Center',"
"Billboard = false,"
"Url = 'http://localhost:8000'"
"},"
"Transform = {"
"Translation = {"
"Type = 'StaticTranslation',"
"Position = " + translation + ""
"},"
"Rotation = {"
"Type = 'StaticRotation',"
"Rotation = " + ghoul::to_string(originOrientedRotation) + ""
"}"
"},"
"GUI = {"
"Name = '" + image.name + "',"
"Path = '" + guiPath + "'"
"}"
"}";
LINFO(browser);
openspace::global::scriptEngine->queueScript(
"openspace.addSceneGraphNode(" + browser + ");",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
else {
LINFO("Image has no 3D coordinate!");
}
return 0;
}
}

View File

@@ -6,12 +6,14 @@
#include <openspace/engine/windowdelegate.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/engine/globals.h>
#include <ghoul/misc/dictionaryjsonformatter.h> // formatJson
#include <ghoul/misc/profiling.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/textureunit.h>
#include <ghoul/misc/profiling.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/opengl/texture.h>
namespace {
@@ -112,6 +114,7 @@ namespace openspace {
_browserInstance->initialize();
_browserInstance->loadUrl(_url);
_dimensions = _texture->dimensions();
}
void RenderableSkyBrowser::deinitializeGL() {
@@ -153,7 +156,6 @@ namespace openspace {
}
}
void RenderableSkyBrowser::bindTexture() {
if (_texture) {
_texture->bind();
@@ -162,4 +164,18 @@ namespace openspace {
glBindTexture(GL_TEXTURE_2D, 0);
}
}
void RenderableSkyBrowser::executeJavascript(std::string script) const {
//LINFOC(_loggerCat, "Executing javascript " + script);
if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) {
CefRefPtr<CefFrame> frame = _browserInstance->getBrowser()->GetMainFrame();
frame->ExecuteJavaScript(script, frame->GetURL(), 0);
}
}
bool RenderableSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) {
std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");";
executeJavascript(script);
return true;
}
} // namespace

View File

@@ -230,113 +230,14 @@ namespace openspace {
return true;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForMovingWWTCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly) const {
using namespace std::string_literals;
ghoul::Dictionary msg;
glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(global::navigationHandler->camera()->lookUpVectorWorldSpace());
glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(global::navigationHandler->camera()->viewDirectionWorldSpace());
double angle = glm::degrees(atan2(glm::dot(glm::cross(camUpJ2000, skybrowser::NORTH_POLE), camForwardJ2000), glm::dot(skybrowser::NORTH_POLE, camUpJ2000)));
msg.setValue("event", "center_on_coordinates"s);
msg.setValue("ra", celestCoords.x);
msg.setValue("dec", celestCoords.y);
msg.setValue("fov", fov);
msg.setValue("roll", angle);
msg.setValue("instant", moveInstantly);
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForLoadingWWTImgColl(const std::string& url) const {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "load_image_collection"s);
msg.setValue("url", url);
msg.setValue("loadChildFolders", true);
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundWWT(const std::string& name) const {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_by_name"s);
msg.setValue("name", name);
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForAddingImageLayerWWT(ImageData& image) {
std::string idString = std::to_string(_imageId);
using namespace std::string_literals;
ghoul::Dictionary msg;
image.id = _imageId;
msg.setValue("event", "image_layer_create"s);
msg.setValue("id", idString);
msg.setValue("url", image.imageUrl);
_imageId++;
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForRemovingImageLayerWWT(const std::string& id) const {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_remove"s);
msg.setValue("id", id);
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingOpacityLayerWWT(const ImageData& image, double opacity) const {
std::string idString = std::to_string(image.id);
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_set"s);
msg.setValue("id", idString);
msg.setValue("setting", "opacity"s);
msg.setValue("value", opacity);
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForSettingForegroundOpacityWWT(double val) const {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_opacity"s);
msg.setValue("value", val);
return msg;
}
ghoul::Dictionary ScreenSpaceSkyBrowser::createMessageForPausingWWTTime() const {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "pause_time"s);
return msg;
}
void ScreenSpaceSkyBrowser::sendMouseEvent(CefStructBase<CefMouseEventTraits> event, int x, int y) const {
//LINFOC(_loggerCat, "Executing javascript " + script);
LINFO(std::to_string(_objectSize.x) + " " + std::to_string(_objectSize.y));
if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetHost()) {
//_browserInstance->getBrowser()->GetHost()->SendMouseWheelEvent(event, x, y);
//LINFOC(_loggerCat, "Sending scroll");
}
}
void ScreenSpaceSkyBrowser::WWTfollowCamera() {
// Start a thread to enable user interaction while sending the calls to WWT
_threadWWTMessages = std::thread([&] {
while (_camIsSyncedWWT) {
if (_skyTarget) {
ghoul::Dictionary message = createMessageForMovingWWTCamera(_skyTarget->getTargetDirectionCelestial(), _vfieldOfView);
glm::dvec2 aim = _skyTarget->getTargetDirectionCelestial();
ghoul::Dictionary message = wwtmessage::moveCamera(aim, _vfieldOfView);
sendMessageToWWT(message);
}
@@ -414,4 +315,10 @@ namespace openspace {
glm::vec2 ScreenSpaceSkyBrowser::getBrowserPixelDimensions() {
return _browserDimensions.value();
}
void ScreenSpaceSkyBrowser::addImage(ImageData& image) {
sendMessageToWWT(wwtmessage::createImageLayer(image, _imageId));
sendMessageToWWT(wwtmessage::setLayerOpacity(image, 1.0));
_imageId++;
}
}

View File

@@ -12,86 +12,177 @@
namespace openspace::skybrowser {
glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) {
glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) {
glm::dvec3 cartesian = glm::dvec3(
cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD),
sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD),
sin(sphericalCoords.y * DEG_TO_RAD)
);
glm::dvec3 cartesian = glm::dvec3(
cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD),
sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD),
sin(sphericalCoords.y * DEG_TO_RAD)
);
return cartesian;
}
return cartesian;
}
glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) {
glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) {
double ra = atan2(cartesianCoords[1], cartesianCoords[0]);
double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1])));
double ra = atan2(cartesianCoords[1], cartesianCoords[0]);
double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1])));
ra = ra > 0 ? ra : ra + (2 * M_PI);
ra = ra > 0 ? ra : ra + (2 * M_PI);
return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec);
}
return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec);
}
glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) {
return glm::transpose(conversionMatrix) * rGal;
}
glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) {
return glm::transpose(conversionMatrix) * rGal;
}
glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) {
return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal));
}
glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) {
return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal));
}
glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) {
glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere
return distance * rGalactic;
}
glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) {
glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere
return distance * rGalactic;
}
glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) {
glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere
return distance * rGalactic;
}
glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) {
glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere
return distance * rGalactic;
}
glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) {
glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) {
glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian);
// Ensure that if the coord is behind the camera, the converted coord will be there too
double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z;
glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian);
// Ensure that if the coord is behind the camera, the converted coord will be there too
double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z;
// Calculate screen space coords x and y
long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z;
long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z;
// Calculate screen space coords x and y
long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z;
long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z;
glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y));
glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast<double>(std::tanl(angleCoordsLocal.x)), zCoord * static_cast<double>(std::tanl(angleCoordsLocal.y)), zCoord);
glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y));
glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast<double>(std::tanl(angleCoordsLocal.x)), zCoord * static_cast<double>(std::tanl(angleCoordsLocal.y)), zCoord);
return imageCoordsScreenSpace;
}
glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) {
// Transform vector to camera's local coordinate system
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos);
glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix();
glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0);
viewDirectionLocal = glm::normalize(viewDirectionLocal);
return viewDirectionLocal;
}
glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) {
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity);
// Transform galactic coord to screen space
return galacticToScreenSpace(imageCoordsGalacticCartesian);
}
glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) {
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity);
// Transform galactic coord to screen space
return galacticToScreenSpace(imageCoordsGalacticCartesian);
}
return imageCoordsScreenSpace;
}
glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) {
// Transform vector to camera's local coordinate system
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos);
glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix();
glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0);
viewDirectionLocal = glm::normalize(viewDirectionLocal);
return viewDirectionLocal;
}
glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) {
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity);
// Transform galactic coord to screen space
return galacticToScreenSpace(imageCoordsGalacticCartesian);
}
glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) {
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity);
// Transform galactic coord to screen space
return galacticToScreenSpace(imageCoordsGalacticCartesian);
}
}
// WWT messages
namespace openspace::wwtmessage {
// WWT messages
ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords, const double fov, const bool moveInstantly) {
using namespace std::string_literals;
ghoul::Dictionary msg;
// Calculate roll between up vector of camera and J2000 equatorial north
glm::dvec3 upVector = global::navigationHandler->camera()->lookUpVectorWorldSpace();
glm::dvec3 viewVector = global::navigationHandler->camera()->viewDirectionWorldSpace();
glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(upVector);
glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(viewVector);
glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NORTH_POLE);
double dotNorthUp = glm::dot(skybrowser::NORTH_POLE, camUpJ2000);
double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000);
double roll = glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
// Create message
msg.setValue("event", "center_on_coordinates"s);
msg.setValue("ra", celestCoords.x);
msg.setValue("dec", celestCoords.y);
msg.setValue("fov", fov);
msg.setValue("roll", roll);
msg.setValue("instant", moveInstantly);
return msg;
}
ghoul::Dictionary loadCollection(const std::string& url) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "load_image_collection"s);
msg.setValue("url", url);
msg.setValue("loadChildFolders", true);
return msg;
}
ghoul::Dictionary setForeground(const std::string& name) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_by_name"s);
msg.setValue("name", name);
return msg;
}
ghoul::Dictionary createImageLayer(ImageData& image, int id) {
std::string idString = std::to_string(id);
image.id = id;
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_create"s);
msg.setValue("id", idString);
msg.setValue("url", image.imageUrl);
return msg;
}
ghoul::Dictionary removeImageLayer(const std::string& id) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_remove"s);
msg.setValue("id", id);
return msg;
}
ghoul::Dictionary setLayerOpacity(const ImageData& image, double opacity) {
std::string idString = std::to_string(image.id);
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_set"s);
msg.setValue("id", idString);
msg.setValue("setting", "opacity"s);
msg.setValue("value", opacity);
return msg;
}
ghoul::Dictionary setForegroundOpacity(double val) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_opacity"s);
msg.setValue("value", val);
return msg;
}
}

View File

@@ -272,15 +272,16 @@ namespace openspace {
ImageData& img) {
// Get attributes for the image
img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : "";
img.hasCoords = node->FindAttribute("RA") && node->FindAttribute("Dec");
if (img.hasCoords) {
img.hasCelestCoords = node->FindAttribute("RA") && node->FindAttribute("Dec");
if (img.hasCelestCoords) {
// The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h) = 15
img.celestCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value());
img.celestCoords.y = std::stof(node->FindAttribute("Dec")->Value());
}
img.collection = collectionName;
img.thumbnailUrl = thumbnail;
img.zoomLevel = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) : 0.f;
// In WWT, the definition of ZoomLevel is: VFOV = ZoomLevel / 6
img.fov = node->FindAttribute("ZoomLevel") ? std::stof(node->FindAttribute("ZoomLevel")->Value()) / 6: 0.f;
img.credits = credits;
img.creditsUrl = creditsUrl;
img.imageUrl = imageUrl;
@@ -290,6 +291,7 @@ namespace openspace {
auto it = _3dPositions.find(str);
if (it != _3dPositions.end()) {
img.position3d = it->second;
img.has3dCoords = true;
nImagesWith3dPositions++;
}
}