mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-23 05:19:18 -06:00
Cleanup
This commit is contained in:
@@ -11,7 +11,7 @@ local browser = {
|
||||
Name = "Sky Browser",
|
||||
Url = serverUrl,
|
||||
FaceCamera = false,
|
||||
TargetID = targetId,
|
||||
TargetId = targetId,
|
||||
CartesianPosition = {-1.0, -0.5, -2.1},
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user