This commit is contained in:
sylvass
2021-10-25 09:38:09 -04:00
parent 1cefc8bc5e
commit c895f24989
17 changed files with 910 additions and 752 deletions

View File

@@ -11,7 +11,7 @@ local browser = {
Name = "Sky Browser",
Url = serverUrl,
FaceCamera = false,
TargetID = targetId,
TargetId = targetId,
CartesianPosition = {-1.0, -0.5, -2.1},
};

View File

@@ -73,10 +73,10 @@ public:
// Added by skybrowser team
// Screen space functionality in these coords: [-1,1][-ratio,ratio]
glm::vec2 getScreenSpacePosition();
glm::vec2 getScreenSpaceDimensions();
glm::vec2 getUpperRightCornerScreenSpace();
glm::vec2 getLowerLeftCornerScreenSpace();
glm::vec2 screenSpacePosition();
glm::vec2 screenSpaceDimensions();
glm::vec2 upperRightCornerScreenSpace();
glm::vec2 lowerLeftCornerScreenSpace();
bool coordIsInsideCornersScreenSpace(glm::vec2 coord);
void translate(glm::vec2 translation, glm::vec2 position);
friend bool operator<(const ScreenSpaceRenderable& lhs, const ScreenSpaceRenderable& rhs);

View File

@@ -47,30 +47,35 @@ namespace openspace {
RenderableSkyBrowser(const ghoul::Dictionary& dictionary);
virtual ~RenderableSkyBrowser() = default;
// Inherited from RenderablePlane
void initializeGL() override;
void deinitializeGL() override;
void update(const UpdateData& data) override;
// Web page communication
void executeJavascript(std::string script) const;
bool sendMessageToWWT(const ghoul::Dictionary& msg);
void connectToWwt();
void stopConnectingToWwt();
void setIdInBrowser(std::string id);
// WorldWide Telescope communication
void displayImage(ImageData& image, int i);
void removeSelectedImage(ImageData& image, int i);
void setIdInBrowser(std::string id);
float fieldOfView() const;
std::deque<int>& selectedImages();
bool sendMessageToWwt(const ghoul::Dictionary& msg);
void syncWwtView();
void stopSyncingWwtView();
// Getters
float verticalFov() const;
std::deque<int>& getSelectedImages();
// Setters
void setImageLayerOrder(int i, int order, int version);
protected:
properties::Vec2Property _dimensions;
std::unique_ptr<BrowserInstance> _browserInstance;
std::unique_ptr<ghoul::opengl::Texture> _texture;
private:
// Properties
properties::Vec2Property _dimensions;
properties::StringProperty _url;
properties::TriggerProperty _reload;
class ScreenSpaceRenderHandler : public WebRenderHandler {
public:
void draw() override;
@@ -79,23 +84,21 @@ namespace openspace {
void setTexture(GLuint t);
};
CefRefPtr<ScreenSpaceRenderHandler> _renderHandler;
void bindTexture() override;
properties::StringProperty _url;
properties::TriggerProperty _reload;
// Browser variables
std::unique_ptr<BrowserInstance> _browserInstance;
std::unique_ptr<ghoul::opengl::Texture> _texture;
CefRefPtr<ScreenSpaceRenderHandler> _renderHandler;
CefRefPtr<WebKeyboardHandler> _keyboardHandler;
// Flags
bool _isUrlDirty = false;
bool _isDimensionsDirty = false;
bool _syncViewWithWwt;
float _fov;
bool _connectToWwt;
float _verticalFov;
std::thread _threadWwtMessages;
std::deque<int> _selectedImages;
};
}

View File

@@ -13,63 +13,88 @@ namespace openspace {
class ScreenSpaceSkyBrowser : public ScreenSpaceBrowser
{
public:
// Constructor and destructor
ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary);
virtual ~ScreenSpaceSkyBrowser();
// Inherited functions
bool initializeGL() override;
bool deinitializeGL() override;
bool setConnectedTarget();
glm::mat4 scaleMatrix() override;
// Target - browser connection
bool connectToSkyTarget();
void initializeBrowser();
void setIdInBrowser();
// Getters returning values
bool hasLoadedImages() const;
glm::vec2 browserPixelDimensions() const;
glm::ivec3 borderColor() const;
float verticalFov() const;
// Communication with the webpage and WWT
void executeJavascript(std::string script) const;
bool sendMessageToWWT(const ghoul::Dictionary& msg);
void WWTfollowCamera();
float fieldOfView() const;
void setVerticalFieldOfView(float fov);
void scrollZoom(float scroll);
// Getters returning references
ScreenSpaceSkyTarget* getSkyTarget();
bool hasLoadedCollections();
void setHasLoadedCollections(bool isLoaded);
std::deque<int>& getSelectedImages();
properties::FloatProperty& getOpacity();
std::deque<int>& selectedImages();
// Setters
void setHasLoadedImages(bool isLoaded);
void setVerticalFov(float vfov);
void setVerticalFovWithScroll(float scroll);
void setScale(glm::vec2 scalingFactor);
void setScale(float scalingFactor);
void setWebpageBorderColor(glm::ivec3 color);
// Communication with the web page
void executeJavascript(std::string script);
void sendIdToBrowser();
// Communication with WorldWide Telescope
void addSelectedImage(ImageData& image, int i);
void removeSelectedImage(ImageData& image, int i);
void setImageLayerOrder(int i, int order, int version);
void setImageOrder(int i, int order, int version);
void sendMessageToWwt(const ghoul::Dictionary& msg);
void syncWwtView();
// Mouse interaction with the browser. Returns 1 or -1 at the coordinate in
// image if the mouse is on a side of the browser
// __1__
// y| -1 |_____|1
// |__x -1
glm::vec2 isOnResizeArea(glm::vec2 screenSpaceCoord);
// Resize functions
void saveResizeStartSize();
void updateBrowserSize();
// Translation
//void translate(glm::vec2 translation);
// Position and dimension and corners
glm::vec2 getBrowserPixelDimensions();
glm::vec2 coordIsOnResizeArea(glm::vec2 coord);
// Scaling
void scale(glm::vec2 scalingFactor);
void scale(float scalingFactor);
glm::mat4 scaleMatrix() override;
// Resizing
void saveResizeStartSize();
void updateBrowserSize();
void setBorderColor(glm::ivec3 addColor);
glm::ivec3 getColor();
// Flag for dimensions
bool _browserDimIsDirty;
properties::FloatProperty _vfieldOfView;
properties::StringProperty _skyTargetID;
properties::Vec3Property _borderColor;
private:
glm::vec2 _startDimensionsSize;
float _startScale;
// Properties
properties::FloatProperty _verticalFov;
properties::StringProperty _skyTargetId;
properties::Vec2Property _browserDimensions;
bool _camIsSyncedWWT;
ScreenSpaceSkyTarget* _skyTarget;
std::thread _threadWWTMessages;
// For capping the calls to change the zoom from scrolling
constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 };
std::chrono::system_clock::time_point _lastUpdateTime;
bool _hasLoadedCollections{ false };
properties::Vec3Property _borderColor;
// Flags
bool _hasLoadedImages{ false };
bool _syncViewWithWwt{ false };
// Resizing of browser
glm::vec2 _originalDimensions;
float _originalScale;
float _resizeAreaPercentage{ 0.1f };
// Target & images
ScreenSpaceSkyTarget* _skyTarget{ nullptr };
std::thread _threadWwtMessages;
std::deque<int> _selectedImages;
// Time variables
// For capping the calls to change the zoom from scrolling
constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 };
std::chrono::system_clock::time_point _lastUpdateTime;
};
}

View File

@@ -19,64 +19,77 @@ namespace openspace {
class ScreenSpaceSkyTarget : public ScreenSpaceRenderable {
public:
// Constructor & destructor
ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary);
virtual ~ScreenSpaceSkyTarget();
// ScreenSpaceRenderable inherited functions
bool initializeGL() override;
bool isReady() const override;
void render() override;
glm::mat4 scaleMatrix() override;
void bindTexture() override; // Empty function but has to be defined
void createShaders();
void initializeWithBrowser();
// Sky browser functionality
bool findSkyBrowser();
void matchAppearanceToSkyBrowser();
// Getters
ScreenSpaceSkyBrowser* getSkyBrowser();
void setVerticalFOV(float VFOV);
glm::ivec3 borderColor() const;
float opacity() const;
// Setters
void setScale(float verticalFov);
void setDimensions(glm::vec2 dimensions);
void setColor(glm::ivec3 color);
glm::ivec3 getColor();
properties::FloatProperty& getOpacity();
void setOpacity(float opacity);
// Target directions
glm::dvec3 getTargetDirectionGalactic();
glm::dvec2 getTargetDirectionCelestial();
glm::dvec3 targetDirectionGalactic() const;
glm::dvec3 targetDirectionEquatorial() const;
// Locking functionality
void unlock();
void lock();
void unlock();
bool isLocked();
// Animations
void startAnimation(glm::dvec2 coordsEnd, float FOVEnd, bool lockAfterwards = true);
void animateToCoord(double deltaTime);
bool animateToFOV(float endFOV, float deltaTime);
void startAnimation(glm::dvec3 coordsEnd, float FOVEnd, bool lockAfter = true);
void animateToCoordinate(double deltaTime);
bool animateToFov(float endFOV, float deltaTime);
properties::StringProperty _skyBrowserID;
private:
// Properties
properties::StringProperty _skyBrowserId;
properties::FloatProperty _showCrosshairThreshold;
properties::FloatProperty _showRectangleThreshold;
private:
// Flags
bool _isAnimated{ false };
bool _lockAfterAnimation{ false };
bool _isLocked{ false };
// Shader
UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth, dimensions, lineColor) _uniformCache;
GLuint _vertexArray = 0;
GLuint _vertexBuffer = 0;
glm::ivec3 _color;
float _verticalFOV = 100.f;
ScreenSpaceSkyBrowser* _skyBrowser;
// Locking target to a coordinate on the sky
bool _isLocked;
glm::dvec2 _lockedCoords; // Spherical celestial coords
std::thread _lockTargetThread;
// Sky browser
ScreenSpaceSkyBrowser* _skyBrowser;
glm::ivec3 _color;
// Lock target to a coordinate on the sky
glm::dvec3 _lockedCoordinates; // Spherical celestial coordinates
std::thread _lockTarget;
// Animating the target
bool _isAnimated = false;
glm::dvec3 _coordsEndAnimation; // Cartesian celestial coords
glm::dvec3 _coordsStartAnimation; // Cartesian celestial coords
// Animation of target
glm::dvec3 _animationEnd; // Cartesian celestial coordinates
glm::dvec3 _animationStart; // Cartesian celestial coordinates
double _animationTime = 1.0;
float _FOVEndAnimation;
bool _lockAfterAnimation;
float _vfovEndAnimation;
};
}

View File

@@ -10,45 +10,49 @@
namespace openspace {
namespace skybrowser {
const double SCREENSPACE_Z = -2.1;
const double RAD_TO_DEG = 180.0 / M_PI;
const double DEG_TO_RAD = M_PI / 180.0;
const glm::dvec3 NORTH_POLE = { 0.0 , 0.0 , 1.0 };
constexpr double infinity = std::numeric_limits<float>::max();
// Constants
constexpr const double ScreenSpaceZ = -2.1;
constexpr const glm::dvec3 NorthPole = { 0.0 , 0.0 , 1.0 };
constexpr const double CelestialSphereRadius = std::numeric_limits<float>::max();
// Conversion matrix from this paper: https://arxiv.org/abs/1010.3773v1
// Conversion matrix - J2000 equatorial <-> galactic
// https://arxiv.org/abs/1010.3773v1
const glm::dmat3 conversionMatrix = glm::dmat3({
-0.054875539390, 0.494109453633, -0.867666135681, // col 0
-0.873437104725, -0.444829594298, -0.198076389622, // col 1
-0.483834991775, 0.746982248696, 0.455983794523 // col 2
});
// J2000 to galactic conversion and vice versa
glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords);
glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords);
glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal);
glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal);
glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords);
glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords,
double distance = infinity);
glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords,
double distance = infinity);
// Convert J2000, spherical or Cartesian, to screen space
glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords);
glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords);
glm::dvec3 galacticToScreenSpace(glm::dvec3 galacticCoord);
double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld);
glm::dvec3 cameraDirectionJ2000Cartesian();
// Conversion spherical <-> Cartesian
glm::dvec2 cartesianToSpherical(glm::dvec3 coords);
glm::dvec3 sphericalToCartesian(glm::dvec2 coords);
// Conversion J2000 equatorial <-> galactic
glm::dvec3 galacticToEquatorial(glm::dvec3 coords);
glm::dvec3 galacticToCameraLocal(glm::dvec3 coords);
glm::dvec3 equatorialToGalactic(glm::dvec3 coords);
// Conversion J2000 equatorial / galactic <-> screen space
glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords);
glm::dvec3 galacticToScreenSpace(glm::dvec3 coords);
glm::dvec3 screenSpaceToGalactic(glm::dvec3 coords);
glm::dvec3 screenSpaceToEquatorial(glm::dvec3 coords);
// Camera roll and direction
// Camera roll is with respect to the equatorial North Pole
double cameraRoll();
glm::dvec3 cameraDirectionGalactic();
glm::dvec3 cameraDirectionEquatorial();
}
// WorldWide Telescope messages
namespace wwtmessage {
// WWT messages
ghoul::Dictionary moveCamera(const glm::dvec2 celestCoords,
const double fov, const double roll, const bool moveInstantly = true);
ghoul::Dictionary loadCollection(const std::string& url);
ghoul::Dictionary setForeground(const std::string& name);
ghoul::Dictionary createImageLayer(const std::string& id, const std::string& url);
ghoul::Dictionary removeImageLayer(const std::string& id);
ghoul::Dictionary setLayerOpacity(const std::string& id, double opacity);
ghoul::Dictionary addImage(const std::string& id, const std::string& url);
ghoul::Dictionary removeImage(const std::string& id);
ghoul::Dictionary setImageOpacity(const std::string& id, double opacity);
ghoul::Dictionary setForegroundOpacity(double val);
ghoul::Dictionary setLayerOrder(const std::string& id, int order, int version);
}

View File

@@ -57,12 +57,12 @@ namespace openspace {
std::string name;
std::string thumbnailUrl;
std::string imageUrl;
std::string credits;
std::string creditsUrl;
glm::dvec2 celestCoords;
std::string credits;
glm::dvec2 celestialCoords;
std::string collection;
float fov;
bool hasCelestCoords{ false };
bool hasCelestialCoords{ false };
bool has3dCoords{ false };
glm::dvec3 position3d;
};
@@ -73,24 +73,31 @@ namespace openspace {
bool loaded = false;
};
class WWTDataHandler {
class WwtDataHandler {
public:
WWTDataHandler() = default;
~WWTDataHandler();
// Image downloading and xml parsing
bool downloadFile(std::string& url, std::string& fileDestination);
void loadWTMLCollectionsFromURL(std::string directory, std::string url, std::string fileName);
bool loadWTMLCollectionsFromDirectory(std::string directory);
int loadImagesFromLoadedXMLs();
// Constructor and destructor
WwtDataHandler() = default;
~WwtDataHandler();
// Image downloading and xml parsing
bool loadWtmlCollectionsFromUrl(std::string directory, std::string url,
std::string fileName);
bool loadWtmlCollectionsFromDirectory(std::string directory);
int loadImagesFromLoadedXmls();
// Loading speck files
void loadSpeckData(speck::Dataset& dataset);
// Getters
const std::vector<ImageCollection>& getAllImageCollectionUrls() const;
std::vector<ImageData>& getLoadedImages();
void loadSpeckData(speck::Dataset& dataset);
std::string createSearchableString(std::string name);
private:
void loadImagesFromXML(tinyxml2::XMLElement* node,
// Parsing and downloading of wtml files
bool downloadFile(std::string& url, std::string& fileDestination);
void loadImagesFromXml(tinyxml2::XMLElement* node,
std::string collectionName);
int loadImageFromXmlNode(tinyxml2::XMLElement* imageSet,
std::string collectionName);
@@ -105,17 +112,22 @@ namespace openspace {
std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet,
std::string elementName);
std::string getURLFromPlace(tinyxml2::XMLElement* place);
std::string getUrlFromPlace(tinyxml2::XMLElement* place);
tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node,
std::string name);
tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name);
std::vector<ImageData> images;
std::vector<ImageCollection> imageUrls;
std::vector<tinyxml2::XMLDocument*> xmls;
// Used for matching names
std::string createSearchableString(std::string name);
// Images
std::vector<ImageData> _images;
std::vector<ImageCollection> _imageUrls;
std::vector<tinyxml2::XMLDocument*> _xmls;
// 3D position data loaded from speck files
std::unordered_map<std::string, glm::dvec3> _3dPositions;
int nImagesWith3dPositions = 0;
int _nImagesWith3dPositions = 0;
};
}

View File

@@ -11,45 +11,45 @@ in vec4 vs_position;
// This compensates for the optical illusion that vertical lines appear thinner
#define VERTICAL_THICKNESS 1.15f
float line(in float _lineCenter, in float _lineWidth, in float _coord) {
float createLine(in float lineCenter, in float lineWidth, in float coord) {
// Calculate edges of line
float start_edge = _lineCenter - (_lineWidth * 0.5f);
float end_edge = _lineCenter + (_lineWidth * 0.5f);
float start_edge = lineCenter - (lineWidth * 0.5f);
float end_edge = lineCenter + (lineWidth * 0.5f);
// Create line
float line = step(start_edge, _coord) - step(end_edge, _coord);
float line = step(start_edge, coord) - step(end_edge, coord);
return line;
}
float rectangle(in float _linewidth_y, in float _ratio, in vec2 _coord) {
float createRectangle(in float linewidth_y, in float ratio, in vec2 coord) {
// Calculate the widths and centers for the lines
float linewidth_x = _linewidth_y * _ratio * VERTICAL_THICKNESS;
float linewidth_x = linewidth_y * ratio * VERTICAL_THICKNESS;
float linecenter_x = linewidth_x * 0.5f;
float linecenter_y = _linewidth_y * 0.5f;
float linecenter_y = linewidth_y * 0.5f;
// Create the four lines for the rectangle
float l = line(linecenter_x, linewidth_x, _coord.x);
float r = line(1.0f - linecenter_x, linewidth_x, _coord.x);
float b = line(linecenter_y, _linewidth_y, _coord.y);
float t = line(1.0f - linecenter_y, _linewidth_y, _coord.y);
float l = createLine(linecenter_x, linewidth_x, coord.x);
float r = createLine(1.0f - linecenter_x, linewidth_x, coord.x);
float b = createLine(linecenter_y, linewidth_y, coord.y);
float t = createLine(1.0f - linecenter_y, linewidth_y, coord.y);
// Add all lines together
return l + r + b + t;
}
float crosshair(in float _linewidth, in float _ratio, in vec2 _coord) {
float createCrosshair(in float linewidth, in float ratio, in vec2 coord) {
float center = 0.5f;
float crosshair_vertical = line(center, _linewidth * _ratio * VERTICAL_THICKNESS, _coord.x);
float crosshair_horizontal = line(center, _linewidth, _coord.y);
float crosshair_vertical = createLine(center, linewidth * ratio * VERTICAL_THICKNESS, coord.x);
float crosshair_horizontal = createLine(center, linewidth, coord.y);
return crosshair_horizontal + crosshair_vertical;
}
float filledRectangle(in float _size, in float _ratio, in vec2 _coord) {
float createFilledRectangle(in float size, in float ratio, in vec2 coord) {
float center = 0.5f;
float horizontal = line(center, _size, _coord.y);
float vertical = line(center, _size, _coord.x);
float horizontal = createLine(center, size, coord.y);
float vertical = createLine(center, size, coord.x);
return horizontal * vertical;
}
@@ -57,24 +57,24 @@ float filledRectangle(in float _size, in float _ratio, in vec2 _coord) {
#include "fragment.glsl"
Fragment getFragment() {
float _ratio = dimensions.y / dimensions.x;
float _crosshair = 0.0f;
float _rectangle = 0.0f;
float ratio = dimensions.y / dimensions.x;
float crosshair = 0.0f;
float rectangle = 0.0f;
if(showCrosshair) {
_crosshair = crosshair(lineWidth, _ratio, vs_st);
crosshair = createCrosshair(lineWidth, ratio, vs_st);
}
if(showRectangle) {
_rectangle = rectangle(lineWidth, _ratio, vs_st);
rectangle = createRectangle(lineWidth, ratio, vs_st);
}
// If both rectangle and crosshair are displayed, draw crosshair a bit smaller
if(showCrosshair && showRectangle) {
_crosshair *= filledRectangle(lineWidth * 7.0f, _ratio, vs_st);
crosshair *= createFilledRectangle(lineWidth * 7.0f, ratio, vs_st);
}
float result = clamp(_crosshair + _rectangle, 0.0, 1.0);
float result = clamp(crosshair + rectangle, 0.0, 1.0);
Fragment frag;
frag.color = lineColor;

View File

@@ -247,34 +247,37 @@ namespace openspace {
return res;
}
// Transforms a pixel coordinate to a screen space coordinate
glm::vec2 pixelToScreenSpace(glm::vec2& mouseCoordinate) {
glm::vec2 size = global::windowDelegate->currentWindowSize();
// Change origin to middle of the window
glm::vec2 screenSpacePos = glm::vec2((mouseCoordinate - (size / 2.0f)));
// Ensure the upper right corner is positive on the y axis
screenSpacePos *= glm::vec2(1.0f, -1.0f);
// Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio]
screenSpacePos /= (0.5f * size.y);
return screenSpacePos;
}
SkyBrowserModule::SkyBrowserModule()
: OpenSpaceModule(SkyBrowserModule::Name)
, _mouseOnObject(nullptr)
, currentlyResizingBrowser(false)
, currentlyDraggingObject(false)
, resizeVector(0.f, 0.f)
, changeViewWithinBrowser(false)
, _browser3d(nullptr)
, _layerOrderCounter(0)
, _cameraInSolarSystem(true)
, highlightAddition(35, 35, 35)
{
global::callback::mousePosition->emplace_back(
[&](double x, double y) {
glm::vec2 pos = glm::vec2(static_cast<float>(x), static_cast<float>(y));
_mousePosition = getMousePositionInScreenSpaceCoords(pos);
glm::vec2 pixel = glm::vec2(static_cast<float>(x), static_cast<float>(y));
_mousePosition = pixelToScreenSpace(pixel);
if (currentlyDraggingObject) {
if (_isDragging) {
glm::dvec2 move = _mousePosition - startDragMousePos;
glm::dvec2 move = _mousePosition - _startMousePosition;
// Change view within the browser and move target accordingly to mousedrag movement
if (changeViewWithinBrowser) {
// Change view within the browser and move target accordingly to mouse drag movement
if (_fineTuneMode) {
// WWT FOV
double WWTVerticalFOV = to_browser(_mouseOnObject)->fieldOfView();
glm::dvec2 browserDim = to_browser(_mouseOnObject)->getScreenSpaceDimensions();
double WWTVerticalFOV = toBrowser(_mouseOnObject)->verticalFov();
glm::dvec2 browserDim = toBrowser(_mouseOnObject)->screenSpaceDimensions();
double browserRatio = browserDim.x / browserDim.y;
glm::dvec2 WWTFOV = glm::dvec2(WWTVerticalFOV * browserRatio, WWTVerticalFOV);
@@ -291,24 +294,24 @@ SkyBrowserModule::SkyBrowserModule()
glm::dvec2 screenSpaceCoord{ (2 / windowRatio), 2.f };
glm::dvec2 result = screenSpaceCoord * OSresult;
to_browser(_mouseOnObject)->getSkyTarget()->translate(-result, startDragObjectPos);
toBrowser(_mouseOnObject)->getSkyTarget()->translate(-result, _startDragPosition);
}
// Move browser or target
else _mouseOnObject->translate(move, startDragObjectPos);
else _mouseOnObject->translate(move, _startDragPosition);
}
else if (currentlyResizingBrowser) {
else if (_isResizing) {
// Calculate scaling factor
glm::vec2 mouseDragVector = (_mousePosition - startDragMousePos);
glm::vec2 scalingVector = mouseDragVector * resizeVector;
glm::vec2 newSizeRelToOld = (startResizeBrowserSize + (scalingVector)) / startResizeBrowserSize;
glm::vec2 mouseDragVector = (_mousePosition - _startMousePosition);
glm::vec2 scalingVector = mouseDragVector * _resizeDirection;
glm::vec2 newSizeRelToOld = (_startBrowserSize + (scalingVector)) / _startBrowserSize;
// Scale the browser
to_browser(_mouseOnObject)->scale(newSizeRelToOld);
toBrowser(_mouseOnObject)->setScale(newSizeRelToOld);
// For dragging functionality, translate so it looks like the browser isn't moving
// Make sure the browser doesn't move in directions it's not supposed to
_mouseOnObject->translate(mouseDragVector * abs(resizeVector) / 2.f, startDragObjectPos);
_mouseOnObject->translate(mouseDragVector * abs(_resizeDirection) / 2.f, _startDragPosition);
}
// If there is no dragging or resizing, look for new objects
else {
@@ -316,27 +319,27 @@ SkyBrowserModule::SkyBrowserModule()
ScreenSpaceRenderable* lastObj = _mouseOnObject;
// Find and save what mouse is currently hovering on
auto currentlyOnObject = std::find_if(renderables.begin(), renderables.end(), [&](ScreenSpaceRenderable* obj) {
auto currentlyOnObject = std::find_if(_renderables.begin(), _renderables.end(), [&](ScreenSpaceRenderable* obj) {
return obj && (obj->coordIsInsideCornersScreenSpace(_mousePosition) && obj->isEnabled());
});
_mouseOnObject = currentlyOnObject != renderables.end() ? *currentlyOnObject : nullptr;
_mouseOnObject = currentlyOnObject != _renderables.end() ? *currentlyOnObject : nullptr;
// Selection has changed
if (lastObj != _mouseOnObject) {
// Remove highlight
if (to_browser(lastObj)) {
to_browser(lastObj)->setBorderColor(to_browser(lastObj)->getColor() - highlightAddition);
if (toBrowser(lastObj)) {
toBrowser(lastObj)->setWebpageBorderColor(toBrowser(lastObj)->borderColor() - _highlightAddition);
}
else if (to_target(lastObj)) {
to_target(lastObj)->setColor(to_target(lastObj)->getColor() - highlightAddition);
else if (toTarget(lastObj)) {
toTarget(lastObj)->setColor(toTarget(lastObj)->borderColor() - _highlightAddition);
}
// Add highlight
if (to_browser(_mouseOnObject)) {
to_browser(_mouseOnObject)->setBorderColor(to_browser(_mouseOnObject)->getColor() + highlightAddition);
if (toBrowser(_mouseOnObject)) {
toBrowser(_mouseOnObject)->setWebpageBorderColor(toBrowser(_mouseOnObject)->borderColor() + _highlightAddition);
}
else if (to_target(_mouseOnObject)) {
to_target(_mouseOnObject)->setColor(to_target(_mouseOnObject)->getColor() + highlightAddition);
else if (toTarget(_mouseOnObject)) {
toTarget(_mouseOnObject)->setColor(toTarget(_mouseOnObject)->borderColor() + _highlightAddition);
}
}
@@ -348,12 +351,12 @@ SkyBrowserModule::SkyBrowserModule()
[&](double, double scroll) -> bool {
// If mouse is on browser or target, apply zoom
if (to_browser(_mouseOnObject)) {
to_browser(_mouseOnObject)->scrollZoom(static_cast<float>(scroll));
if (toBrowser(_mouseOnObject)) {
toBrowser(_mouseOnObject)->setVerticalFovWithScroll(static_cast<float>(scroll));
return true;
}
else if (to_target(_mouseOnObject) && to_target(_mouseOnObject)->getSkyBrowser()) {
to_target(_mouseOnObject)->getSkyBrowser()->scrollZoom(static_cast<float>(scroll));
else if (toTarget(_mouseOnObject) && toTarget(_mouseOnObject)->getSkyBrowser()) {
toTarget(_mouseOnObject)->getSkyBrowser()->setVerticalFovWithScroll(static_cast<float>(scroll));
}
return false;
@@ -366,62 +369,62 @@ SkyBrowserModule::SkyBrowserModule()
if (_mouseOnObject && action == MouseAction::Press) {
// Get the currently selected browser
if (to_browser(_mouseOnObject)) {
setSelectedBrowser(to_browser(_mouseOnObject));
if (toBrowser(_mouseOnObject)) {
setSelectedBrowser(toBrowser(_mouseOnObject));
}
else if (to_target(_mouseOnObject) &&
to_target(_mouseOnObject)->getSkyBrowser()) {
else if (toTarget(_mouseOnObject) &&
toTarget(_mouseOnObject)->getSkyBrowser()) {
setSelectedBrowser(to_target(_mouseOnObject)->getSkyBrowser());
setSelectedBrowser(toTarget(_mouseOnObject)->getSkyBrowser());
}
if (button == MouseButton::Left) {
isRotating = false;
startDragMousePos = _mousePosition;
startDragObjectPos = _mouseOnObject->getScreenSpacePosition();
_isRotating = false;
_startMousePosition = _mousePosition;
_startDragPosition = _mouseOnObject->screenSpacePosition();
// If current object is browser, check for resizing
if (to_browser(_mouseOnObject)) {
if (toBrowser(_mouseOnObject)) {
// Resize browser if mouse is over resize button
resizeVector = to_browser(_mouseOnObject)->coordIsOnResizeArea(_mousePosition);
if (resizeVector != glm::vec2{ 0 }) {
to_browser(_mouseOnObject)->saveResizeStartSize();
startResizeBrowserSize = to_browser(_mouseOnObject)->getScreenSpaceDimensions();
currentlyResizingBrowser = true;
_resizeDirection = toBrowser(_mouseOnObject)->isOnResizeArea(_mousePosition);
if (_resizeDirection != glm::vec2{ 0 }) {
toBrowser(_mouseOnObject)->saveResizeStartSize();
_startBrowserSize = toBrowser(_mouseOnObject)->screenSpaceDimensions();
_isResizing = true;
return true;
}
}
// If you start dragging around the target, it should unlock
if (to_target(_mouseOnObject)) {
to_target(_mouseOnObject)->unlock();
if (toTarget(_mouseOnObject)) {
toTarget(_mouseOnObject)->unlock();
}
currentlyDraggingObject = true;
_isDragging = true;
return true;
}
else if (to_browser(_mouseOnObject) && button == MouseButton::Right) {
else if (toBrowser(_mouseOnObject) && button == MouseButton::Right) {
// If you start dragging around on the browser, the target should unlock
if (to_browser(_mouseOnObject) && to_browser(_mouseOnObject)->getSkyTarget()) {
to_browser(_mouseOnObject)->getSkyTarget()->unlock();
if (toBrowser(_mouseOnObject) && toBrowser(_mouseOnObject)->getSkyTarget()) {
toBrowser(_mouseOnObject)->getSkyTarget()->unlock();
}
// Change view (by moving target) within browser if right mouse click on browser
startDragMousePos = _mousePosition;
startDragObjectPos = to_browser(_mouseOnObject)->getSkyTarget()->getScreenSpacePosition();
changeViewWithinBrowser = true;
currentlyDraggingObject = true;
_startMousePosition = _mousePosition;
_startDragPosition = toBrowser(_mouseOnObject)->getSkyTarget()->screenSpacePosition();
_fineTuneMode = true;
_isDragging = true;
return true;
}
}
else if (action == MouseAction::Release) {
if (currentlyDraggingObject) {
currentlyDraggingObject = false;
changeViewWithinBrowser = false;
if (_isDragging) {
_isDragging = false;
_fineTuneMode = false;
return true;
}
if (currentlyResizingBrowser) {
currentlyResizingBrowser = false;
to_browser(_mouseOnObject)->updateBrowserSize();
if (_isResizing) {
_isResizing = false;
toBrowser(_mouseOnObject)->updateBrowserSize();
return true;
}
}
@@ -440,7 +443,7 @@ SkyBrowserModule::SkyBrowserModule()
double deltaTime = global::windowDelegate->deltaTime();
// Fade out or in browser & target
for (std::pair<std::string, ScreenSpaceSkyBrowser*> pair : browsers) {
for (std::pair<std::string, ScreenSpaceSkyBrowser*> pair : _browsers) {
ScreenSpaceSkyBrowser* browser = pair.second;
// If outside solar system and browser is visible
if (!_cameraInSolarSystem && browser->isEnabled()) {
@@ -450,7 +453,7 @@ SkyBrowserModule::SkyBrowserModule()
browser->property("Enabled")->set(false);
// Select the 3D browser when moving out of the solar system
if (_browser3d != nullptr) {
selectedBrowser = _browser3d->renderable()->identifier();
_selectedBrowser = _browser3d->renderable()->identifier();
}
}
}
@@ -458,8 +461,8 @@ SkyBrowserModule::SkyBrowserModule()
else if (_cameraInSolarSystem && !browser->isEnabled()) {
browser->property("Enabled")->set(true);
// Select the first 2D browser when moving into the solar system
if (browsers.size() != 0) {
selectedBrowser = std::begin(browsers)->second->identifier();
if (_browsers.size() != 0) {
_selectedBrowser = std::begin(_browsers)->second->identifier();
}
}
// If within solar system and browser is visible
@@ -467,18 +470,18 @@ SkyBrowserModule::SkyBrowserModule()
fadeBrowserAndTarget(false, fadingTime, deltaTime);
if (browser->getSkyTarget()) {
browser->getSkyTarget()->animateToCoord(deltaTime);
browser->getSkyTarget()->animateToCoordinate(deltaTime);
}
}
}
if (isRotating) {
if (_isRotating) {
rotateCamera(deltaTime);
}
});
}
SkyBrowserModule::~SkyBrowserModule() {
delete dataHandler;
delete _dataHandler;
}
void SkyBrowserModule::internalDeinitialize() {
@@ -502,37 +505,26 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) {
fRenderable->registerClass<RenderableSkyBrowser>("RenderableSkyBrowser");
// Create data handler dynamically to avoid the linking error that
// came up when including the include file in the module header file
dataHandler = new WWTDataHandler();
_dataHandler = new WwtDataHandler();
}
glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) {
glm::vec2 size = global::windowDelegate->currentWindowSize();
// Change origin to middle of the window
glm::vec2 screenSpacePos = glm::vec2((mousePos - (size / 2.0f)));
// Ensure the upper right corner is positive on the y axis
screenSpacePos *= glm::vec2(1.0f, -1.0f);
// Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio]
screenSpacePos /= (0.5f*size.y);
return screenSpacePos;
}
int SkyBrowserModule::getAndIncrementLayerOrder() {
return _layerOrderCounter++;
int SkyBrowserModule::getAndIncrementMessageOrder() {
return _messageOrder++;
}
void SkyBrowserModule::addRenderable(ScreenSpaceRenderable* object) {
renderables.push_back(object);
_renderables.push_back(object);
// Sort on z coordinate, objects closer to camera are in beginning of list
std::sort(renderables.begin(), renderables.end());
ScreenSpaceSkyBrowser* browser = to_browser(object);
std::sort(_renderables.begin(), _renderables.end());
ScreenSpaceSkyBrowser* browser = toBrowser(object);
if (browser) {
browsers[browser->identifier()] = browser;
_browsers[browser->identifier()] = browser;
}
}
bool SkyBrowserModule::browserIdExists(std::string id) {
// If the id doesn't exist, return false
if (browsers.find(id) == browsers.end()) {
if (_browsers.find(id) == _browsers.end()) {
return false;
}
return true;
@@ -605,7 +597,7 @@ void SkyBrowserModule::createTargetBrowserPair() {
void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) {
if (!browserIdExists(browserId)) return;
ScreenSpaceSkyBrowser* browser = browsers[browserId];
ScreenSpaceSkyBrowser* browser = _browsers[browserId];
// Find corresponding target
std::string targetId{ "" };
@@ -614,10 +606,10 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) {
targetId = browser->getSkyTarget()->identifier();
}
// Remove pointer to the renderable from browsers vector
browsers.erase(browserId);
_browsers.erase(browserId);
// Remove pointer to the renderable from screenspace renderable vector
renderables.erase(std::remove_if(std::begin(renderables), std::end(renderables),
_renderables.erase(std::remove_if(std::begin(_renderables), std::end(_renderables),
[&](ScreenSpaceRenderable* renderable) {
if (renderable->identifier() == browserId) {
return true;
@@ -628,7 +620,7 @@ void SkyBrowserModule::removeTargetBrowserPair(std::string& browserId) {
else {
return false;
}
}), std::end(renderables));
}), std::end(_renderables));
// Remove from engine
openspace::global::scriptEngine->queueScript(
"openspace.removeScreenSpaceRenderable('" + browserId + "');",
@@ -661,7 +653,7 @@ void SkyBrowserModule::place3dBrowser(ImageData& image) {
// /_| Adjacent is the horizontal line, opposite the vertical
// \ | Calculate for half the triangle first, then multiply with 2
// \|
glm::dvec3 j2000 = skybrowser::galacticCartesianToJ2000Cartesian(position);
glm::dvec3 j2000 = skybrowser::galacticToEquatorial(position);
double adjacent = glm::length(j2000);
double opposite = 2 * adjacent * glm::tan(glm::radians(image.fov * 0.5));
@@ -698,23 +690,23 @@ void SkyBrowserModule::set3dBrowser(SceneGraphNode* node) {
_browser3d = node;
}
ScreenSpaceSkyBrowser* SkyBrowserModule::to_browser(ScreenSpaceRenderable* ptr) {
ScreenSpaceSkyBrowser* SkyBrowserModule::toBrowser(ScreenSpaceRenderable* ptr) {
return dynamic_cast<ScreenSpaceSkyBrowser*>(ptr);
}
ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) {
ScreenSpaceSkyTarget* SkyBrowserModule::toTarget(ScreenSpaceRenderable* ptr) {
return dynamic_cast<ScreenSpaceSkyTarget*>(ptr);
}
WWTDataHandler* SkyBrowserModule::getWWTDataHandler() {
return dataHandler;
WwtDataHandler* SkyBrowserModule::getWWTDataHandler() {
return _dataHandler;
}
std::map<std::string, ScreenSpaceSkyBrowser*>& SkyBrowserModule::getSkyBrowsers() {
return browsers;
return _browsers;
}
std::vector<ScreenSpaceRenderable*>& SkyBrowserModule::getBrowsersAndTargets() {
return renderables;
return _renderables;
}
SceneGraphNode* SkyBrowserModule::get3dBrowser() {
@@ -738,35 +730,32 @@ void SkyBrowserModule::lookAt3dBrowser() {
);
}
void SkyBrowserModule::startRotation(glm::dvec2 coordsEnd) {
void SkyBrowserModule::startRotation(glm::dvec3 endAnimation) {
// Save coordinates to rotate to in galactic world coordinates
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
_coordsToAnimateTo = skybrowser::J2000SphericalToGalacticCartesian(coordsEnd);
_coordsStartAnimation = (global::navigationHandler->camera()->viewDirectionWorldSpace() * skybrowser::infinity) + camPos;
isRotating = true;
_endAnimation = endAnimation;
_startAnimation = skybrowser::cameraDirectionGalactic();
_isRotating = true;
}
void SkyBrowserModule::rotateCamera(double deltaTime) {
// Find smallest angle between the two vectors
double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsToAnimateTo) / (glm::length(_coordsStartAnimation) * glm::length(_coordsToAnimateTo)));
double smallestAngle = std::acos(glm::dot(_startAnimation, _endAnimation) / (glm::length(_startAnimation) * glm::length(_endAnimation)));
// Only keep animating when target is not at final position
if (abs(smallestAngle) > 0.0001) {
// Calculate rotation this frame
double rotationAngle = smallestAngle * deltaTime;
// Create the rotation matrix for local camera space
glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsToAnimateTo));
glm::dvec3 rotationAxis = glm::normalize(glm::cross(_startAnimation, _endAnimation));
glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis);
// Rotate
global::navigationHandler->camera()->rotate(glm::quat_cast(rotmat));
// Update camera direction
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
_coordsStartAnimation = (global::navigationHandler->camera()->viewDirectionWorldSpace() * skybrowser::infinity) + camPos;
_startAnimation = skybrowser::cameraDirectionGalactic();
}
else {
isRotating = false;
_isRotating = false;
}
}
@@ -780,17 +769,18 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim
opacityDelta *= -1.f;
}
bool finished = true;
for (std::pair <std::string, ScreenSpaceSkyBrowser*> idAndBrowser : browsers) {
for (std::pair <std::string, ScreenSpaceSkyBrowser*> idAndBrowser : _browsers) {
ScreenSpaceSkyBrowser* browser = idAndBrowser.second;
// If there is a target, fade it as well. Otherwise, skip
ScreenSpaceSkyTarget* target = browser->getSkyTarget();
bool targetFinished = true;
if (target) {
target->getOpacity() = target->getOpacity().value() + opacityDelta;
float opacityTarget = abs(target->getOpacity().value());
target->setOpacity(target->opacity() + opacityDelta);
float opacityTarget = abs(target->opacity());
targetFinished = makeTransparent ? opacityTarget < lowThreshold : opacityTarget > highTreshold;
if (targetFinished) {
target->getOpacity() = makeTransparent ? transparent : opaque;
float newOpacity = makeTransparent ? transparent : opaque;
target->setOpacity(newOpacity);
}
}
// Keep fading the browsers until all are finished
@@ -809,16 +799,16 @@ bool SkyBrowserModule::fadeBrowserAndTarget(bool makeTransparent, double fadeTim
void SkyBrowserModule::setSelectedBrowser(ScreenSpaceSkyBrowser* browser) {
if (browser) {
selectedBrowser = browser->identifier();
_selectedBrowser = browser->identifier();
}
}
void SkyBrowserModule::setSelectedBrowser(std::string id) {
selectedBrowser = id;
_selectedBrowser = id;
}
std::string SkyBrowserModule::selectedBrowserId() {
return selectedBrowser;
return _selectedBrowser;
}
int SkyBrowserModule::loadImages(const std::string& root, const std::string& directory) {
@@ -830,13 +820,13 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir
speck::Dataset speckGlobularClusters = speck::loadSpeckFile(globularClusters);
speck::Dataset speckOpenClusters = speck::loadSpeckFile(openClusters);
dataHandler->loadSpeckData(speckGlobularClusters);
dataHandler->loadSpeckData(speckOpenClusters);
_dataHandler->loadSpeckData(speckGlobularClusters);
_dataHandler->loadSpeckData(speckOpenClusters);
int nLoadedImages;
// Read from disc
bool loadedImages = dataHandler->loadWTMLCollectionsFromDirectory(directory);
bool loadedImages = _dataHandler->loadWtmlCollectionsFromDirectory(directory);
// Reading from url if there is no directory
if (loadedImages) {
@@ -844,10 +834,10 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir
}
else {
LINFO("Loading images from url");
dataHandler->loadWTMLCollectionsFromURL(directory, root, "root");
_dataHandler->loadWtmlCollectionsFromUrl(directory, root, "root");
}
nLoadedImages = dataHandler->loadImagesFromLoadedXMLs();
nLoadedImages = _dataHandler->loadImagesFromLoadedXmls();
LINFO("Loaded " + std::to_string(nLoadedImages) + " WorldWide Telescope images.");
return nLoadedImages;
@@ -856,12 +846,12 @@ int SkyBrowserModule::loadImages(const std::string& root, const std::string& dir
bool SkyBrowserModule::cameraInSolarSystem() {
return _cameraInSolarSystem;
}
/*
std::vector<documentation::Documentation> SkyBrowserModule::documentations() const {
return {
ExoplanetsDataPreparationTask::documentation(),
RenderableOrbitDisc::Documentation()
};
}
*/
//std::vector<documentation::Documentation> SkyBrowserModule::documentations() const {
// return {
// ExoplanetsDataPreparationTask::documentation(),
// RenderableOrbitDisc::Documentation()
// };
//}
} // namespace openspace

View File

@@ -43,7 +43,7 @@ class ScreenSpaceSkyBrowser;
class ScreenSpaceSkyTarget;
class RenderableSkyBrowser;
class ScreenSpaceRenderable;
class WWTDataHandler;
class WwtDataHandler;
class SceneGraphNode;
class ImageData;
@@ -51,32 +51,42 @@ class ImageData;
class SkyBrowserModule : public OpenSpaceModule {
public:
constexpr static const char* Name = "SkyBrowser";
constexpr static const int FROM_DIRECTORY = 0;
constexpr static const int FROM_URL = 1;
// Constructor & destructor
SkyBrowserModule();
virtual ~SkyBrowserModule();
glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos);
void addRenderable(ScreenSpaceRenderable* object);
WWTDataHandler* getWWTDataHandler();
// Getters
std::map<std::string, ScreenSpaceSkyBrowser*>& getSkyBrowsers();
std::vector<ScreenSpaceRenderable*>& getBrowsersAndTargets();
SceneGraphNode* get3dBrowser();
void startRotation(glm::dvec2 coordsEnd);
void rotateCamera(double deltaTime);
bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime);
WwtDataHandler* getWWTDataHandler();
std::string selectedBrowserId();
// Setters
void setSelectedBrowser(ScreenSpaceSkyBrowser* ptr);
void setSelectedBrowser(std::string id);
bool browserIdExists(std::string id);
std::string selectedBrowserId();
int loadImages(const std::string& root, const std::string& directory);
void set3dBrowser(SceneGraphNode* node);
// Rotation and animation
void startRotation(glm::dvec3 endAnimation); // Pass in galactic coord
void rotateCamera(double deltaTime);
bool fadeBrowserAndTarget(bool makeTransparent, double fadeTime, double deltaTime);
void lookAt3dBrowser();
// Boolean functions
bool browserIdExists(std::string id);
bool cameraInSolarSystem();
// Managing the browsers
void createTargetBrowserPair();
void removeTargetBrowserPair(std::string& browserId);
void addRenderable(ScreenSpaceRenderable* object);
void place3dBrowser(ImageData& image);
void lookAt3dBrowser();
int getAndIncrementLayerOrder();
// Image collection handling
int loadImages(const std::string& root, const std::string& directory);
int getAndIncrementMessageOrder(); // For version handling calls to WWT
scripting::LuaLibrary luaLibrary() const override;
//std::vector<documentation::Documentation> documentations() const override;
@@ -84,43 +94,42 @@ public:
protected:
void internalInitialize(const ghoul::Dictionary& dict) override;
void internalDeinitialize() override;
// Using snake case on these casting functions to make them similar to eg std::to_string
ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr);
ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr);
private:
// Cast screen space renderable to either target or browser
ScreenSpaceSkyBrowser* toBrowser(ScreenSpaceRenderable* ptr);
ScreenSpaceSkyTarget* toTarget(ScreenSpaceRenderable* ptr);
// The browsers and targets
std::vector<ScreenSpaceRenderable*> renderables;
// Only the browsers
std::map<std::string, ScreenSpaceSkyBrowser*> browsers;
// 3D browser
SceneGraphNode* _browser3d;
// Pointer to what mouse is currently on
ScreenSpaceRenderable* _mouseOnObject;
// Dragging
glm::vec2 startDragMousePos;
glm::vec2 startDragObjectPos;
bool changeViewWithinBrowser;
// Resizing
glm::vec2 startResizeBrowserSize;
glm::vec2 resizeVector;
// The current mouse position in screenspace coordinates
glm::vec2 _mousePosition;
// Current interaction status
bool currentlyResizingBrowser;
bool currentlyDraggingObject;
// Data handler
WWTDataHandler* dataHandler;
// For animating rotation of camera to look at coordinate
glm::dvec3 _coordsToAnimateTo;
glm::dvec3 _coordsStartAnimation;
bool isRotating = false;
// For tracking the currently selected browser
std::string selectedBrowser;
glm::ivec3 highlightAddition;
// Mode of browsing
bool _cameraInSolarSystem;
int _layerOrderCounter;
std::vector<ScreenSpaceRenderable*> _renderables; // 2D browsers and targets
std::map<std::string, ScreenSpaceSkyBrowser*> _browsers; // Only the 2D browsers
ScreenSpaceRenderable* _mouseOnObject{ nullptr }; // Pointer to what mouse is currently on
SceneGraphNode* _browser3d{ nullptr };
std::string _selectedBrowser; // Currently selected browser (2D or 3D)
// Flags
bool _fineTuneMode{ false };
bool _isResizing{ false };
bool _isDragging{ false };
bool _cameraInSolarSystem{ true };
bool _isRotating = false;
// Mouse interaction - dragging and resizing
glm::vec2 _mousePosition; // Current mouse position in screen space coordinates
glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers
glm::vec2 _startMousePosition;
glm::vec2 _startDragPosition;
glm::vec2 _startBrowserSize;
glm::vec2 _resizeDirection{ 0.f };
// Animation of rotation of camera to look at coordinate galactic coordinates
glm::dvec3 _startAnimation;
glm::dvec3 _endAnimation;
// Data handler for the image collections
WwtDataHandler* _dataHandler;
int _messageOrder{ 0 }; // Version handler for WorldWide Telescope messages
};
} // namespace openspace

View File

@@ -53,12 +53,15 @@ namespace openspace::skybrowser::luascriptfunctions {
ScreenSpaceSkyTarget* selectedTarget = selectedBrowser->getSkyTarget();
// If the image has coordinates, move the target
if (image.hasCelestCoords && selectedTarget) {
if (image.hasCelestialCoords && selectedTarget) {
// Animate the target to the image coord position
selectedTarget->unlock();
selectedTarget->startAnimation(image.celestCoords, image.fov);
glm::dvec3 equatorial = skybrowser::sphericalToCartesian(image.celestialCoords);
selectedTarget->startAnimation(equatorial, image.fov);
// Check if image coordinate is within current FOV
glm::dvec3 coordsScreen = J2000SphericalToScreenSpace(image.celestCoords);
glm::dvec3 coordsScreen = equatorialToScreenSpace(equatorial);
glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
float r = windowRatio.x / windowRatio.y;
bool coordIsWithinView = (abs(coordsScreen.x) < r &&
@@ -66,7 +69,8 @@ namespace openspace::skybrowser::luascriptfunctions {
bool coordIsBehindCamera = coordsScreen.z > 0;
// If the coordinate is not in view, rotate camera
if (!coordIsWithinView || coordIsBehindCamera) {
module->startRotation(image.celestCoords);
glm::dvec3 galactic = skybrowser::equatorialToGalactic(equatorial);
module->startRotation(galactic);
}
}
}
@@ -95,13 +99,14 @@ namespace openspace::skybrowser::luascriptfunctions {
const ImageData& image = module->getWWTDataHandler()->getLoadedImages()[i];
// Only move and show circle if the image has coordinates
if (image.hasCelestCoords && module->cameraInSolarSystem()) {
if (image.hasCelestialCoords && module->cameraInSolarSystem()) {
// Make circle visible
ScreenSpaceImageLocal* hoverCircle = dynamic_cast<ScreenSpaceImageLocal*>(
global::renderEngine->screenSpaceRenderable("HoverCircle"));
hoverCircle->property("Enabled")->set(true);
// Calculate coords for the circle and translate
glm::vec3 coordsScreen = skybrowser::J2000SphericalToScreenSpace(image.celestCoords);
glm::dvec3 equatorialCartesian = skybrowser::sphericalToCartesian(image.celestialCoords);
glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace(equatorialCartesian);
hoverCircle->property("CartesianPosition")->set(coordsScreen);
}
@@ -152,12 +157,12 @@ namespace openspace::skybrowser::luascriptfunctions {
const int i = ghoul::lua::value<int>(L, 2);
int order = ghoul::lua::value<int>(L, 3);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
int version = module->getAndIncrementLayerOrder();
int version = module->getAndIncrementMessageOrder();
if (module->browserIdExists(browserId)) {
ScreenSpaceSkyBrowser* browser = module->getSkyBrowsers()[browserId];
browser->setImageLayerOrder(i, order, version);
browser->setImageOrder(i, order, version);
}
else if (module->get3dBrowser() != nullptr) {
RenderableSkyBrowser* browser3d = dynamic_cast<RenderableSkyBrowser*>(
@@ -180,9 +185,9 @@ namespace openspace::skybrowser::luascriptfunctions {
ScreenSpaceSkyBrowser* browser = dynamic_cast<ScreenSpaceSkyBrowser*>(
global::renderEngine->screenSpaceRenderable(id));
if (browser && !browser->hasLoadedCollections()) {
browser->sendMessageToWWT(wwtmessage::loadCollection(root));
browser->setHasLoadedCollections(true);
if (browser && !browser->hasLoadedImages()) {
browser->sendMessageToWwt(wwtmessage::loadCollection(root));
browser->setHasLoadedImages(true);
}
else {
SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(id);
@@ -191,9 +196,9 @@ namespace openspace::skybrowser::luascriptfunctions {
node->renderable());
if (browser3d) {
// Load Image collections
browser3d->stopConnectingToWwt();
browser3d->stopSyncingWwtView();
LINFO("Load images to " + browser3d->identifier());
browser3d->sendMessageToWWT(wwtmessage::loadCollection(root));
browser3d->sendMessageToWwt(wwtmessage::loadCollection(root));
LINFO("Image collection loaded in " + browser3d->identifier());
}
}
@@ -210,7 +215,7 @@ namespace openspace::skybrowser::luascriptfunctions {
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
std::map<std::string, ScreenSpaceSkyBrowser*> browsers = module->getSkyBrowsers();
for (std::pair<std::string, ScreenSpaceSkyBrowser*> pair : browsers) {
pair.second->setIdInBrowser();
pair.second->sendIdToBrowser();
}
SceneGraphNode* node = module->get3dBrowser();
if(node) {
@@ -228,15 +233,17 @@ namespace openspace::skybrowser::luascriptfunctions {
// Find the ScreenSpaceRenderable that has the id
ScreenSpaceRenderable* found = global::renderEngine->screenSpaceRenderable(id);
ScreenSpaceSkyBrowser* browser = dynamic_cast<ScreenSpaceSkyBrowser*>(found);
ScreenSpaceSkyTarget* target = dynamic_cast<ScreenSpaceSkyTarget*>(found);
// Connect it to its corresponding target / browser
if (dynamic_cast<ScreenSpaceSkyBrowser*>(found)) {
ScreenSpaceSkyBrowser* browser = dynamic_cast<ScreenSpaceSkyBrowser*>(found);
browser->setConnectedTarget();
if (browser) {
browser->connectToSkyTarget();
}
else if (dynamic_cast<ScreenSpaceSkyTarget*>(found)) {
ScreenSpaceSkyTarget* target = dynamic_cast<ScreenSpaceSkyTarget*>(found);
target->initializeWithBrowser();
else if (target) {
target->findSkyBrowser();
}
return 0;
}
@@ -247,12 +254,12 @@ namespace openspace::skybrowser::luascriptfunctions {
const std::string id = ghoul::lua::value<std::string>(L, 1);
ScreenSpaceSkyBrowser* browser = dynamic_cast<ScreenSpaceSkyBrowser*>(
global::renderEngine->screenSpaceRenderable(id));
LINFO("Initializing sky browsers");
LINFO("Initializing sky browser " + id);
if (browser) {
browser->initializeBrowser();
ScreenSpaceSkyTarget* target = browser->getSkyTarget();
if (target) {
target->initializeWithBrowser();
target->findSkyBrowser();
}
}
else {
@@ -263,7 +270,7 @@ namespace openspace::skybrowser::luascriptfunctions {
if (browser3d && id == node->identifier()) {
// Initialize
LINFO("Initializing 3D sky browsers");
browser3d->connectToWwt();
browser3d->syncWwtView();
}
}
}
@@ -315,7 +322,7 @@ namespace openspace::skybrowser::luascriptfunctions {
for (int i = 0; i < images.size(); i++) {
std::string name = images[i].name != "" ? images[i].name : "undefined";
std::string thumbnail = images[i].thumbnailUrl != "" ? images[i].thumbnailUrl : "undefined";
glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestCoords);
glm::dvec3 cartCoords = skybrowser::sphericalToCartesian(images[i].celestialCoords);
std::vector<double> cartCoordsVec = { cartCoords.x, cartCoords.y, cartCoords.z };
glm::dvec3 position = images[i].position3d;
std::vector<double> position3d = { position.x, position.y, position.z };
@@ -328,13 +335,13 @@ namespace openspace::skybrowser::luascriptfunctions {
lua_settable(L, -3);
ghoul::lua::push(L, "thumbnail", thumbnail);
lua_settable(L, -3);
ghoul::lua::push(L, "ra", images[i].celestCoords.x);
ghoul::lua::push(L, "ra", images[i].celestialCoords.x);
lua_settable(L, -3);
ghoul::lua::push(L, "dec", images[i].celestCoords.y);
ghoul::lua::push(L, "dec", images[i].celestialCoords.y);
lua_settable(L, -3);
ghoul::lua::push(L, "cartesianDirection", cartCoordsVec);
lua_settable(L, -3);
ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestCoords);
ghoul::lua::push(L, "hasCelestialCoords", images[i].hasCelestialCoords);
lua_settable(L, -3);
ghoul::lua::push(L, "credits", images[i].credits);
lua_settable(L, -3);
@@ -364,7 +371,7 @@ namespace openspace::skybrowser::luascriptfunctions {
// Add the window data for OpenSpace
ghoul::lua::push(L, "OpenSpace");
lua_newtable(L);
glm::dvec3 cartesianJ2000 = skybrowser::cameraDirectionJ2000Cartesian();
glm::dvec3 cartesianJ2000 = skybrowser::cameraDirectionEquatorial();
glm::dvec2 sphericalJ2000 = skybrowser::cartesianToSpherical(cartesianJ2000);
// Convert to vector so ghoul can read it
std::vector<double> viewDirCelestVec = { cartesianJ2000.x, cartesianJ2000.y, cartesianJ2000.z };
@@ -400,18 +407,19 @@ namespace openspace::skybrowser::luascriptfunctions {
std::string id = pair.first;
// Convert deque to vector so ghoul can read it
std::vector<int> selectedImagesVector;
std::deque<int> selectedImages = browser->selectedImages();
std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) {
selectedImagesVector.push_back(index);
std::deque<int> selectedImages = browser->getSelectedImages();
std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) {
selectedImagesVector.push_back(i);
});
// Only add browsers that have an initialized target
ScreenSpaceSkyTarget* target = browser->getSkyTarget();
if (target) {
glm::dvec2 celestialSpherical = target->getTargetDirectionCelestial();
glm::dvec3 celestialCart = skybrowser::sphericalToCartesian(celestialSpherical);
glm::dvec3 celestialCart = target->targetDirectionEquatorial();
glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart);
std::vector<double> celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z };
// Convert color to vector so ghoul can read it
glm::ivec3 color = browser->_borderColor.value();
glm::ivec3 color = browser->borderColor();
std::vector<int> colorVec = { color.r, color.g, color.b };
ghoul::lua::push(L, id);
@@ -421,7 +429,7 @@ namespace openspace::skybrowser::luascriptfunctions {
lua_settable(L, -3);
ghoul::lua::push(L, "name", browser->guiName());
lua_settable(L, -3);
ghoul::lua::push(L, "FOV", browser->fieldOfView());
ghoul::lua::push(L, "FOV", browser->verticalFov());
lua_settable(L, -3);
ghoul::lua::push(L, "selectedImages", selectedImagesVector);
lua_settable(L, -3);
@@ -447,12 +455,12 @@ namespace openspace::skybrowser::luascriptfunctions {
node->renderable());
// Convert deque to vector so ghoul can read it
std::vector<int> selectedImagesVector;
std::deque<int> selectedImages = browser3d->selectedImages();
std::deque<int> selectedImages = browser3d->getSelectedImages();
std::for_each(selectedImages.begin(), selectedImages.end(), [&](int index) {
selectedImagesVector.push_back(index);
});
glm::dvec3 worldPosition = node->position();
glm::dvec3 celestialCart = skybrowser::galacticCartesianToJ2000Cartesian(worldPosition);
glm::dvec3 celestialCart = skybrowser::galacticToEquatorial(worldPosition);
glm::dvec2 celestialSpherical = skybrowser::cartesianToSpherical(celestialCart);
std::vector<double> celestialCartVec = { celestialCart.x, celestialCart.y, celestialCart.z };
// Convert color to vector so ghoul can read it
@@ -466,7 +474,7 @@ namespace openspace::skybrowser::luascriptfunctions {
lua_settable(L, -3);
ghoul::lua::push(L, "name", node->guiName());
lua_settable(L, -3);
ghoul::lua::push(L, "FOV", browser3d->fieldOfView());
ghoul::lua::push(L, "FOV", browser3d->verticalFov());
lua_settable(L, -3);
ghoul::lua::push(L, "selectedImages", selectedImagesVector);
lua_settable(L, -3);
@@ -496,7 +504,8 @@ namespace openspace::skybrowser::luascriptfunctions {
if(module->cameraInSolarSystem() && module->browserIdExists(id)) {
ScreenSpaceSkyTarget* target = module->getSkyBrowsers()[id]->getSkyTarget();
if (target) {
module->startRotation(target->getTargetDirectionCelestial());
glm::dvec3 cartesian = target->targetDirectionEquatorial();
module->startRotation(skybrowser::equatorialToGalactic(cartesian));
}
}
else if (!module->cameraInSolarSystem() && id3dBrowser == id) {
@@ -516,9 +525,9 @@ namespace openspace::skybrowser::luascriptfunctions {
RenderableSkyBrowser* browser3d = dynamic_cast<RenderableSkyBrowser*>(
module->get3dBrowser()->renderable());
// Empty 3D browser selection
browser3d->selectedImages().clear();
browser3d->getSelectedImages().clear();
// Copy 2D selection of images to 3D browser
std::deque images = browser->selectedImages();
std::deque images = browser->getSelectedImages();
std::for_each(std::begin(images), std::end(images), [&](int index) {
ImageData& image = module->getWWTDataHandler()->getLoadedImages()[index];
browser3d->displayImage(image, index);
@@ -534,15 +543,15 @@ namespace openspace::skybrowser::luascriptfunctions {
const std::string i = std::to_string(ghoul::lua::value<int>(L, 2));
double opacity = ghoul::lua::value<double>(L, 3);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
ghoul::Dictionary message = wwtmessage::setLayerOpacity(i, opacity);
ghoul::Dictionary message = wwtmessage::setImageOpacity(i, opacity);
if (module->browserIdExists(browserId)) {
module->getSkyBrowsers()[browserId]->sendMessageToWWT(message);
module->getSkyBrowsers()[browserId]->sendMessageToWwt(message);
}
else if (module->get3dBrowser() != nullptr) {
RenderableSkyBrowser* browser3d = dynamic_cast<RenderableSkyBrowser*>(
module->get3dBrowser()->renderable());
browser3d->sendMessageToWWT(message);
browser3d->sendMessageToWwt(message);
}
return 0;
@@ -558,12 +567,10 @@ namespace openspace::skybrowser::luascriptfunctions {
// Animate the target to the center of the screen
browser->getSkyTarget()->unlock();
// Get camera direction in celestial spherical coordinates
glm::dvec3 viewDirection = skybrowser::cameraDirectionJ2000Cartesian();
glm::dvec2 centerOfScreen = skybrowser::cartesianToSpherical(
viewDirection);
glm::dvec3 viewDirection = skybrowser::cameraDirectionEquatorial();
// Keep the current fov
float fov = browser->fieldOfView();
browser->getSkyTarget()->startAnimation(centerOfScreen, fov, false);
float fov = browser->verticalFov();
browser->getSkyTarget()->startAnimation(viewDirection, fov, false);
browser->getSkyTarget()->unlock();
}
}

View File

@@ -68,8 +68,8 @@ namespace openspace {
, _url(UrlInfo)
, _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f))
, _reload(ReloadInfo)
, _fov(70.f)
, _connectToWwt(false)
, _verticalFov(70.f)
, _syncViewWithWwt(false)
{
// Handle target dimension property
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -182,22 +182,22 @@ namespace openspace {
}
}
bool RenderableSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) {
bool RenderableSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) {
std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");";
executeJavascript(script);
return true;
}
void RenderableSkyBrowser::displayImage(ImageData& image, int i) {
sendMessageToWWT(wwtmessage::moveCamera(image.celestCoords, image.fov, 0.0));
_fov = image.fov;
sendMessageToWwt(wwtmessage::moveCamera(image.celestialCoords, image.fov, 0.0));
_verticalFov = image.fov;
// Add to selected images if there are no duplicates
auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i);
if (it == std::end(_selectedImages)) {
// Push newly selected image to front
_selectedImages.push_front(i);
// Create image layer and center WWT app on the image
sendMessageToWWT(wwtmessage::createImageLayer(std::to_string(i), image.imageUrl));
sendMessageToWwt(wwtmessage::addImage(std::to_string(i), image.imageUrl));
LINFO("Image has been loaded to " + identifier());
}
}
@@ -207,7 +207,7 @@ namespace openspace {
auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i);
if (it != std::end(_selectedImages)) {
_selectedImages.erase(it);
sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i)));
sendMessageToWwt(wwtmessage::removeImage(std::to_string(i)));
}
}
@@ -216,22 +216,22 @@ namespace openspace {
executeJavascript("setId('" + id + "')");
}
float RenderableSkyBrowser::fieldOfView() const {
return _fov;
float RenderableSkyBrowser::verticalFov() const {
return _verticalFov;
}
void RenderableSkyBrowser::connectToWwt() {
void RenderableSkyBrowser::syncWwtView() {
// If the camera is already synced, the browser is already initialized
if (!_connectToWwt) {
_connectToWwt = true;
if (!_syncViewWithWwt) {
_syncViewWithWwt = true;
// Start a thread to enable user interaction while sending the calls to WWT
_threadWwtMessages = std::thread([&] {
while (_connectToWwt) {
while (_syncViewWithWwt) {
glm::dvec2 aim{ 0.0 };
// Send a message just to establish contact
ghoul::Dictionary message = wwtmessage::moveCamera(aim, _fov, 0.0);
sendMessageToWWT(message);
ghoul::Dictionary message = wwtmessage::moveCamera(aim, _verticalFov, 0.0);
sendMessageToWwt(message);
// Sleep so we don't bombard WWT with too many messages
std::this_thread::sleep_for(std::chrono::milliseconds(500));
@@ -241,15 +241,15 @@ namespace openspace {
}
void RenderableSkyBrowser::stopConnectingToWwt() {
_connectToWwt = false;
void RenderableSkyBrowser::stopSyncingWwtView() {
_syncViewWithWwt = false;
if (_threadWwtMessages.joinable()) {
_threadWwtMessages.join();
}
}
std::deque<int>& RenderableSkyBrowser::selectedImages() {
std::deque<int>& RenderableSkyBrowser::getSelectedImages() {
return _selectedImages;
}
@@ -267,7 +267,7 @@ namespace openspace {
int reverseOrder = _selectedImages.size() - order - 1;
ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i),
reverseOrder, version);
sendMessageToWWT(message);
sendMessageToWwt(message);
}

View File

@@ -30,26 +30,27 @@ namespace {
constexpr const openspace::properties::Property::PropertyInfo BrowserDimensionInfo =
{
"BrowserDimensions",
"Browser Dimensions Info",
"Set the dimensions of the SkyTarget according to the SkyBrowser ratio "
"Browser Dimensions",
"The pixel dimensions of the sky browser."
};
constexpr const openspace::properties::Property::PropertyInfo ZoomInfo =
constexpr const openspace::properties::Property::PropertyInfo VerticalFovInfo =
{
"Zoom",
"Zoom Info",
"tjobidabidobidabidopp plupp"
"VerticalFieldOfView",
"Vertical Field Of View",
"The vertical field of view in degrees."
};
constexpr const openspace::properties::Property::PropertyInfo TargetIDInfo =
constexpr const openspace::properties::Property::PropertyInfo TargetIdInfo =
{
"TargetID",
"Target Info",
"tjobidabidobidabidopp plupp"
"TargetId",
"Target Id",
"The identifier of the target. It is used to synchronize the sky browser and the"
"sky target."
};
constexpr const openspace::properties::Property::PropertyInfo BorderColorInfo =
{
"BorderColor",
"Border color Info",
"tjobidabidobidabidopp plupp"
"Border Color",
"The color of the border of the sky browser as well as the sky target."
};
@@ -58,14 +59,14 @@ namespace {
// [[codegen::verbatim(BrowserDimensionInfo.description)]]
std::optional<glm::vec2> browserDimensions;
// [[codegen::verbatim(ZoomInfo.description)]]
std::optional<float> zoom;
// [[codegen::verbatim(VerticalFovInfo.description)]]
std::optional<float> verticalFov;
// [[codegen::verbatim(TargetIDInfo.description)]]
std::optional<std::string> targetID;
// [[codegen::verbatim(TargetIdInfo.description)]]
std::optional<std::string> targetId;
// [[codegen::verbatim(BorderColorInfo.description)]]
std::optional<glm::ivec3> borderColor;
std::optional<glm::vec3> borderColor;
};
#include "screenspaceskybrowser_codegen.cpp"
@@ -76,47 +77,44 @@ namespace openspace {
ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary)
: ScreenSpaceBrowser(dictionary)
, _browserDimensions(BrowserDimensionInfo, _dimensions, glm::ivec2(0), glm::ivec2(300))
, _vfieldOfView(ZoomInfo, 10.f, 0.1f, 70.f)
, _borderColor(BorderColorInfo, glm::ivec3(rand() % 256, rand() % 256, rand() % 256))
, _skyTargetID(TargetIDInfo)
, _camIsSyncedWWT(false)
, _skyTarget(nullptr)
, _verticalFov(VerticalFovInfo, 10.f, 0.1f, 70.f)
, _borderColor(BorderColorInfo, glm::vec3(rand() % 256, rand() % 256, rand() % 256))
, _skyTargetId(TargetIdInfo)
{
// Ensure the color of the border is bright enough.
// Make sure the RGB color at least is 50% brightness
// By making each channel 50% bright in general
// 222 = sqrt(3*(0.5*256)^2)
while (glm::length(_borderColor.value()) < 222) {
_borderColor = glm::ivec3(rand() % 256, rand() % 256, rand() % 256);
}
// Make the color property display a color picker in the GUI
_borderColor.setViewOption("Color", true);
// Handle target dimension property
const Parameters p = codegen::bake<Parameters>(dictionary);
_browserDimensions = p.browserDimensions.value_or(_browserDimensions);
_browserDimensions.onChange([&]() {
if(_skyTarget) {
glm::vec2 dim = getBrowserPixelDimensions();
_verticalFov = p.verticalFov.value_or(_verticalFov);
_borderColor = p.borderColor.value_or(_borderColor);
_skyTargetId = p.targetId.value_or(_skyTargetId);
addProperty(_browserDimensions);
addProperty(_verticalFov);
addProperty(_borderColor);
addProperty(_skyTargetId);
_browserDimensions.onChange([&]() {
if (_skyTarget) {
glm::vec2 dim = browserPixelDimensions();
_skyTarget->setDimensions(dim);
}
});
addProperty(_browserDimensions);
_vfieldOfView = p.zoom.value_or(_vfieldOfView);
addProperty(_vfieldOfView);
_skyTargetID = p.targetID.value_or(_skyTargetID);
addProperty(_skyTargetID);
_skyTargetID.onChange([&]() {
setConnectedTarget();
});
_vfieldOfView.onChange([&]() {
_verticalFov.onChange([&]() {
if (_skyTarget) {
_skyTarget->setVerticalFOV(_vfieldOfView);
_skyTarget->setScale(_verticalFov);
}
});
_borderColor.onChange([&]() {
setWebpageBorderColor(_borderColor.value());
});
_skyTargetId.onChange([&]() {
connectToSkyTarget();
});
// Set a unique identifier
std::string identifier;
if (dictionary.hasValue<std::string>(KeyIdentifier)) {
identifier = dictionary.value<std::string>(KeyIdentifier);
@@ -127,7 +125,8 @@ namespace openspace {
identifier = makeUniqueIdentifier(identifier);
setIdentifier(identifier);
_cartesianPosition.setValue(glm::dvec3(_cartesianPosition.value().x, _cartesianPosition.value().y, skybrowser::SCREENSPACE_Z));
glm::vec2 screenPosition = _cartesianPosition.value();
_cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ));
// Always make sure that the target and browser are visible together
_enabled.onChange([&]() {
@@ -135,13 +134,21 @@ namespace openspace {
_skyTarget->property("Enabled")->set(_enabled.value());
}
});
// Ensure the color of the border is bright enough.
// Make sure the RGB color at least is 50% brightness
// By making each channel 50% bright in general
// 222 = sqrt(3*(0.5*256)^2)
while (glm::length(_borderColor.value()) < 222) {
_borderColor = glm::vec3(rand() % 256, rand() % 256, rand() % 256);
}
}
ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() {
// Set flag to false so the thread can exit
_camIsSyncedWWT = false;
if (_threadWWTMessages.joinable()) {
_threadWWTMessages.join();
_syncViewWithWwt = false;
if (_threadWwtMessages.joinable()) {
_threadWwtMessages.join();
LINFO("Joined thread");
}
}
@@ -150,38 +157,39 @@ namespace openspace {
return ScreenSpaceBrowser::initializeGL();
}
void ScreenSpaceSkyBrowser::setIdInBrowser() {
void ScreenSpaceSkyBrowser::sendIdToBrowser() {
// Send ID to it's browser
executeJavascript("setId('" + identifier() + "')");
}
void ScreenSpaceSkyBrowser::initializeBrowser() {
// If the camera is already synced, the browser is already initialized
if (!_camIsSyncedWWT) {
_camIsSyncedWWT = true;
if (!_syncViewWithWwt) {
_syncViewWithWwt = true;
// Set border color
setBorderColor(_borderColor.value());
setWebpageBorderColor(_borderColor.value());
// Connect to target if they haven't been connected
if (!_skyTarget) {
setConnectedTarget();
connectToSkyTarget();
}
// Track target
WWTfollowCamera();
syncWwtView();
}
}
bool ScreenSpaceSkyBrowser::deinitializeGL() {
// Set flag to false so the thread can exit
_camIsSyncedWWT = false;
if (_threadWWTMessages.joinable()) {
_threadWWTMessages.join();
_syncViewWithWwt = false;
if (_threadWwtMessages.joinable()) {
_threadWwtMessages.join();
LINFO("Joined thread");
}
return ScreenSpaceBrowser::deinitializeGL();
}
bool ScreenSpaceSkyBrowser::setConnectedTarget() {
_skyTarget = dynamic_cast<ScreenSpaceSkyTarget*>(global::renderEngine->screenSpaceRenderable(_skyTargetID.value()));
bool ScreenSpaceSkyBrowser::connectToSkyTarget() {
_skyTarget = dynamic_cast<ScreenSpaceSkyTarget*>(
global::renderEngine->screenSpaceRenderable(_skyTargetId.value()));
return _skyTarget;
}
@@ -189,72 +197,81 @@ namespace openspace {
return _skyTarget;
}
bool ScreenSpaceSkyBrowser::hasLoadedCollections() {
return _hasLoadedCollections;
bool ScreenSpaceSkyBrowser::hasLoadedImages() const {
return _hasLoadedImages;
}
void ScreenSpaceSkyBrowser::setHasLoadedCollections(bool isLoaded) {
_hasLoadedCollections = isLoaded;
void ScreenSpaceSkyBrowser::setHasLoadedImages(bool isLoaded) {
_hasLoadedImages = isLoaded;
}
float ScreenSpaceSkyBrowser::fieldOfView() const {
return _vfieldOfView;
void ScreenSpaceSkyBrowser::setVerticalFov(float vfov) {
_verticalFov = vfov;
}
void ScreenSpaceSkyBrowser::setVerticalFieldOfView(float fov) {
_vfieldOfView = fov;
}
void ScreenSpaceSkyBrowser::scrollZoom(float scroll) {
void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) {
// Cap how often the zoom is allowed to update
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
if (now - _lastUpdateTime > TimeUpdateInterval) {
std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime;
if (timeSinceLastUpdate > _timeUpdateInterval) {
// Make scroll more sensitive the smaller the FOV
float x = _vfieldOfView;
float x = _verticalFov;
float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999;
float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor;
_vfieldOfView = std::clamp(_vfieldOfView + zoom, 0.001f, 70.0f);
_verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f);
_lastUpdateTime = std::chrono::system_clock::now();
}
}
void ScreenSpaceSkyBrowser::executeJavascript(std::string script) const {
//LINFOC(_loggerCat, "Executing javascript " + script);
if (_browserInstance && _browserInstance->getBrowser() && _browserInstance->getBrowser()->GetMainFrame()) {
void ScreenSpaceSkyBrowser::executeJavascript(std::string script) {
// Make sure that the browser has a main frame
bool browserExists = _browserInstance && _browserInstance->getBrowser();
bool frameIsLoaded = browserExists &&
_browserInstance->getBrowser()->GetMainFrame();
if (frameIsLoaded) {
CefRefPtr<CefFrame> frame = _browserInstance->getBrowser()->GetMainFrame();
frame->ExecuteJavaScript(script, frame->GetURL(), 0);
}
}
glm::ivec3 ScreenSpaceSkyBrowser::getColor() {
glm::ivec3 ScreenSpaceSkyBrowser::borderColor() const {
return _borderColor.value();
}
void ScreenSpaceSkyBrowser::setBorderColor(glm::ivec3 col) {
std::string stringColor = std::to_string(col.x) + "," + std::to_string(col.y) + "," + std::to_string(col.z);
std::string script = "document.body.style.backgroundColor = 'rgb(" + stringColor + ")';";
float ScreenSpaceSkyBrowser::verticalFov() const {
return _verticalFov.value();
}
void ScreenSpaceSkyBrowser::setWebpageBorderColor(glm::ivec3 color) {
std::string stringColor = std::to_string(color.x) + ","
+ std::to_string(color.y) + "," + std::to_string(color.z);
std::string script = "document.body.style.backgroundColor = 'rgb("
+ stringColor + ")';";
executeJavascript(script);
}
bool ScreenSpaceSkyBrowser::sendMessageToWWT(const ghoul::Dictionary& msg) {
void ScreenSpaceSkyBrowser::sendMessageToWwt(const ghoul::Dictionary& msg) {
std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");";
executeJavascript(script);
return true;
}
void ScreenSpaceSkyBrowser::WWTfollowCamera() {
void ScreenSpaceSkyBrowser::syncWwtView() {
// Start a thread to enable user interaction while sending the calls to WWT
_threadWWTMessages = std::thread([&] {
while (_camIsSyncedWWT) {
if (_skyTarget) {
glm::dvec2 aim = _skyTarget->getTargetDirectionCelestial();
// Calculate roll between up vector of camera and J2000 equatorial north
glm::dvec3 upVector = global::navigationHandler->camera()->lookUpVectorWorldSpace();
glm::dvec3 viewVector = global::navigationHandler->camera()->viewDirectionWorldSpace();
double roll = skybrowser::calculateRoll(upVector, viewVector);
ghoul::Dictionary message = wwtmessage::moveCamera(aim, _vfieldOfView, roll);
sendMessageToWWT(message);
_threadWwtMessages = std::thread([&] {
while (_syncViewWithWwt) {
if (_skyTarget) {
// Message WorldWide Telescope current view
glm::dvec3 cartesian = _skyTarget->targetDirectionEquatorial();
ghoul::Dictionary message = wwtmessage::moveCamera(
skybrowser::cartesianToSpherical(cartesian),
_verticalFov,
skybrowser::cameraRoll()
);
sendMessageToWwt(message);
}
// Sleep so we don't bombard WWT with too many messages
@@ -264,23 +281,24 @@ namespace openspace {
}
/*
void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) {
glm::vec3 position = _cartesianPosition;
_cartesianPosition = glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f);
}*/
//
//void ScreenSpaceSkyBrowser::translate(glm::vec2 translation) {
// glm::vec3 position = _cartesianPosition;
// _cartesianPosition =glm::translate(glm::mat4(1.f), glm::vec3(translation, 0.0f)) * glm::vec4(position, 1.0f);
//}
glm::vec2 ScreenSpaceSkyBrowser::coordIsOnResizeArea(glm::vec2 coord) {
glm::vec2 ScreenSpaceSkyBrowser::isOnResizeArea(glm::vec2 screenSpaceCoord) {
glm::vec2 resizePosition = glm::vec2{ 0 };
// Make sure coord is on browser
if (!coordIsInsideCornersScreenSpace(coord)) return resizePosition;
// Make sure coordinate is on browser
if (!coordIsInsideCornersScreenSpace(screenSpaceCoord)) return resizePosition;
float resizeButtonSize = 0.1f;
bool isOnTop = coord.y > getUpperRightCornerScreenSpace().y - (getScreenSpaceDimensions().y * resizeButtonSize);
bool isOnBottom = coord.y < getLowerLeftCornerScreenSpace().y + (getScreenSpaceDimensions().y * resizeButtonSize);
bool isOnRight = coord.x > getUpperRightCornerScreenSpace().x - (getScreenSpaceDimensions().x * resizeButtonSize);
bool isOnLeft = coord.x < getLowerLeftCornerScreenSpace().x + (getScreenSpaceDimensions().x * resizeButtonSize);
float resizeAreaY = screenSpaceDimensions().y * _resizeAreaPercentage;
float resizeAreaX = screenSpaceDimensions().x * _resizeAreaPercentage;
bool isOnTop = screenSpaceCoord.y > upperRightCornerScreenSpace().y - resizeAreaY;
bool isOnBottom = screenSpaceCoord.y < lowerLeftCornerScreenSpace().y + resizeAreaY;
bool isOnRight = screenSpaceCoord.x > upperRightCornerScreenSpace().x - resizeAreaX;
bool isOnLeft = screenSpaceCoord.x < lowerLeftCornerScreenSpace().x + resizeAreaX;
resizePosition.x = isOnRight ? 1.f : isOnLeft ? -1.f : 0.f;
resizePosition.y = isOnTop ? 1.f : isOnBottom ? -1.f : 0.f;
@@ -288,13 +306,13 @@ namespace openspace {
return resizePosition;
}
// Scales the ScreenSpaceBrowser to a new ratio
void ScreenSpaceSkyBrowser::scale(glm::vec2 scalingFactor) {
void ScreenSpaceSkyBrowser::setScale(glm::vec2 scalingFactor) {
// Scale on the y axis, this is to ensure that _scale = 1 is
// equal to the height of the window
scale(abs(scalingFactor.y));
setScale(abs(scalingFactor.y));
// Resize the dimensions of the texture on the x axis
glm::vec2 newSize = abs(scalingFactor) * _startDimensionsSize;
glm::vec2 newSize = abs(scalingFactor) * _originalDimensions;
_texture->setDimensions(glm::ivec3(newSize, 1));
_objectSize = _texture->dimensions();
_browserDimensions = newSize;
@@ -303,8 +321,9 @@ namespace openspace {
glm::mat4 ScreenSpaceSkyBrowser::scaleMatrix() {
// To ensure the plane has the right ratio
// The _scale tells us how much of the windows height the
// browser covers: eg a browser that covers 0.25 of the
// browser covers: e.g. a browser that covers 0.25 of the
// height of the window will have scale = 0.25
float textureRatio =
static_cast<float>(_texture->dimensions().x) / static_cast<float>(_texture->dimensions().y);
@@ -316,19 +335,19 @@ namespace openspace {
}
void ScreenSpaceSkyBrowser::saveResizeStartSize() {
_startDimensionsSize = glm::vec2(_dimensions.value().x, _dimensions.value().y);
_startScale = _scale.value();
_originalDimensions = _dimensions.value();
_originalScale = _scale.value();
}
// Updates the browser size to match the size of the texture
void ScreenSpaceSkyBrowser::updateBrowserSize() {
_dimensions = _texture->dimensions();
}
void ScreenSpaceSkyBrowser::scale(float scalingFactor) {
_scale = _startScale * scalingFactor;
void ScreenSpaceSkyBrowser::setScale(float scalingFactor) {
_scale = _originalScale * scalingFactor;
}
glm::vec2 ScreenSpaceSkyBrowser::getBrowserPixelDimensions() {
glm::vec2 ScreenSpaceSkyBrowser::browserPixelDimensions() const {
return _browserDimensions.value();
}
@@ -336,45 +355,62 @@ namespace openspace {
return _opacity;
}
std::deque<int>& ScreenSpaceSkyBrowser::selectedImages() {
std::deque<int>& ScreenSpaceSkyBrowser::getSelectedImages() {
return _selectedImages;
}
void ScreenSpaceSkyBrowser::addSelectedImage(ImageData& image, int i) {
// Ensure there are no duplicates
auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i);
if (it == std::end(_selectedImages)) {
bool found = it != std::end(_selectedImages);
if (!found) {
// Push newly selected image to front
_selectedImages.push_front(i);
// Index of image is used as layer ID as it is unique in the image data set
sendMessageToWWT(wwtmessage::createImageLayer(std::to_string(i), image.imageUrl));
sendMessageToWWT(wwtmessage::setLayerOpacity(std::to_string(i), 1.0));
sendMessageToWwt(wwtmessage::addImage(std::to_string(i), image.imageUrl));
sendMessageToWwt(wwtmessage::setImageOpacity(std::to_string(i), 1.0));
}
}
void ScreenSpaceSkyBrowser::removeSelectedImage(ImageData& image, int i) {
// Remove from selected list
auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i);
if (it != std::end(_selectedImages)) {
bool found = it != std::end(_selectedImages);
if (found) {
_selectedImages.erase(it);
sendMessageToWWT(wwtmessage::removeImageLayer(std::to_string(i)));
sendMessageToWwt(wwtmessage::removeImage(std::to_string(i)));
}
}
void ScreenSpaceSkyBrowser::setImageLayerOrder(int i, int order, int version) {
// Remove from selected list
auto current = std::find(std::begin(_selectedImages), std::end(_selectedImages), i);
void ScreenSpaceSkyBrowser::setImageOrder(int i, int order, int version) {
// Find the selected image
auto selected = std::find(
std::begin(_selectedImages),
std::end(_selectedImages),
i
);
// Find the target for the swap
auto target = std::begin(_selectedImages) + order;
// Make sure the image was found in the list
if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) {
// Make sure the selected and the target placement was found in the list
bool foundSelected = selected != std::end(_selectedImages);
bool foundTarget = target != std::end(_selectedImages);
if (foundSelected && foundTarget) {
// Swap the two images
std::iter_swap(current, target);
std::iter_swap(selected, target);
}
// The images in the selected list are displayed in the reverse order from how the
// WorldWide Telescope application sees them
int reverseOrder = _selectedImages.size() - order - 1;
ghoul::Dictionary message = wwtmessage::setLayerOrder(std::to_string(i),
reverseOrder, version);
sendMessageToWWT(message);
ghoul::Dictionary message = wwtmessage::setLayerOrder(
std::to_string(i),
reverseOrder,
version
);
sendMessageToWwt(message);
}
}

View File

@@ -74,7 +74,7 @@ namespace {
namespace openspace {
ScreenSpaceSkyTarget::ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary)
: ScreenSpaceRenderable(dictionary)
, _skyBrowserID(BrowserIDInfo)
, _skyBrowserId(BrowserIDInfo)
, _skyBrowser(nullptr)
, _showCrosshairThreshold(CrosshairThresholdInfo, 2.0f, 0.1f, 70.f)
, _showRectangleThreshold(RectangleThresholdInfo, 0.6f, 0.1f, 70.f)
@@ -82,17 +82,17 @@ namespace openspace {
{
// Handle target dimension property
const Parameters p = codegen::bake<Parameters>(dictionary);
_skyBrowserID = p.browserID.value_or(_skyBrowserID);
_skyBrowserId = p.browserID.value_or(_skyBrowserId);
_showCrosshairThreshold = p.crosshairThreshold.value_or(_showCrosshairThreshold);
_showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold);
addProperty(_skyBrowserID);
addProperty(_skyBrowserId);
addProperty(_showCrosshairThreshold);
addProperty(_showRectangleThreshold);
// If the ID changes for the corresponding browser, update
_skyBrowserID.onChange([&]() {
initializeWithBrowser();
_skyBrowserId.onChange([&]() {
findSkyBrowser();
});
// Always make sure that the target and browser are visible together
@@ -115,14 +115,14 @@ namespace openspace {
// Set the position to screen space z
glm::dvec3 startPos{ _cartesianPosition.value().x, _cartesianPosition.value().y,
skybrowser::SCREENSPACE_Z };
skybrowser::ScreenSpaceZ };
_cartesianPosition.setValue(startPos);
}
ScreenSpaceSkyTarget::~ScreenSpaceSkyTarget() {
if (_lockTargetThread.joinable()) {
_lockTargetThread.join();
if (_lockTarget.joinable()) {
_lockTarget.join();
}
}
@@ -131,13 +131,18 @@ namespace openspace {
}
void ScreenSpaceSkyTarget::initializeWithBrowser() {
bool ScreenSpaceSkyTarget::findSkyBrowser() {
_skyBrowser = dynamic_cast<ScreenSpaceSkyBrowser*>(
global::renderEngine->screenSpaceRenderable(_skyBrowserID.value()));
global::renderEngine->screenSpaceRenderable(_skyBrowserId.value()));
matchAppearanceToSkyBrowser();
return _skyBrowser;
}
void ScreenSpaceSkyTarget::matchAppearanceToSkyBrowser() {
if (_skyBrowser) {
_color = _skyBrowser->getColor();
_objectSize = _skyBrowser->getBrowserPixelDimensions();
setVerticalFOV(_skyBrowser->_vfieldOfView.value());
_color = _skyBrowser->borderColor();
_objectSize = _skyBrowser->browserPixelDimensions();
setScale(_skyBrowser->verticalFov());
}
}
@@ -156,10 +161,10 @@ namespace openspace {
glm::mat4 ScreenSpaceSkyTarget::scaleMatrix() {
// To ensure the plane has the right ratio
// The _scale us how much of the windows height the browser covers: eg a browser
// The _scale us how much of the windows height the browser covers: e.g. a browser
// that covers 0.25 of the height of the window will have scale = 0.25
float ratio = static_cast<float>(_objectSize.x) /
static_cast<float>(_objectSize.y);
glm::vec2 floatObjectSize = glm::abs(_objectSize);
float ratio = floatObjectSize.x / floatObjectSize.y;
glm::mat4 scale = glm::scale(
glm::mat4(1.f),
@@ -186,7 +191,7 @@ namespace openspace {
_color = color;
}
glm::ivec3 ScreenSpaceSkyTarget::getColor() {
glm::ivec3 ScreenSpaceSkyTarget::borderColor() const {
return _color;
}
@@ -196,20 +201,18 @@ namespace openspace {
void ScreenSpaceSkyTarget::render() {
glDisable(GL_CULL_FACE);
bool showCrosshair = _skyBrowser->verticalFov() < _showCrosshairThreshold;
bool showRectangle = _skyBrowser->verticalFov() > _showRectangleThreshold;
glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() };
glm::mat4 modelTransform = globalRotationMatrix() * translationMatrix() *
localRotationMatrix() * scaleMatrix();
float lineWidth = 0.0016f/_scale.value();
_shader->activate();
glDisable(GL_CULL_FACE);
bool showCrosshair = _verticalFOV < _showCrosshairThreshold;
bool showRect = _verticalFOV > _showRectangleThreshold;
glm::vec4 color = { glm::vec3(_color) / 255.f, _opacity.value() };
_shader->activate();
_shader->setUniform(_uniformCache.showCrosshair, showCrosshair);
_shader->setUniform(_uniformCache.showRectangle, showRect);
_shader->setUniform(_uniformCache.showRectangle, showRectangle);
_shader->setUniform(_uniformCache.lineWidth, lineWidth);
_shader->setUniform(_uniformCache.dimensions, glm::vec2(_objectSize));
_shader->setUniform(_uniformCache.modelTransform, modelTransform);
@@ -231,7 +234,7 @@ namespace openspace {
_objectSize = dimensions;
}
glm::dvec3 ScreenSpaceSkyTarget::getTargetDirectionGalactic() {
glm::dvec3 ScreenSpaceSkyTarget::targetDirectionGalactic() const {
glm::dmat4 rotation = glm::inverse(
global::navigationHandler->camera()->viewRotationMatrix());
glm::dvec4 position = glm::dvec4(_cartesianPosition.value(), 1.0);
@@ -239,20 +242,26 @@ namespace openspace {
return glm::normalize(rotation * position);
}
void ScreenSpaceSkyTarget::setVerticalFOV(float VFOV) {
_verticalFOV = VFOV;
// Update the scale of the target
float horizFOV = global::windowDelegate->getHorizFieldOfView();
glm::ivec2 windowRatio = global::windowDelegate->currentWindowSize();
float verticFOV = horizFOV * (static_cast<float>(windowRatio.y) / static_cast<float>(windowRatio.x));
_scale = std::max((VFOV / verticFOV), (_showRectangleThreshold.value() / verticFOV));
// Update the scale of the target (the height of the target in relation to the
// OpenSpace window)
void ScreenSpaceSkyTarget::setScale(float verticalFov) {
// Calculate the vertical field of view of the OpenSpace window
float hFovOs = global::windowDelegate->getHorizFieldOfView();
glm::vec2 windowRatio = glm::vec2(global::windowDelegate->currentWindowSize());
float vFovOs = hFovOs * windowRatio.y / windowRatio.x;
// Cap the scale at small scales so it is still visible
float heightRatio = verticalFov / vFovOs;
float smallestHeightRatio = _showRectangleThreshold.value() / vFovOs;
_scale = std::max(heightRatio, smallestHeightRatio);
}
void ScreenSpaceSkyTarget::unlock() {
_isLocked = false;
if (_lockTargetThread.joinable()) {
_lockTargetThread.join();
if (_lockTarget.joinable()) {
_lockTarget.join();
}
}
@@ -261,13 +270,13 @@ namespace openspace {
unlock();
}
_isLocked = true;
_lockedCoords = getTargetDirectionCelestial();
_lockedCoordinates = targetDirectionEquatorial();
// Start a thread to enable user interactions while locking target
_lockTargetThread = std::thread([&] {
_lockTarget = std::thread([&] {
while (_isLocked) {
glm::vec3 imageCoordsScreenSpace = skybrowser::J2000SphericalToScreenSpace(_lockedCoords);
_cartesianPosition = imageCoordsScreenSpace;
glm::vec3 coordsScreen = skybrowser::equatorialToScreenSpace(_lockedCoordinates);
_cartesianPosition = coordsScreen;
}
});
}
@@ -276,57 +285,55 @@ namespace openspace {
return _isLocked;
}
glm::dvec2 ScreenSpaceSkyTarget::getTargetDirectionCelestial() {
glm::dvec3 ScreenSpaceSkyTarget::targetDirectionEquatorial() const {
// Calculate the galactic coordinate of the target direction
// with infinite radius
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
constexpr double infinity = std::numeric_limits<float>::max();
glm::dvec3 galCoord = camPos + (infinity * getTargetDirectionGalactic());
return skybrowser::galacticCartesianToJ2000Spherical(galCoord);
// projected onto the celestial sphere
return skybrowser::screenSpaceToEquatorial(_cartesianPosition.value());
}
void ScreenSpaceSkyTarget::animateToCoord(double deltaTime) {
void ScreenSpaceSkyTarget::animateToCoordinate(double deltaTime) {
if (_isAnimated) {
// Find smallest angle between the two vectors
double smallestAngle = std::acos(glm::dot(_coordsStartAnimation, _coordsEndAnimation) / (glm::length(_coordsStartAnimation) * glm::length(_coordsEndAnimation)));
double smallestAngle = std::acos(glm::dot(_animationStart, _animationEnd) / (glm::length(_animationStart) * glm::length(_animationEnd)));
// Only keep animating when target is not at final position
if (abs(smallestAngle) > 0.0005) {
// Calculate rotation this frame
double rotationAngle = smallestAngle * deltaTime * 5.0;
// Create the rotation matrix
glm::dvec3 rotationAxis = glm::normalize(glm::cross(_coordsStartAnimation, _coordsEndAnimation));
glm::dvec3 rotationAxis = glm::normalize(glm::cross(_animationStart, _animationEnd));
glm::dmat4 rotmat = glm::rotate(rotationAngle, rotationAxis);
// Rotate target direction
glm::dvec3 newDir = rotmat * glm::dvec4(_coordsStartAnimation, 1.0);
// Convert to screenspace
_cartesianPosition = skybrowser::J2000CartesianToScreenSpace(newDir);
glm::dvec3 newDir = rotmat * glm::dvec4(_animationStart, 1.0);
// Convert to screen space
_cartesianPosition = skybrowser::equatorialToScreenSpace(newDir);
// Update position
_coordsStartAnimation = glm::normalize(newDir);
_animationStart = glm::normalize(newDir);
}
else {
// Set the exact target position
_cartesianPosition = skybrowser::J2000CartesianToScreenSpace(_coordsEndAnimation);
_cartesianPosition = skybrowser::equatorialToScreenSpace(_animationEnd);
// Lock target when it first arrives to the position
if (!_isLocked && _lockAfterAnimation) {
lock();
}
// When target is in position, animate the FOV until it has finished
if(animateToFOV(_FOVEndAnimation, deltaTime)) {
if(animateToFov(_vfovEndAnimation, deltaTime)) {
_isAnimated = false;
}
}
}
}
bool ScreenSpaceSkyTarget::animateToFOV(float endFOV, float deltaTime) {
bool ScreenSpaceSkyTarget::animateToFov(float endFOV, float deltaTime) {
if (!_skyBrowser) {
initializeWithBrowser();
findSkyBrowser();
}
if (_skyBrowser) {
double distance = static_cast<double>(_skyBrowser->_vfieldOfView.value()) - endFOV;
double distance = static_cast<double>(_skyBrowser->verticalFov()) - endFOV;
// If distance is too large, keep animating
if (abs(distance) > 0.01) {
_skyBrowser->scrollZoom(distance);
_skyBrowser->setVerticalFovWithScroll(distance);
return false;
}
// Animation is finished
@@ -339,18 +346,22 @@ namespace openspace {
return true;
}
void ScreenSpaceSkyTarget::startAnimation(glm::dvec2 coordsEnd, float FOVEnd,
void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 coordsEnd, float FOVEnd,
bool lockAfterwards) {
// Save the Cartesian celestial coordinates for animation
// The coordinates are Cartesian to avoid wrap-around issues
_coordsEndAnimation = glm::normalize(skybrowser::sphericalToCartesian(coordsEnd));
_coordsStartAnimation = glm::normalize(skybrowser::sphericalToCartesian(
getTargetDirectionCelestial()));
_FOVEndAnimation = FOVEnd;
_animationEnd = glm::normalize(coordsEnd);
_animationStart = glm::normalize(targetDirectionEquatorial());
_vfovEndAnimation = FOVEnd;
_isAnimated = true;
_lockAfterAnimation = lockAfterwards;
}
properties::FloatProperty& ScreenSpaceSkyTarget::getOpacity() {
return _opacity;
float ScreenSpaceSkyTarget::opacity() const {
return _opacity.value();
}
void ScreenSpaceSkyTarget::setOpacity(float opacity) {
_opacity = opacity;
}
}

View File

@@ -12,103 +12,118 @@
namespace openspace::skybrowser {
glm::dvec3 sphericalToCartesian(glm::dvec2 sphericalCoords) {
glm::dvec3 sphericalToCartesian(glm::dvec2 coords) {
glm::dvec2 coordsRadians = glm::radians(coords);
glm::dvec3 cartesian = glm::dvec3(
cos(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD),
sin(sphericalCoords.x * DEG_TO_RAD) * cos(sphericalCoords.y * DEG_TO_RAD),
sin(sphericalCoords.y * DEG_TO_RAD)
cos(coordsRadians.x) * cos(coordsRadians.y),
sin(coordsRadians.x) * cos(coordsRadians.y),
sin(coordsRadians.y)
);
return cartesian;
}
glm::dvec2 cartesianToSpherical(glm::dvec3 cartesianCoords) {
double ra = atan2(cartesianCoords[1], cartesianCoords[0]);
double dec = atan2(cartesianCoords[2], glm::sqrt((cartesianCoords[0] * cartesianCoords[0]) + (cartesianCoords[1] * cartesianCoords[1])));
glm::dvec2 cartesianToSpherical(glm::dvec3 coord) {
// Equatorial coordinates RA = right ascension, Dec = declination
double ra = atan2(coord.y, coord.x);
double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y)));
ra = ra > 0 ? ra : ra + (2 * M_PI);
return glm::dvec2(RAD_TO_DEG * ra, RAD_TO_DEG * dec);
glm::dvec2 celestialCoords{ ra, dec };
return glm::degrees(celestialCoords);
}
glm::dvec3 galacticCartesianToJ2000Cartesian(glm::dvec3 rGal) {
return glm::transpose(conversionMatrix) * rGal;
}
glm::dvec2 galacticCartesianToJ2000Spherical(glm::dvec3 rGal) {
return cartesianToSpherical(galacticCartesianToJ2000Cartesian(rGal));
}
glm::dvec3 J2000SphericalToGalacticCartesian(glm::dvec2 coords, double distance) {
glm::dvec3 rGalactic = conversionMatrix * sphericalToCartesian(coords); // on the unit sphere
return distance * rGalactic;
glm::dvec3 galacticToEquatorial(glm::dvec3 coords) {
return glm::transpose(conversionMatrix) * glm::normalize(coords);
}
glm::dvec3 J2000CartesianToGalacticCartesian(glm::dvec3 coords, double distance) {
glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords); // on the unit sphere
return distance * rGalactic;
glm::dvec3 equatorialToGalactic(glm::dvec3 coords) {
// On the unit sphere
glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords);
return rGalactic * CelestialSphereRadius;
}
glm::dvec3 galacticToScreenSpace(glm::dvec3 imageCoordsGalacticCartesian) {
glm::dvec3 galacticToScreenSpace(glm::dvec3 coords) {
glm::dvec3 viewDirectionLocal = galacticCartesianToCameraLocalCartesian(imageCoordsGalacticCartesian);
// Ensure that if the coord is behind the camera, the converted coord will be there too
double zCoord = viewDirectionLocal.z > 0 ? -SCREENSPACE_Z : SCREENSPACE_Z;
glm::dvec3 localCameraSpace = galacticToCameraLocal(coords);
// Ensure that if the coord is behind the camera,
// the converted coordinate will be there too
double zCoord = localCameraSpace.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ;
// Calculate screen space coords x and y
long double tan_x = viewDirectionLocal.x / viewDirectionLocal.z;
long double tan_y = viewDirectionLocal.y / viewDirectionLocal.z;
double tan_x = localCameraSpace.x / localCameraSpace.z;
double tan_y = localCameraSpace.y / localCameraSpace.z;
glm::dvec2 angleCoordsLocal = glm::dvec2(std::atanl(tan_x), std::atanl(tan_y));
glm::dvec3 imageCoordsScreenSpace = glm::dvec3(zCoord * static_cast<double>(std::tanl(angleCoordsLocal.x)), zCoord * static_cast<double>(std::tanl(angleCoordsLocal.y)), zCoord);
glm::dvec3 screenSpace = glm::dvec3(zCoord * tan_x, zCoord * tan_y, zCoord);
return imageCoordsScreenSpace;
return screenSpace;
}
glm::dvec3 screenSpaceToGalactic(glm::dvec3 coords) {
glm::dmat4 rotation = glm::inverse(
global::navigationHandler->camera()->viewRotationMatrix());
glm::dvec4 position = glm::dvec4(coords, 1.0);
return glm::normalize(rotation * position) * skybrowser::CelestialSphereRadius;
}
glm::dvec3 screenSpaceToEquatorial(glm::dvec3 coords) {
// Calculate the galactic coordinate of the target direction
// projected onto the celestial sphere
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
glm::dvec3 galactic = camPos + skybrowser::screenSpaceToGalactic(coords);
return skybrowser::galacticToEquatorial(galactic);
}
glm::dvec3 galacticCartesianToCameraLocalCartesian(glm::dvec3 galCoords) {
glm::dvec3 galacticToCameraLocal(glm::dvec3 coords) {
// Transform vector to camera's local coordinate system
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
glm::dvec3 camToCoordsDir = glm::normalize(galCoords - camPos);
glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix();
glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(camToCoordsDir, 1.0);
viewDirectionLocal = glm::normalize(viewDirectionLocal);
return viewDirectionLocal;
glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos);
glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0);
return glm::normalize(viewDirectionLocal);
}
glm::dvec3 J2000CartesianToScreenSpace(glm::dvec3 coords) {
glm::dvec3 equatorialToScreenSpace(glm::dvec3 coords) {
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 imageCoordsGalacticCartesian = J2000CartesianToGalacticCartesian(coords, infinity);
glm::dvec3 galactic = equatorialToGalactic(coords);
// Transform galactic coord to screen space
return galacticToScreenSpace(imageCoordsGalacticCartesian);
return galacticToScreenSpace(galactic);
}
glm::dvec3 J2000SphericalToScreenSpace(glm::dvec2 coords) {
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 imageCoordsGalacticCartesian = J2000SphericalToGalacticCartesian(coords, infinity);
// Transform galactic coord to screen space
return galacticToScreenSpace(imageCoordsGalacticCartesian);
}
double cameraRoll() {
openspace::Camera* camera = global::navigationHandler->camera();
glm::dvec3 upWorld = camera->lookUpVectorWorldSpace();
glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace();
double calculateRoll(glm::dvec3 upWorld, glm::dvec3 forwardWorld) {
glm::dvec3 camUpJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(upWorld);
glm::dvec3 camForwardJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(forwardWorld);
glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld);
glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld);
glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NORTH_POLE);
double dotNorthUp = glm::dot(skybrowser::NORTH_POLE, camUpJ2000);
glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole);
double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000);
double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000);
double roll = glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
return roll;
return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
}
glm::dvec3 cameraDirectionJ2000Cartesian() {
glm::dvec3 cameraDirectionEquatorial() {
// Get the view direction of the screen in cartesian J2000 coordinates
return galacticToEquatorial(cameraDirectionGalactic());
}
glm::dvec3 cameraDirectionGalactic() {
// Get the view direction of the screen in galactic coordinates
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
constexpr double infinity = std::numeric_limits<float>::max();
glm::dvec3 galCoord = camPos + (infinity * global::navigationHandler->camera()->viewDirectionWorldSpace());
glm::dvec3 cartesianJ2000 = skybrowser::galacticCartesianToJ2000Cartesian(galCoord);
return cartesianJ2000;
glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace();
glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view);
return galCoord;
}
}
@@ -150,7 +165,7 @@ namespace openspace::wwtmessage {
return msg;
}
ghoul::Dictionary createImageLayer(const std::string& id, const std::string& url) {
ghoul::Dictionary addImage(const std::string& id, const std::string& url) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_create"s);
@@ -162,7 +177,7 @@ namespace openspace::wwtmessage {
return msg;
}
ghoul::Dictionary removeImageLayer(const std::string& imageId) {
ghoul::Dictionary removeImage(const std::string& imageId) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_remove"s);
@@ -171,7 +186,7 @@ namespace openspace::wwtmessage {
return msg;
}
ghoul::Dictionary setLayerOpacity(const std::string& imageId, double opacity) {
ghoul::Dictionary setImageOpacity(const std::string& imageId, double opacity) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_set"s);

View File

@@ -20,20 +20,37 @@ namespace {
namespace openspace {
WWTDataHandler::~WWTDataHandler() {
// Call destructor of all allocated xmls
xmls.clear();
bool hasAttribute(tinyxml2::XMLElement* element, std::string name) {
return element->FindAttribute(name.c_str());
}
bool WWTDataHandler::downloadFile(std::string& url, std::string& fileDestination) {
// Get the webpage and save to file
std::string getAttribute(tinyxml2::XMLElement* element, std::string name) {
if (hasAttribute(element, name)) {
return element->FindAttribute(name.c_str())->Value();
}
else {
return "";
}
}
WwtDataHandler::~WwtDataHandler() {
// Call destructor of all allocated xmls
_xmls.clear();
}
bool WwtDataHandler::downloadFile(std::string& url, std::string& fileDestination) {
// Get the web page and save to file
HttpRequest::RequestOptions opt{ 5 };
SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes);
SyncHttpFileDownload wtml_root(
url, fileDestination, HttpFileDownload::Overwrite::Yes
);
wtml_root.download(opt);
return wtml_root.hasSucceeded();
}
void WWTDataHandler::loadWTMLCollectionsFromURL(std::string directory, std::string url, std::string fileName) {
bool WwtDataHandler::loadWtmlCollectionsFromUrl(std::string directory,
std::string url, std::string fileName)
{
// Look for WWT image data folder
if (!directoryExists(directory)) {
std::string newDir = directory;
@@ -46,7 +63,7 @@ namespace openspace {
std::string file = directory + fileName + ".aspx";
if (!downloadFile(url, file)) {
LINFO("Couldn't download file " + url);
return;
return false;
}
// Parse to XML
using namespace tinyxml2;
@@ -55,41 +72,52 @@ namespace openspace {
XMLElement* root = doc->RootElement();
XMLElement* element = root->FirstChildElement(std::string("Folder").c_str());
// If there are no folders, or there are folder but without urls, stop recursion
if (!element || (element && !element->FindAttribute("Url"))) {
bool folderExists = element;
bool folderContainNoUrls = folderExists && !hasAttribute(element, "Url");
if (!folderExists || folderContainNoUrls) {
// Save the url
std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : "";
if (collectionName != "") {
if (hasAttribute(root, "Name")) {
std::string collectionName = getAttribute(root, "Name");
ImageCollection newCollection{ collectionName, url };
imageUrls.push_back(newCollection);
_imageUrls.push_back(newCollection);
}
xmls.push_back(doc);
_xmls.push_back(doc);
LINFO("Saving " + url);
return;
return true;
}
// Iterate through all the folders
while (element && std::string(element->Value()) == "Folder") {
// Get all attributes for the <Folder>
std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : "";
std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : "";
if (subUrl != "" && subName != "") {
loadWTMLCollectionsFromURL(directory, subUrl, subName);
// Get all attributes for the <Folder>
if (hasAttribute(element, "Url") && hasAttribute(element, "Name")) {
std::string subUrl = getAttribute(element, "Url");
std::string subName = getAttribute(element, "Name");
loadWtmlCollectionsFromUrl(directory, subUrl, subName);
}
element = element->NextSiblingElement();
}
}
bool WWTDataHandler::directoryExists(std::string& path)
bool WwtDataHandler::directoryExists(std::string& path)
{
struct stat info;
int statRC = stat(path.c_str(), &info);
if (statRC != 0)
{
if (errno == ENOENT) { return false; } // something along the path does not exist
if (errno == ENOTDIR) { return false; } // something in path prefix is not a dir
// something along the path does not exist
if (errno == ENOENT) {
return false;
}
// something in path prefix is not a dir
if (errno == ENOTDIR) {
return false;
}
return false;
}
@@ -98,43 +126,49 @@ namespace openspace {
return directoryExists;
}
bool WWTDataHandler::loadWTMLCollectionsFromDirectory(std::string directory) {
bool WwtDataHandler::loadWtmlCollectionsFromDirectory(std::string directory) {
if (!directoryExists(directory)) return false;
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) {
tinyxml2::XMLElement* root = doc->RootElement();
std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : "";
if (collectionName != "") {
ImageCollection newCollection{collectionName, entry.path().u8string()};
imageUrls.push_back(newCollection);
tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument();
std::string path = entry.path().u8string();
tinyxml2::XMLError successCode = document->LoadFile(path.c_str());
bool fileIsLoaded = successCode == tinyxml2::XMLError::XML_SUCCESS;
if (fileIsLoaded) {
tinyxml2::XMLElement* root = document->RootElement();
if (hasAttribute(root, "Name")) {
std::string collectionName = getAttribute(root, "Name");
ImageCollection newCollection{ collectionName, path };
_imageUrls.push_back(newCollection);
}
xmls.push_back(doc);
_xmls.push_back(document);
}
}
return true;
}
std::ostream& operator<<(std::ostream& os, const ImageData& img) {
os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl;
os << "Name: " << img.name << " Coords: ra: " << img.celestialCoords.x
<< " dec: " << img.celestialCoords.y << std::endl;
os << "Thumbnail: " << img.thumbnailUrl << std::endl;
os << "Collection: " << img.collection << std::endl << std::endl;
return os;
}
int WWTDataHandler::loadImagesFromLoadedXMLs() {
for (tinyxml2::XMLDocument* doc : xmls) {
int WwtDataHandler::loadImagesFromLoadedXmls() {
for (tinyxml2::XMLDocument* doc : _xmls) {
tinyxml2::XMLElement* root = doc->FirstChildElement();
std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : "";
loadImagesFromXML(root, collectionName);
loadImagesFromXml(root, collectionName);
}
// Sort images in alphabetial order
std::sort(images.begin(), images.end(), [](ImageData a, ImageData b) {
// If the first charachter in the names are lowercase, make it upper case
// Sort images in alphabetical order
std::sort(_images.begin(), _images.end(), [](ImageData a, ImageData b) {
// If the first character in the names are lowercase, make it upper case
if (std::islower(a.name[0])) {
// convert string to upper case
a.name[0] = ::toupper(a.name[0]);
@@ -144,16 +178,16 @@ namespace openspace {
}
return a.name < b.name;
});
LINFO(std::to_string(nImagesWith3dPositions) + " 3D positions were matched in the speck files!");
LINFO(std::to_string(_nImagesWith3dPositions) + " 3D positions were matched in the speck files!");
return images.size();
return _images.size();
}
const std::vector<ImageCollection>& WWTDataHandler::getAllImageCollectionUrls() const {
return imageUrls;
const std::vector<ImageCollection>& WwtDataHandler::getAllImageCollectionUrls() const {
return _imageUrls;
}
void WWTDataHandler::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) {
void WwtDataHandler::loadImagesFromXml(tinyxml2::XMLElement* node, std::string collectionName) {
// Get direct child of node called "Place"
using namespace tinyxml2;
XMLElement* ptr = node->FirstChildElement();
@@ -171,7 +205,7 @@ namespace openspace {
if (ptr->FindAttribute("Name")) {
newCollectionName += std::string(ptr->FindAttribute("Name")->Value());
}
loadImagesFromXML(ptr, newCollectionName);
loadImagesFromXml(ptr, newCollectionName);
}
ptr = ptr->NextSiblingElement();
@@ -179,7 +213,7 @@ namespace openspace {
}
int WWTDataHandler::loadImageFromXmlNode(tinyxml2::XMLElement* node, std::string collectionName) {
int WwtDataHandler::loadImageFromXmlNode(tinyxml2::XMLElement* node, std::string collectionName) {
// Only load "Sky" type images
if (std::string(node->FindAttribute("DataSetType")->Value()) != "Sky")
return -1;
@@ -195,7 +229,7 @@ namespace openspace {
imageSet = node;
}
else if (std::string(node->Name()) == "Place") {
thumbnailUrl = getURLFromPlace(node);
thumbnailUrl = getUrlFromPlace(node);
imageSet = getChildNode(node, "ImageSet");
}
else {
@@ -218,19 +252,19 @@ namespace openspace {
ImageData image{};
setImageDataValues(node, credits, creditsUrl, thumbnailUrl, collectionName, imageUrl, image);
images.push_back(image);
_images.push_back(image);
// Return index of image in vector
return images.size();
return _images.size();
}
std::string WWTDataHandler::getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName) {
std::string WwtDataHandler::getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet, std::string elementName) {
// FInd the thumbnail image url
// The thumbnail is the last node so traverse backwards for speed
tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement(elementName.c_str());
return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : "";
}
std::string WWTDataHandler::getURLFromPlace(tinyxml2::XMLElement* place) {
std::string WwtDataHandler::getUrlFromPlace(tinyxml2::XMLElement* place) {
// Get thumbnail attribute, if there is one
std::string url = place->FindAttribute("Thumbnail") ? place->FindAttribute("Thumbnail")->Value() : "";
// Url found! Return it
@@ -244,14 +278,14 @@ namespace openspace {
return imageSet ? getChildNodeContentFromImageSet(imageSet, "ThumbnailUrl") : "";
}
tinyxml2::XMLElement* WWTDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) {
tinyxml2::XMLElement* WwtDataHandler::getDirectChildNode(tinyxml2::XMLElement* node, std::string name) {
while (node && std::string(node->Name()) != name) {
node = node->FirstChildElement();
}
return node;
}
tinyxml2::XMLElement* WWTDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) {
tinyxml2::XMLElement* WwtDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) {
// Traverse the children and look at all their first child to find ImageSet
tinyxml2::XMLElement* child = node->FirstChildElement();
tinyxml2::XMLElement* imageSet = nullptr;
@@ -263,7 +297,7 @@ namespace openspace {
return imageSet;
}
void WWTDataHandler::setImageDataValues(tinyxml2::XMLElement* node,
void WwtDataHandler::setImageDataValues(tinyxml2::XMLElement* node,
std::string credits,
std::string creditsUrl,
std::string thumbnail,
@@ -272,11 +306,11 @@ namespace openspace {
ImageData& img) {
// Get attributes for the image
img.name = node->FindAttribute("Name") ? node->FindAttribute("Name")->Value() : "";
img.hasCelestCoords = node->FindAttribute("RA") && node->FindAttribute("Dec");
if (img.hasCelestCoords) {
img.hasCelestialCoords = node->FindAttribute("RA") && node->FindAttribute("Dec");
if (img.hasCelestialCoords) {
// The RA from WWT is in the unit hours: to convert to degrees, multiply with 360 (deg) /24 (h) = 15
img.celestCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value());
img.celestCoords.y = std::stof(node->FindAttribute("Dec")->Value());
img.celestialCoords.x = 15.0f * std::stof(node->FindAttribute("RA")->Value());
img.celestialCoords.y = std::stof(node->FindAttribute("Dec")->Value());
}
img.collection = collectionName;
img.thumbnailUrl = thumbnail;
@@ -292,15 +326,15 @@ namespace openspace {
if (it != _3dPositions.end()) {
img.position3d = it->second;
img.has3dCoords = true;
nImagesWith3dPositions++;
_nImagesWith3dPositions++;
}
}
std::vector<ImageData>& WWTDataHandler::getLoadedImages() {
return images;
std::vector<ImageData>& WwtDataHandler::getLoadedImages() {
return _images;
}
void WWTDataHandler::loadSpeckData(speck::Dataset& dataset) {
void WwtDataHandler::loadSpeckData(speck::Dataset& dataset) {
for (speck::Dataset::Entry entry : dataset.entries) {
if (entry.comment.has_value()) {
std::string name = createSearchableString(entry.comment.value());
@@ -310,7 +344,7 @@ namespace openspace {
LINFO("Loaded speck file with " + std::to_string(_3dPositions.size()) + " entries!");
}
std::string WWTDataHandler::createSearchableString(std::string str) {
std::string WwtDataHandler::createSearchableString(std::string str) {
// Remove white spaces and all special characters
str.erase(std::remove_if(str.begin(), str.end(), [](char c) {
bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c);
@@ -322,7 +356,6 @@ namespace openspace {
[](unsigned char c) { return std::tolower(c); });
return str;
}
}
// Loading of speck files

View File

@@ -498,25 +498,25 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() {
return scale;
}
glm::vec2 ScreenSpaceRenderable::getScreenSpacePosition() {
glm::vec2 ScreenSpaceRenderable::screenSpacePosition() {
return glm::vec2(_cartesianPosition.value().x, _cartesianPosition.value().y);
}
glm::vec2 ScreenSpaceRenderable::getScreenSpaceDimensions() {
glm::vec2 ScreenSpaceRenderable::screenSpaceDimensions() {
return glm::vec2(2.f * _scale * static_cast<float>(_objectSize.x) / static_cast<float>(_objectSize.y), 2.f * _scale);
}
glm::vec2 ScreenSpaceRenderable::getUpperRightCornerScreenSpace() {
return getScreenSpacePosition() + (getScreenSpaceDimensions() / 2.0f);
glm::vec2 ScreenSpaceRenderable::upperRightCornerScreenSpace() {
return screenSpacePosition() + (screenSpaceDimensions() / 2.0f);
}
glm::vec2 ScreenSpaceRenderable::getLowerLeftCornerScreenSpace() {
return getScreenSpacePosition() - (getScreenSpaceDimensions() / 2.0f);
glm::vec2 ScreenSpaceRenderable::lowerLeftCornerScreenSpace() {
return screenSpacePosition() - (screenSpaceDimensions() / 2.0f);
}
bool ScreenSpaceRenderable::coordIsInsideCornersScreenSpace(glm::vec2 coord) {
bool lessThanUpperRight = coord.x < getUpperRightCornerScreenSpace().x && coord.y < getUpperRightCornerScreenSpace().y;
bool moreThanLowerLeft = coord.x > getLowerLeftCornerScreenSpace().x && coord.y > getLowerLeftCornerScreenSpace().y;
bool lessThanUpperRight = coord.x < upperRightCornerScreenSpace().x && coord.y < upperRightCornerScreenSpace().y;
bool moreThanLowerLeft = coord.x > lowerLeftCornerScreenSpace().x && coord.y > lowerLeftCornerScreenSpace().y;
return lessThanUpperRight && moreThanLowerLeft;
}