Fix comments from pull request

This commit is contained in:
sylvass
2022-03-02 16:39:44 -05:00
parent 02c9ef4a7a
commit 21e572149e
23 changed files with 1867 additions and 1861 deletions
+24 -29
View File
@@ -2,7 +2,7 @@
# #
# OpenSpace #
# #
# Copyright (c) 2014-2021 #
# Copyright (c) 2014-2022 #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
# software and associated documentation files (the "Software"), to deal in the Software #
@@ -25,40 +25,35 @@
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
set(HEADER_FILES
skybrowsermodule.h
include/screenspaceskytarget.h
include/wwtdatahandler.h
include/utility.h
include/targetbrowserpair.h
include/wwtcommunicator.h
include/browser.h
include/screenspaceskybrowser.h
ext/tinyxml2/tinyxml2.h
skybrowsermodule.h
include/screenspaceskytarget.h
include/wwtdatahandler.h
include/utility.h
include/targetbrowserpair.h
include/wwtcommunicator.h
include/browser.h
include/screenspaceskybrowser.h
ext/tinyxml2/tinyxml2.h
)
source_group("Header Files" FILES ${HEADER_FILES})
set(SOURCE_FILES
skybrowsermodule.cpp
skybrowsermodule_lua.inl
src/screenspaceskytarget.cpp
src/wwtdatahandler.cpp
src/utility.cpp
src/targetbrowserpair.cpp
src/wwtcommunicator.cpp
src/browser.cpp
src/screenspaceskybrowser.cpp
ext/tinyxml2/tinyxml2.cpp
skybrowsermodule.cpp
skybrowsermodule_lua.inl
src/screenspaceskytarget.cpp
src/wwtdatahandler.cpp
src/utility.cpp
src/targetbrowserpair.cpp
src/wwtcommunicator.cpp
src/browser.cpp
src/screenspaceskybrowser.cpp
ext/tinyxml2/tinyxml2.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
create_new_module(
"SkyBrowser"
skybrowser_module
STATIC
${HEADER_FILES} ${SOURCE_FILES}
"SkyBrowser"
skybrowser_module
STATIC
${HEADER_FILES} ${SOURCE_FILES}
)
+4 -5
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -25,8 +25,8 @@
#ifndef __OPENSPACE_MODULE_SKYBROWSER___BROWSER___H__
#define __OPENSPACE_MODULE_SKYBROWSER___BROWSER___H__
#include <openspace/documentation/documentation.h>
#include <modules/webbrowser/include/webrenderhandler.h>
#include <openspace/documentation/documentation.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/vector/vec2property.h>
#include <openspace/properties/triggerproperty.h>
@@ -61,9 +61,8 @@ class WebKeyboardHandler;
class Browser {
public:
Browser(const ghoul::Dictionary& dictionary);
Browser(Browser const&) = default;
~Browser();
explicit Browser(const ghoul::Dictionary& dictionary);
virtual ~Browser();
bool initializeGL();
bool deinitializeGL();
@@ -1,8 +1,33 @@
#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__
#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__
#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__
#include <openspace/rendering/screenspacerenderable.h>
#include <modules/skybrowser/include/wwtcommunicator.h>
#include <openspace/documentation/documentation.h>
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
@@ -10,58 +35,56 @@
namespace openspace {
class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator
{
public:
constexpr static const double FovThreshold = 0.001f;
class ScreenSpaceSkyBrowser : public ScreenSpaceRenderable, public WwtCommunicator
{
public:
constexpr static const double FovThreshold = 0.001;
// Constructor and destructor
ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary);
~ScreenSpaceSkyBrowser();
explicit ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary);
~ScreenSpaceSkyBrowser();
// Inherited functions
bool initializeGL() override;
bool deinitializeGL() override;
glm::mat4 scaleMatrix() override;
void render() override;
void update() override;
bool initializeGL() override;
bool deinitializeGL() override;
glm::mat4 scaleMatrix() override;
void render() override;
void update() override;
// Animation
bool isAnimated();
void startFovAnimation(float fov);
void incrementallyAnimateToFov(float deltaTime);
// Animation
bool isAnimated() const;
void startFovAnimation(float fov);
void incrementallyAnimateToFov(float deltaTime);
// Getters
float opacity() const;
glm::vec2 size() const;
// Getters
float opacity() const;
glm::vec2 size() const;
// Setters
void setVerticalFovWithScroll(float scroll);
void setOpacity(float opacity);
void setScreenSpaceSize(const glm::vec2& newSize);
void updateScreenSpaceSize();
// Setters
void setVerticalFovWithScroll(float scroll);
void setOpacity(float opacity);
void setScreenSpaceSize(const glm::vec2& newSize);
void updateScreenSpaceSize();
glm::dvec2 fineTuneVector(glm::dvec2 drag);
void setIdInBrowser();
glm::dvec2 fineTuneVector(glm::dvec2 drag);
void setIdInBrowser();
void updateTextureResolution();
void updateTextureResolution();
private:
properties::DoubleProperty _animationSpeed;
properties::FloatProperty _textureQuality;
private:
properties::DoubleProperty _animationSpeed;
properties::FloatProperty _textureQuality;
void bindTexture() override;
void bindTexture() override;
// Flags
bool _isSyncedWithWwt{ false };
bool _isFovAnimated{ false };
bool _textureDimensionsIsDirty{ false };
bool _sizeIsDirty{ false };
// Flags
bool _isSyncedWithWwt = false;
bool _isFovAnimated = false;
bool _textureDimensionsIsDirty = false;
bool _sizeIsDirty = false;
// Animation of fieldOfView
float _endVfov{ 0.f };
glm::vec2 _size{ 0.5f };
};
}
// Animation of fieldOfView
float _endVfov = 0.f;
glm::vec2 _size = glm::vec2(0.5f);
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER2___H__
#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYBROWSER___H__
@@ -1,7 +1,32 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__
#define __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/documentation/documentation.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/scalar/doubleproperty.h>
@@ -10,92 +35,83 @@ namespace openspace::documentation { struct Documentation; }
namespace openspace {
class ScreenSpaceSkyBrowser;
class ScreenSpaceSkyBrowser;
class ScreenSpaceSkyTarget : public ScreenSpaceRenderable {
class ScreenSpaceSkyTarget : public ScreenSpaceRenderable {
public:
constexpr static const float DeltaTimeThreshold = 0.03f;
public:
constexpr static const float DeltaTimeThreshold = 0.03f;
// Constructor & destructor
ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary);
virtual ~ScreenSpaceSkyTarget();
explicit ScreenSpaceSkyTarget(const ghoul::Dictionary& dictionary);
virtual ~ScreenSpaceSkyTarget();
// ScreenSpaceRenderable inherited functions
bool initializeGL() override;
bool deinitializeGL() override;
bool isReady() const override;
void render() override;
void update() override;
glm::mat4 scaleMatrix() override;
void bindTexture() override; // Empty function but has to be defined
void createShaders();
bool initializeGL() override;
bool deinitializeGL() override;
bool isReady() const override;
void render() override;
void update() override;
glm::mat4 scaleMatrix() override;
void bindTexture() override; // Empty function but has to be defined
void createShaders();
glm::ivec3 borderColor() const;
float opacity() const;
glm::dvec2 lockedCoordinates() const;
glm::ivec3 borderColor() const;
float opacity() const;
glm::dvec2 lockedCoordinates() const;
// Setters
void setScaleFromVfov(float verticalFov);
void setFovFromScale();
void setDimensions(glm::vec2 dimensions);
void setColor(glm::ivec3 color);
void setOpacity(float opacity);
void setLock(bool isLocked);
void setEquatorialAim(const glm::dvec2& aim);
void setScaleFromVfov(float verticalFov);
void setFovFromScale();
void setDimensions(glm::vec2 dimensions);
void setColor(glm::ivec3 color);
void setOpacity(float opacity);
void setLock(bool isLocked);
void setEquatorialAim(const glm::dvec2& aim);
// Target directions
glm::dvec3 directionGalactic() const;
glm::dvec2 equatorialAim() const;
// Target directions
glm::dvec3 directionGalactic() const;
glm::dvec2 equatorialAim() const;
// Locking functionality
bool isLocked() const;
// Locking functionality
bool isLocked() const;
// Animation
bool isAnimated();
void startAnimation(glm::dvec3 end, bool shouldLockAfter = true);
void incrementallyAnimateToCoordinate(float deltaTime);
// Display
void highlight(glm::ivec3 addition);
void removeHighlight(glm::ivec3 removal);
// Animation
bool isAnimated();
void startAnimation(glm::dvec3 end, bool shouldLockAfter = true);
void incrementallyAnimateToCoordinate(float deltaTime);
// Display
void highlight(glm::ivec3 addition);
void removeHighlight(glm::ivec3 removal);
private:
// Properties
properties::FloatProperty _showCrosshairThreshold;
properties::FloatProperty _showRectangleThreshold;
properties::FloatProperty _lineWidth;
properties::DoubleProperty _stopAnimationThreshold;
properties::DoubleProperty _animationSpeed;
private:
// Properties
properties::FloatProperty _showCrosshairThreshold;
properties::FloatProperty _showRectangleThreshold;
properties::FloatProperty _lineWidth;
properties::DoubleProperty _stopAnimationThreshold;
properties::DoubleProperty _animationSpeed;
// Flags
bool _isLocked{ false };
bool _isAnimated{ false };
bool _shouldLockAfterAnimation{ false };
// Flags
bool _isLocked = false;
bool _isAnimated = false;
bool _shouldLockAfterAnimation = false;
// Shader
UniformCache(
modelTransform,
viewProj,
showCrosshair,
showRectangle,
lineWidth,
dimensions,
lineColor) _uniformCache;
GLuint _vertexArray = 0;
GLuint _vertexBuffer = 0;
// Shader
UniformCache(modelTransform, viewProj, showCrosshair, showRectangle, lineWidth,
dimensions, lineColor) _uniformCache;
GLuint _vertexArray = 0;
GLuint _vertexBuffer = 0;
// Sky browser
float _verticalFov{ 70.0f };
glm::dvec2 _equatorialAim{ 0.0 };
glm::ivec3 _borderColor{ 255 };
// Sky browser
float _verticalFov = 70.0f;
glm::dvec2 _equatorialAim = glm::dvec2(0.0);
glm::ivec3 _borderColor = glm::ivec3(255);
// Lock target to a coordinate on the sky
glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates
// Lock target to a coordinate on the sky
glm::dvec3 _lockedCoordinates; // Cartesian equatorial coordinates
// Animation
glm::dvec3 _animationEnd; // Cartesian equatorial coordinates
glm::dvec3 _animationStart; // Cartesian equatorial coordinates
};
// Animation
glm::dvec3 _animationEnd; // Cartesian equatorial coordinates
glm::dvec3 _animationStart; // Cartesian equatorial coordinates
};
}
#endif // __OPENSPACE_MODULE_SKYBROWSER___SCREENSPACESKYTARGET___H__
+2 -10
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -37,13 +37,10 @@ class ImageData;
class TargetBrowserPair {
public:
constexpr static const float FadeThreshold = 0.01f;
constexpr static const double AnimationThreshold = 0.0001f;
TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target);
TargetBrowserPair(TargetBrowserPair const&) = default;
// user-defined copy assignment (copy-and-swap idiom)
TargetBrowserPair& operator=(TargetBrowserPair other);
// Target & Browser
@@ -73,14 +70,12 @@ public:
void lock();
void unlock();
// Boolean functions
bool hasFinishedFading(float goalState) const;
bool isFacingCamera() const;
bool isUsingRadiusAzimuthElevation() const;
bool isEnabled() const;
bool isLocked() const;
// Setters
void setEnabled(bool enable);
void setIsSyncedWithWwt(bool isSynced);
void setVerticalFov(float vfov);
@@ -90,7 +85,6 @@ public:
void setVerticalFovWithScroll(float scroll);
void setSelectedWithId(const std::string& id);
// Getters by value
float verticalFov() const;
glm::ivec3 borderColor() const;
glm::dvec2 targetDirectionEquatorial() const;
@@ -100,8 +94,7 @@ public:
std::string targetId() const;
std::string selectedId();
glm::vec2 size() const;
// Getters by reference
ScreenSpaceSkyTarget* getTarget();
ScreenSpaceSkyBrowser* getBrowser();
const std::deque<int>& getSelectedImages() const;
@@ -114,7 +107,6 @@ public:
void setImageOpacity(int i, float opacity);
void hideChromeInterface(bool shouldHide);
// Comparision operators
friend bool operator==(const TargetBrowserPair& lhs,
const TargetBrowserPair& rhs);
friend bool operator!=(const TargetBrowserPair& lhs,
+66 -48
View File
@@ -1,63 +1,81 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__
#define __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__
#include <openspace/documentation/documentation.h>
namespace openspace {
namespace skybrowser {
// 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();
namespace openspace::skybrowser {
// 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 - 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
});
// 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
});
// Galactic coordinates are projected onto the celestial sphere
// Equatorial coordinates are unit length
// Conversion spherical <-> Cartesian
glm::dvec2 cartesianToSpherical(const glm::dvec3& coords);
glm::dvec3 sphericalToCartesian(const glm::dvec2& coords);
// Galactic coordinates are projected onto the celestial sphere
// Equatorial coordinates are unit length
// Conversion spherical <-> Cartesian
glm::dvec2 cartesianToSpherical(const glm::dvec3& coords);
glm::dvec3 sphericalToCartesian(const glm::dvec2& coords);
// Conversion J2000 equatorial <-> galactic
glm::dvec3 galacticToEquatorial(const glm::dvec3& coords);
glm::dvec3 equatorialToGalactic(const glm::dvec3& coords);
// Conversion J2000 equatorial <-> galactic
glm::dvec3 galacticToEquatorial(const glm::dvec3& coords);
glm::dvec3 equatorialToGalactic(const glm::dvec3& coords);
// Conversion to screen space from local camera / pixels
glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords);
glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate);
// Conversion to screen space from local camera / pixels
glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords);
glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate);
// Conversion local camera space <-> galactic / equatorial
glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords);
glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords);
glm::dvec3 localCameraToGalactic(const glm::dvec3& coords);
glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords);
// Conversion local camera space <-> galactic / equatorial
glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords);
glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords);
glm::dvec3 localCameraToGalactic(const glm::dvec3& coords);
glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords);
// Camera roll and direction
double cameraRoll(); // Camera roll is with respect to the equatorial North Pole
glm::dvec3 cameraDirectionGalactic();
glm::dvec3 cameraDirectionEquatorial();
// Camera roll and direction
double cameraRoll(); // Camera roll is with respect to the equatorial North Pole
glm::dvec3 cameraDirectionGalactic();
glm::dvec3 cameraDirectionEquatorial();
// Window and field of view
float windowRatio();
glm::dvec2 fovWindow();
bool isCoordinateInView(const glm::dvec3& equatorial);
// Window and field of view
float windowRatio();
glm::dvec2 fovWindow();
bool isCoordinateInView(const glm::dvec3& equatorial);
// Animation for target and camera
double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end);
glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start,
const glm::dvec3& end,
double deltaTime,
double speedFactor = 1.0);
}
}
// Animation for target and camera
double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end);
glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end,
double deltaTime, double speedFactor = 1.0);
} // namespace openspace::skybrowser
#endif // __OPENSPACE_MODULE_SKYBROWSER___UTILITY___H__
+32 -41
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -26,6 +26,7 @@
#define __OPENSPACE_MODULE_SKYBROWSER___WWTCOMMUNICATOR___H__
#include <modules/skybrowser/include/browser.h>
#include <openspace/properties/vector/ivec3property.h>
#include <openspace/properties/vector/dvec2property.h>
#include <openspace/properties/scalar/floatproperty.h>
@@ -35,11 +36,10 @@
namespace openspace {
class WwtCommunicator : public Browser {
public:
WwtCommunicator(const ghoul::Dictionary& dictionary);
WwtCommunicator(WwtCommunicator const&) = default;
virtual ~WwtCommunicator();
explicit WwtCommunicator(const ghoul::Dictionary& dictionary);
WwtCommunicator(const WwtCommunicator&) = default;
~WwtCommunicator();
void update();
void render();
@@ -48,74 +48,65 @@ public:
// WorldWide Telescope communication
void displayImage(const std::string& url, int i);
void removeSelectedImage(const int i);
void removeSelectedImage(int i);
void setImageOrder(int i, int order);
void loadImageCollection(const std::string& collection);
void setImageOpacity(int i, float opacity);
void hideChromeInterface(bool shouldHide);
// Getters
const std::deque<int>& getSelectedImages();
glm::ivec3 borderColor() const;
float verticalFov() const;
glm::dvec2 fieldsOfView();
bool hasLoadedImages() const;
float verticalFov() const;
glm::ivec3 borderColor() const;
glm::dvec2 equatorialAim() const;
glm::dvec2 fieldsOfView() const;
const std::deque<int>& getSelectedImages() const;
// Setters
void setHasLoadedImages(bool isLoaded);
void setVerticalFov(float vfov);
void setIsSyncedWithWwt(bool isSynced);
void setEquatorialAim(const glm::dvec2& equatorial);
void setBorderColor(const glm::ivec3& color);
void setEquatorialAim(glm::dvec2 equatorial);
void setBorderColor(glm::ivec3 color);
// Display
void highlight(glm::ivec3 addition);
// The removal parameter decides what will be removed from the border color
void removeHighlight(glm::ivec3 removal);
void updateBorderColor();
void updateAim();
protected:
// Web page communication
void setIdInBrowser(const std::string& id);
glm::dvec2 _equatorialAim;
float _verticalFov{ 10.f };
glm::ivec3 _borderColor;
float _verticalFov = 10.f;
glm::ivec3 _borderColor = glm::ivec3(70);
glm::dvec2 _equatorialAim = glm::dvec2(0.0);
bool _hasLoadedImages = false;
std::deque<int> _selectedImages;
bool _hasLoadedImages{ false };
private:
bool _isSyncedWithWwt{ false };
bool _borderColorIsDirty{ false };
bool _equatorialAimIsDirty{ false };
void setWebpageBorderColor(glm::ivec3 color);
void sendMessageToWwt(const ghoul::Dictionary& msg);
int messageCounter{ 0 };
ghoul::Dictionary moveCamera(const glm::dvec2& celestCoords, double fov,
// WorldWide Telescope messages
ghoul::Dictionary moveCameraMessage(const glm::dvec2& celestCoords, double fov,
double roll, bool shouldMoveInstantly = true);
ghoul::Dictionary loadCollection(const std::string& url);
ghoul::Dictionary setForeground(const std::string& name);
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 version);
ghoul::Dictionary hideChromeGui(bool isHidden);
ghoul::Dictionary loadCollectionMessage(const std::string& url);
ghoul::Dictionary setForegroundMessage(const std::string& name);
ghoul::Dictionary addImageMessage(const std::string& id, const std::string& url);
ghoul::Dictionary removeImageMessage(const std::string& id);
ghoul::Dictionary setImageOpacityMessage(const std::string& id, double opacity);
ghoul::Dictionary setLayerOrderMessage(const std::string& id, int version);
ghoul::Dictionary hideChromeGuiMessage(bool isHidden); // Requires a newer CEF version
bool _isSyncedWithWwt = false;
bool _borderColorIsDirty = false;
bool _equatorialAimIsDirty = false;
int messageCounter{ 0 };
// Time variables
// For capping the message passing to WWT
constexpr static const std::chrono::milliseconds _timeUpdateInterval{ 10 };
constexpr static const std::chrono::milliseconds TimeUpdateInterval{ 10 };
std::chrono::system_clock::time_point _lastUpdateTime;
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_SKYBROWSER___WWTCOMMUNICATOR___H__
+51 -31
View File
@@ -1,3 +1,27 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__
#define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__
@@ -24,45 +48,41 @@ namespace openspace::wwt {
const std::string ZoomLevel = "ZoomLevel";
const std::string DataSetType = "DataSetType";
const std::string Sky = "Sky";
} // namespace openspace::wwt\
} // namespace openspace::wwt
namespace openspace {
struct ImageData {
std::string name{ wwt::Undefined };
std::string thumbnailUrl{ wwt::Undefined };
std::string imageUrl{ wwt::Undefined };
std::string credits{ wwt::Undefined };
std::string creditsUrl{ wwt::Undefined };
std::string collection{ wwt::Undefined };
bool hasCelestialCoords{ false };
float fov{ 0.f };
glm::dvec2 equatorialSpherical{ 0.0 };
glm::dvec3 equatorialCartesian{ 0.0 };
};
struct ImageData {
std::string name{ wwt::Undefined };
std::string thumbnailUrl{ wwt::Undefined };
std::string imageUrl{ wwt::Undefined };
std::string credits{ wwt::Undefined };
std::string creditsUrl{ wwt::Undefined };
std::string collection{ wwt::Undefined };
bool hasCelestialCoords = false;
float fov = 0.f;
glm::dvec2 equatorialSpherical = glm::dvec2(0.0);
glm::dvec3 equatorialCartesian = glm::dvec3(0.0);
};
class WwtDataHandler {
public:
WwtDataHandler() = default;
~WwtDataHandler();
class WwtDataHandler {
public:
WwtDataHandler() = default;
~WwtDataHandler();
void loadImages(const std::string& root, const std::string& directory);
int nLoadedImages() const;
const ImageData& getImage(int i) const;
void loadImages(const std::string& root, const std::filesystem::path& directory);
int nLoadedImages() const;
const ImageData& getImage(int i) const;
private:
void saveImageFromNode(tinyxml2::XMLElement* node, std::string collection);
void saveImagesFromXml(tinyxml2::XMLElement* root, std::string collection);
private:
void saveImageFromNode(tinyxml2::XMLElement* node, std::string collection);
void saveImagesFromXml(tinyxml2::XMLElement* root, std::string collection);
// Images
std::vector<ImageData> _images;
std::vector<tinyxml2::XMLDocument*> _xmls;
};
// Images
std::vector<ImageData> _images;
std::vector<tinyxml2::XMLDocument*> _xmls;
};
}
#endif // __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__
+49 -29
View File
@@ -1,65 +1,85 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
in vec2 vs_st;
in vec4 vs_position;
uniform float lineWidth;
uniform vec2 dimensions;
uniform bool showCrosshair;
uniform bool showRectangle;
uniform vec4 lineColor;
in vec2 vs_st;
in vec4 vs_position;
// A factor which states how much thicker vertical lines are rendered than horizontal
// This compensates for the optical illusion that vertical lines appear thinner
#define VERTICAL_THICKNESS 1.15f
const float VerticalThickness = 1.15;
float createLine(in float lineCenter, in float lineWidth, in float coord) {
float createLine(float lineCenter, float lineWidth, float coord) {
// Calculate edges of line
float start_edge = lineCenter - (lineWidth * 0.5f);
float end_edge = lineCenter + (lineWidth * 0.5f);
float startEdge = lineCenter - (lineWidth * 0.5);
float endEdge = lineCenter + (lineWidth * 0.5);
// Create line
float line = step(start_edge, coord) - step(end_edge, coord);
return line;
return step(startEdge, coord) - step(endEdge, coord);
}
float createRectangle(in float linewidth_y, in float ratio, in vec2 coord) {
float createRectangle(float linewidthY, float ratio, vec2 coord) {
// Calculate the widths and centers for the lines
float linewidth_x = linewidth_y * ratio * VERTICAL_THICKNESS;
float linecenter_x = linewidth_x * 0.5f;
float linecenter_y = linewidth_y * 0.5f;
float linewidthX = linewidthY * ratio * VerticalThickness;
float linecenterX = linewidthX * 0.5;
float linecenterY = linewidthY * 0.5;
// Create the four lines for the rectangle
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);
float l = createLine(linecenterX, linewidthX, coord.x);
float r = createLine(1.0 - linecenterX, linewidthX, coord.x);
float b = createLine(linecenterY, linewidthY, coord.y);
float t = createLine(1.0 - linecenterY, linewidthY, coord.y);
// Add all lines together
return l + r + b + t;
}
float createCrosshair(in float linewidth, in float ratio, in vec2 coord) {
float center = 0.5f;
float crosshair_vertical = createLine(center, linewidth * ratio * VERTICAL_THICKNESS, coord.x);
float crosshair_horizontal = createLine(center, linewidth, coord.y);
const float Center = 0.5;
float crosshairVertical = createLine(Center, linewidth * ratio * VerticalThickness, coord.x);
float crosshairHorizontal = createLine(Center, linewidth, coord.y);
return crosshair_horizontal + crosshair_vertical;
return crosshairHorizontal + crosshairVertical;
}
#include "fragment.glsl"
Fragment getFragment() {
float ratio = dimensions.y / dimensions.x;
float crosshair = 0.0f;
float rectangle = 0.0f;
float crosshair = 0.0;
float rectangle = 0.0;
if(showCrosshair) {
if (showCrosshair) {
crosshair = createCrosshair(lineWidth, ratio, vs_st);
float border = 1.0f - createRectangle(lineWidth * 5.0f, ratio, vs_st);
float border = 1.0 - createRectangle(lineWidth * 5.0, ratio, vs_st);
crosshair *= border;
}
if(showRectangle) {
if (showRectangle) {
rectangle = createRectangle(lineWidth, ratio, vs_st);
}
+26 -3
View File
@@ -1,14 +1,37 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#version __CONTEXT__
out vec2 vs_st;
out vec4 vs_position;
uniform mat4 modelTransform;
uniform mat4 viewProj;
layout(location = 0) in vec4 in_position;
layout(location = 1) in vec2 in_st;
out vec2 vs_st;
out vec4 vs_position;
void main(){
vs_st = in_st;
vs_position = viewProj * modelTransform * in_position;
+77 -108
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -22,7 +22,6 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/skybrowser/skybrowsermodule.h>
#include <modules/skybrowser/include/screenspaceskybrowser.h>
@@ -30,7 +29,6 @@
#include <modules/skybrowser/include/screenspaceskytarget.h>
#include <modules/skybrowser/include/wwtdatahandler.h>
#include <modules/base/rendering/screenspaceimagelocal.h>
#include "skybrowsermodule_lua.inl"
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/engine/globalscallbacks.h>
@@ -39,9 +37,9 @@
#include <openspace/camera/camera.h>
#include <openspace/util/factorymanager.h>
#include "skybrowsermodule_lua.inl"
namespace {
constexpr const openspace::properties::Property::PropertyInfo AllowInteractionInfo =
{
"AllowMouseInteraction",
@@ -69,11 +67,8 @@ namespace {
#include "skybrowsermodule_codegen.cpp"
} // namespace
namespace openspace {
scripting::LuaLibrary SkyBrowserModule::luaLibrary() const {
scripting::LuaLibrary res;
res.name = "skybrowser";
res.functions = {
@@ -263,8 +258,6 @@ namespace openspace {
return res;
}
SkyBrowserModule::SkyBrowserModule()
: OpenSpaceModule(SkyBrowserModule::Name)
, _allowMouseInteraction(AllowInteractionInfo, true)
@@ -276,7 +269,6 @@ SkyBrowserModule::SkyBrowserModule()
// Set callback functions
global::callback::mouseButton->emplace_back(
[&](MouseButton button, MouseAction action, KeyModifier modifier) -> bool {
if (!_isCameraInSolarSystem || !_allowMouseInteraction) {
return false;
}
@@ -304,7 +296,6 @@ SkyBrowserModule::SkyBrowserModule()
if (global::windowDelegate->isMaster()) {
global::callback::mousePosition->emplace_back(
[&](double x, double y) {
if (!_isCameraInSolarSystem || !_allowMouseInteraction) {
return false;
}
@@ -314,30 +305,25 @@ SkyBrowserModule::SkyBrowserModule()
glm::vec2 translation = _mousePosition - _startMousePosition;
switch (_interactionMode) {
case MouseInteraction::Hover:
setSelectedObject();
break;
case MouseInteraction::Drag:
_mouseOnPair->translateSelected(_startDragPosition, translation);
break;
case MouseInteraction::FineTune:
_mouseOnPair->fineTuneTarget(_startDragPosition, translation);
break;
default:
setSelectedObject();
break;
}
case MouseInteraction::Hover:
setSelectedObject();
break;
case MouseInteraction::Drag:
_mouseOnPair->translateSelected(_startDragPosition, translation);
break;
case MouseInteraction::FineTune:
_mouseOnPair->fineTuneTarget(_startDragPosition, translation);
break;
default:
setSelectedObject();
break;
}
return false;
}
);
global::callback::mouseScrollWheel->emplace_back(
[&](double, double scroll) -> bool {
if (!_isCameraInSolarSystem || !_mouseOnPair || !_allowMouseInteraction) {
return false;
}
@@ -351,7 +337,6 @@ SkyBrowserModule::SkyBrowserModule()
}
global::callback::preSync->emplace_back([this]() {
// Disable browser and targets when camera is outside of solar system
bool camWasInSolarSystem = _isCameraInSolarSystem;
glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3();
@@ -375,10 +360,13 @@ SkyBrowserModule::SkyBrowserModule()
incrementallyFadeBrowserTargets(_goal, deltaTime);
}
if (_isCameraInSolarSystem) {
std::for_each(std::begin(_targetsBrowsers), std::end(_targetsBrowsers),
std::for_each(
_targetsBrowsers.begin(),
_targetsBrowsers.end(),
[&](const std::unique_ptr<TargetBrowserPair>& pair) {
pair->synchronizeAim();
});
}
);
incrementallyAnimateTargets(deltaTime);
}
if (_isCameraRotating && _allowCameraRotation) {
@@ -387,18 +375,12 @@ SkyBrowserModule::SkyBrowserModule()
});
}
SkyBrowserModule::~SkyBrowserModule() {
}
void SkyBrowserModule::internalDeinitialize() {
}
void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) {
const Parameters p = codegen::bake<Parameters>(dict);
// Register ScreenSpaceRenderable
auto fScreenSpaceRenderable = FactoryManager::ref().factory<ScreenSpaceRenderable>();
ghoul::TemplateFactory<ScreenSpaceRenderable>* fScreenSpaceRenderable =
FactoryManager::ref().factory<ScreenSpaceRenderable>();
ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created");
// Register ScreenSpaceSkyTarget
@@ -412,8 +394,7 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) {
_dataHandler = std::make_unique<WwtDataHandler>();
}
void SkyBrowserModule::setSelectedObject()
{
void SkyBrowserModule::setSelectedObject() {
if (_interactionMode != MouseInteraction::Hover) {
return;
}
@@ -421,13 +402,15 @@ void SkyBrowserModule::setSelectedObject()
TargetBrowserPair* previousPair = _mouseOnPair;
// Find and save what mouse is currently hovering on
auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers),
auto it = std::find_if(
_targetsBrowsers.begin(),
_targetsBrowsers.end(),
[&] (const std::unique_ptr<TargetBrowserPair> &pair) {
return pair->checkMouseIntersection(_mousePosition) &&
!pair->isUsingRadiusAzimuthElevation();
});
if (it == std::end(_targetsBrowsers)) {
if (it == _targetsBrowsers.end()) {
_mouseOnPair = nullptr;
}
else {
@@ -436,7 +419,6 @@ void SkyBrowserModule::setSelectedObject()
// Selection has changed
if (previousPair != _mouseOnPair) {
// Remove highlight
if (previousPair) {
previousPair->removeHighlight(_highlightAddition);
@@ -449,13 +431,12 @@ void SkyBrowserModule::setSelectedObject()
}
void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const std::string& browserId) {
ScreenSpaceSkyTarget* target = dynamic_cast<ScreenSpaceSkyTarget*>(
global::renderEngine->screenSpaceRenderable(targetId)
);
);
ScreenSpaceSkyBrowser* browser = dynamic_cast<ScreenSpaceSkyBrowser*>(
global::renderEngine->screenSpaceRenderable(browserId)
);
);
// Ensure pair has both target and browser
if (browser && target) {
@@ -464,36 +445,35 @@ void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId, const s
}
void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) {
TargetBrowserPair* found = getPair(id);
if (!found) {
return;
}
auto it = std::remove_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers),
auto it = std::remove_if(
_targetsBrowsers.begin(),
_targetsBrowsers.end(),
[&](const std::unique_ptr<TargetBrowserPair>& pair) {
return *found == *(pair.get());
});
}
);
_targetsBrowsers.erase(it, std::end(_targetsBrowsers));
_targetsBrowsers.erase(it, _targetsBrowsers.end());
_mouseOnPair = nullptr;
}
void SkyBrowserModule::lookAtTarget(std::string id)
{
void SkyBrowserModule::lookAtTarget(const std::string& id) {
TargetBrowserPair* pair = getPair(id);
if (pair) {
startRotatingCamera(pair->targetDirectionGalactic());
}
}
void SkyBrowserModule::setHoverCircle(ScreenSpaceImageLocal* circle)
{
void SkyBrowserModule::setHoverCircle(ScreenSpaceImageLocal* circle) {
_hoverCircle = circle;
}
void SkyBrowserModule::moveHoverCircle(int i)
{
void SkyBrowserModule::moveHoverCircle(int i) {
const ImageData& image = _dataHandler->getImage(i);
// Only move and show circle if the image has coordinates
@@ -516,25 +496,22 @@ void SkyBrowserModule::moveHoverCircle(int i)
}
}
void SkyBrowserModule::disableHoverCircle()
{
void SkyBrowserModule::disableHoverCircle() {
if (_hoverCircle && _hoverCircle->isEnabled()) {
_hoverCircle->setEnabled(false);
}
}
void SkyBrowserModule::loadImages(const std::string& root, const std::string& directory)
{
void SkyBrowserModule::loadImages(const std::string& root,
const std::filesystem::path& directory) {
_dataHandler->loadImages(root, directory);
}
int SkyBrowserModule::nLoadedImages()
{
int SkyBrowserModule::nLoadedImages() {
return _dataHandler->nLoadedImages();
}
void SkyBrowserModule::handleMouseClick(const MouseButton& button)
{
void SkyBrowserModule::handleMouseClick(const MouseButton& button) {
setSelectedBrowser(_mouseOnPair->browserId());
if (button == MouseButton::Left) {
@@ -561,28 +538,28 @@ void SkyBrowserModule::handleMouseClick(const MouseButton& button)
}
}
const std::unique_ptr<WwtDataHandler>& SkyBrowserModule::getWwtDataHandler() {
const std::unique_ptr<WwtDataHandler>& SkyBrowserModule::getWwtDataHandler() const {
return _dataHandler;
}
std::vector<std::unique_ptr<TargetBrowserPair>>& SkyBrowserModule::getPairs()
{
std::vector<std::unique_ptr<TargetBrowserPair>>& SkyBrowserModule::getPairs() {
return _targetsBrowsers;
}
int SkyBrowserModule::nPairs()
{
int SkyBrowserModule::nPairs() {
return static_cast<int>(_targetsBrowsers.size());
}
TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id)
{
auto it = std::find_if(std::begin(_targetsBrowsers), std::end(_targetsBrowsers),
TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) {
auto it = std::find_if(
_targetsBrowsers.begin(),
_targetsBrowsers.end(),
[&](const std::unique_ptr<TargetBrowserPair>& pair) {
bool foundBrowser = pair->browserId() == id;
bool foundTarget = pair->targetId() == id;
return foundBrowser || foundTarget;
});
}
);
if (it == std::end(_targetsBrowsers)) {
return nullptr;
}
@@ -623,16 +600,17 @@ void SkyBrowserModule::incrementallyRotateCamera(double deltaTime) {
}
}
void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float deltaTime)
void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal,
float deltaTime)
{
float transparency = [](Transparency goal) {
switch (goal) {
case Transparency::Transparent:
return 0.f;
case Transparency::Transparent:
return 0.f;
case Transparency::Opaque:
return 1.f;
}
case Transparency::Opaque:
return 1.f;
}
}(goal);
bool isAllFinished{ false };
@@ -655,8 +633,7 @@ void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal, float
}
}
void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime)
{
void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime) {
for (std::unique_ptr<TargetBrowserPair>& pair : _targetsBrowsers) {
if (pair->isEnabled()) {
pair->incrementallyAnimateToCoordinate(deltaTime);
@@ -665,59 +642,51 @@ void SkyBrowserModule::incrementallyAnimateTargets(double deltaTime)
}
void SkyBrowserModule::setSelectedBrowser(const std::string& id) {
if (getPair(id)) {
TargetBrowserPair* found = getPair(id);
if (found) {
_selectedBrowser = id;
}
}
std::string SkyBrowserModule::selectedBrowserId() {
std::string SkyBrowserModule::selectedBrowserId() const {
return _selectedBrowser;
}
std::string SkyBrowserModule::selectedTargetId()
{
if (getPair(_selectedBrowser)) {
return getPair(_selectedBrowser)->targetId();
std::string SkyBrowserModule::selectedTargetId() {
TargetBrowserPair* found = getPair(_selectedBrowser);
if (found) {
return found->targetId();
}
else {
return "";
}
}
glm::ivec3 SkyBrowserModule::highlight()
{
glm::ivec3 SkyBrowserModule::highlight() const {
return _highlightAddition;
}
bool SkyBrowserModule::isCameraInSolarSystem() {
bool SkyBrowserModule::isCameraInSolarSystem() const {
return _isCameraInSolarSystem;
}
bool SkyBrowserModule::isSelectedPairUsingRae()
{
if (getPair(_selectedBrowser)) {
return getPair(_selectedBrowser)->isUsingRadiusAzimuthElevation();
bool SkyBrowserModule::isSelectedPairUsingRae() {
TargetBrowserPair* found = getPair(_selectedBrowser);
if (found) {
return found->isUsingRadiusAzimuthElevation();
}
else {
return false;
}
}
bool SkyBrowserModule::isSelectedPairFacingCamera()
{
if (getPair(_selectedBrowser)) {
return getPair(_selectedBrowser)->isFacingCamera();
bool SkyBrowserModule::isSelectedPairFacingCamera() {
TargetBrowserPair* found = getPair(_selectedBrowser);
if (found) {
return found->isFacingCamera();
}
else {
return false;
}
}
//std::vector<documentation::Documentation> SkyBrowserModule::documentations() const {
// return {
// ExoplanetsDataPreparationTask::documentation(),
// RenderableOrbitDisc::Documentation()
// };
//}
} // namespace openspace
+17 -24
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -25,8 +25,9 @@
#ifndef __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__
#define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__
#include <openspace/documentation/documentation.h>
#include <openspace/util/openspacemodule.h>
#include <openspace/documentation/documentation.h>
#include <openspace/util/distanceconstants.h>
#include <openspace/util/mouse.h>
#include <openspace/properties/scalar/boolproperty.h>
@@ -53,40 +54,34 @@ enum class MouseInteraction {
class SkyBrowserModule : public OpenSpaceModule {
public:
constexpr static const char* Name = "SkyBrowser";
constexpr static const double StopAnimationThreshold{ 0.0005 };
constexpr static const double FadingTime = { 2.0 };
constexpr static const double AnimationSpeed = { 1.0 };
constexpr static const double StopAnimationThreshold = 0.0005;
constexpr static const double FadingTime = 2.0;
constexpr static const double AnimationSpeed = 1.0;
const double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit;
// Constructor & destructor
SkyBrowserModule();
virtual ~SkyBrowserModule();
// Getters
std::vector<std::unique_ptr<TargetBrowserPair>>& getPairs();
int nPairs();
TargetBrowserPair* getPair(const std::string& id);
const std::unique_ptr<WwtDataHandler>& getWwtDataHandler();
std::string selectedBrowserId();
const std::unique_ptr<WwtDataHandler>& getWwtDataHandler() const;
std::string selectedBrowserId() const;
std::string selectedTargetId();
glm::ivec3 highlight();
glm::ivec3 highlight() const;
// Setters
void setSelectedBrowser(const std::string& id);
void setSelectedObject(); // Manage mouse interactions
void setHoverCircle(ScreenSpaceImageLocal* circle);
// Rotation, animation, placement
void lookAtTarget(std::string id);
void lookAtTarget(const std::string& id);
void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate
void incrementallyRotateCamera(double deltaTime);
void incrementallyFadeBrowserTargets(Transparency goal, float deltaTime);
void incrementallyAnimateTargets(double deltaTime);
// Boolean functions
bool isCameraInSolarSystem();
bool isCameraInSolarSystem() const;
bool isSelectedPairFacingCamera();
bool isSelectedPairUsingRae();
@@ -99,7 +94,7 @@ public:
void disableHoverCircle();
// Image collection handling
void loadImages(const std::string& root, const std::string& directory);
void loadImages(const std::string& root, const std::filesystem::path& directory);
int nLoadedImages();
// Mouse interaction
@@ -110,21 +105,20 @@ public:
protected:
void internalInitialize(const ghoul::Dictionary& dict) override;
void internalDeinitialize() override;
private:
properties::BoolProperty _allowMouseInteraction;
properties::BoolProperty _allowCameraRotation;
glm::ivec3 _highlightAddition{ 35 }; // Highlight object when mouse hovers
glm::ivec3 _highlightAddition = glm::ivec3(35); // Highlight object when mouse hovers
// The browsers and targets
std::vector<std::unique_ptr<TargetBrowserPair>> _targetsBrowsers;
TargetBrowserPair* _mouseOnPair{ nullptr };
ScreenSpaceImageLocal* _hoverCircle{ nullptr };
std::string _selectedBrowser{ "" }; // Currently selected browser
TargetBrowserPair* _mouseOnPair = nullptr;
ScreenSpaceImageLocal* _hoverCircle = nullptr;
std::string _selectedBrowser = ""; // Currently selected browser
// Fading
Transparency _goal;
Transparency _goal = Transparency::Opaque;
// Flags
bool _isCameraInSolarSystem{ true }; // Visualization modes
@@ -144,7 +138,6 @@ private:
// Data handler for the image collections
std::unique_ptr<WwtDataHandler> _dataHandler;
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__
+107 -120
View File
@@ -1,3 +1,26 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/skybrowser/skybrowsermodule.h>
@@ -11,37 +34,36 @@
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char _loggerCat[] = "SkyBrowserModule";
constexpr const char _loggerCat[] = "SkyBrowserModule";
} // namespace
namespace openspace::skybrowser::luascriptfunctions {
int selectImage(lua_State* L) {
// Load image
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage");
const int i = ghoul::lua::value<int>(L, 1);
// Load image
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::selectImage");
const int i = ghoul::lua::value<int>(L, 1);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
if (module->isCameraInSolarSystem()) {
TargetBrowserPair* selected = module->getPair(module->selectedBrowserId());
if (selected) {
const ImageData& image = module->getWwtDataHandler()->getImage(i);
// Load image into browser
LINFO("Loading image " + image.name);
selected->selectImage(image, i);
bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian);
bool isInView = isCoordinateInView(image.equatorialCartesian);
// If the coordinate is not in view, rotate camera
if (image.hasCelestialCoords && !isInView) {
module->startRotatingCamera(
skybrowser::equatorialToGalactic(image.equatorialCartesian)
equatorialToGalactic(image.equatorialCartesian)
);
}
}
}
return 0;
return 0;
}
int setHoverCircle(lua_State* L) {
@@ -96,9 +118,8 @@ int unlockTarget(lua_State* L) {
int setImageLayerOrder(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setImageLayerOrder");
const std::string id = ghoul::lua::value<std::string>(L, 1);
const int i = ghoul::lua::value<int>(L, 1);
int order = ghoul::lua::value<int>(L, 1);
auto [id, i, order] = ghoul::lua::values<std::string, int, int>(L);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
if (module->getPair(id)) {
@@ -106,10 +127,10 @@ int setImageLayerOrder(lua_State* L) {
}
return 0;
}
int loadImagesToWWT(lua_State* L) {
// Load images from url
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT");
// Load images from url
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadImagesToWWT");
const std::string id = ghoul::lua::value<std::string>(L, 1);
LINFO("Connection established to WorldWide Telescope application in " + id);
LINFO("Loading image collections to " + id);
@@ -122,11 +143,11 @@ int loadImagesToWWT(lua_State* L) {
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
if (module->getPair(id)) {
//module->getPair(id)->hideChromeInterface(true);
module->getPair(id)->hideChromeInterface(true);
module->getPair(id)->loadImageCollection(root);
}
return 0;
return 0;
}
int startSetup(lua_State* L) {
@@ -140,12 +161,15 @@ int startSetup(lua_State* L) {
for (std::unique_ptr<TargetBrowserPair>& pair : pairs) {
std::string id = pair->browserId();
glm::ivec3 color = pair->borderColor();
openspace::global::scriptEngine->queueScript(
"openspace.skybrowser.setBorderColor('" + id + "'," +
std::to_string(color.r) + "," +
std::to_string(color.g) + "," +
std::to_string(color.b) + "" +
");",
std::string script = fmt::format(
"openspace.skybrowser.setBorderColor('{}', {}, {}, {})",
id,
color.r,
color.g,
color.b
);
global::scriptEngine->queueScript(
script,
scripting::ScriptEngine::RemoteScripting::Yes
);
}
@@ -153,7 +177,7 @@ int startSetup(lua_State* L) {
// To ensure each node in a cluster calls its own instance of the wwt application
// Do not send this script to the other nodes
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.skybrowser.sendOutIdsToBrowsers();",
scripting::ScriptEngine::RemoteScripting::No
);
@@ -165,7 +189,7 @@ int sendOutIdsToBrowsers(lua_State* L) {
// This is called when the sky_browser website is connected to OpenSpace
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::sendOutIdsToBrowsers");
// Send out ID's to the browsers
// Send out identifiers to the browsers
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
std::vector<std::unique_ptr<TargetBrowserPair>>& pairs = module->getPairs();
for (std::unique_ptr<TargetBrowserPair>& pair : pairs) {
@@ -182,9 +206,10 @@ int initializeBrowser(lua_State* L) {
LINFO("Initializing sky browser " + id);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
if (module->getPair(id)) {
module->getPair(id)->setIsSyncedWithWwt(true);
module->getPair(id)->initialize();
TargetBrowserPair* found = module->getPair(id);
if (found) {
found->setIsSyncedWithWwt(true);
found->initialize();
}
return 0;
@@ -192,12 +217,11 @@ int initializeBrowser(lua_State* L) {
int addPairToSkyBrowserModule(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addPairToSkyBrowserModule");
const std::string targetId = ghoul::lua::value<std::string>(L, 1);
const std::string browserId = ghoul::lua::value<std::string>(L, 1);
auto [targetId, browserId] = ghoul::lua::values<std::string, std::string>(L);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
LINFO("Add browser " + browserId + " to sky browser module.");
LINFO("Add target " + targetId + " to sky browser module.");
LINFO("Add browser " + browserId + " to sky browser module");
LINFO("Add target " + targetId + " to sky browser module");
module->addTargetBrowserPair(targetId, browserId);
@@ -205,30 +229,26 @@ int addPairToSkyBrowserModule(lua_State* L) {
}
int getListOfImages(lua_State* L) {
// Send image list to GUI
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages");
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
// Send image list to GUI
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfImages");
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
// If no data has been loaded yet, download the data from the web!
// If no data has been loaded yet, download the data from the web!
if (module->nLoadedImages() == 0) {
if (module->nLoadedImages() == 0) {
std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/"
"wwt-web-client/master/assets/webclient-explore-root.wtml";
std::string directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/").string();
std::filesystem::path directory = absPath("${MODULE_SKYBROWSER}/WWTimagedata/");
module->loadImages(root, directory);
}
}
// Create Lua table to send to the GUI
lua_newtable(L);
for (int i = 0; i < module->nLoadedImages(); i++) {
for (int i = 0; i < module->nLoadedImages(); i++) {
const ImageData& img = module->getWwtDataHandler()->getImage(i);
glm::dvec3 coords = img.equatorialCartesian;
// Conversions for ghoul
std::vector<double> cartCoordsVec = { coords.x, coords.y, coords.z };
// Index for current ImageData
ghoul::lua::push(L, i + 1);
@@ -242,7 +262,7 @@ int getListOfImages(lua_State* L) {
lua_settable(L, -3);
ghoul::lua::push(L, "dec", img.equatorialSpherical.y);
lua_settable(L, -3);
ghoul::lua::push(L, "cartesianDirection", cartCoordsVec);
ghoul::lua::push(L, "cartesianDirection", img.equatorialCartesian);
lua_settable(L, -3);
ghoul::lua::push(L, "hasCelestialCoords", img.hasCelestialCoords);
lua_settable(L, -3);
@@ -255,9 +275,9 @@ int getListOfImages(lua_State* L) {
// Set table for the current ImageData
lua_settable(L, -3);
}
}
return 1;
return 1;
}
int getTargetData(lua_State* L) {
@@ -273,20 +293,14 @@ int getTargetData(lua_State* L) {
lua_newtable(L);
glm::dvec3 cartesianCam = skybrowser::cameraDirectionEquatorial();
glm::dvec2 sphericalCam = skybrowser::cartesianToSpherical(cartesianCam);
// Convert to vector so ghoul can read it
std::vector<double> viewDirCelestVec = {
cartesianCam.x,
cartesianCam.y,
cartesianCam.z
};
// Calculate the smallest FOV of vertical and horizontal
glm::dvec2 fovs = skybrowser::fovWindow();
double FOV = std::min(fovs.x, fovs.y);
// Push window data
ghoul::lua::push(L, "windowHFOV", FOV);
lua_settable(L, -3);
ghoul::lua::push(L, "cartesianDirection", viewDirCelestVec);
ghoul::lua::push(L, "cartesianDirection", cartesianCam);
lua_settable(L, -3);
ghoul::lua::push(L, "ra", sphericalCam.x);
lua_settable(L, -3);
@@ -314,26 +328,16 @@ int getTargetData(lua_State* L) {
// Convert deque to vector so ghoul can read it
std::vector<int> selectedImagesVector;
const std::deque<int> selectedImages = pair->getSelectedImages();
std::for_each(selectedImages.begin(), selectedImages.end(), [&](int i) {
selectedImagesVector.push_back(i);
});
std::for_each(
selectedImages.begin(),
selectedImages.end(),
[&](int i) {
selectedImagesVector.push_back(i);
}
);
glm::dvec2 spherical = pair->targetDirectionEquatorial();
glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical);
std::vector<double> cartesianVec = {
cartesian.x,
cartesian.y,
cartesian.z
};
// Convert color to vector so ghoul can read it
glm::ivec3 color = pair->borderColor();
std::vector<int> colorVec = { color.r, color.g, color.b };
// Convert color to vector so ghoul can read it
glm::vec2 size = pair->size();
std::vector<float> sizeVec = { size.x, size.y };
ghoul::lua::push(L, id);
lua_newtable(L);
@@ -346,49 +350,47 @@ int getTargetData(lua_State* L) {
lua_settable(L, -3);
ghoul::lua::push(L, "selectedImages", selectedImagesVector);
lua_settable(L, -3);
ghoul::lua::push(L, "cartesianDirection", cartesianVec);
ghoul::lua::push(L, "cartesianDirection", cartesian);
lua_settable(L, -3);
ghoul::lua::push(L, "ra", spherical.x);
lua_settable(L, -3);
ghoul::lua::push(L, "dec", spherical.y);
lua_settable(L, -3);
ghoul::lua::push(L, "color", colorVec);
ghoul::lua::push(L, "color", pair->borderColor());
lua_settable(L, -3);
ghoul::lua::push(L, "isLocked", pair->isLocked());
lua_settable(L, -3);
ghoul::lua::push(L, "size", sizeVec);
ghoul::lua::push(L, "size", pair->size());
lua_settable(L, -3);
// Set table for the current target
lua_settable(L, -3);
}
}
return 1;
}
int adjustCamera(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera");
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::adjustCamera");
const std::string id = ghoul::lua::value<std::string>(L, 1);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
if(module->isCameraInSolarSystem()) {
if (module->isCameraInSolarSystem()) {
module->lookAtTarget(id);
}
return 0;
return 0;
}
int setOpacityOfImageLayer(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setOpacityOfImageLayer");
const std::string id = ghoul::lua::value<std::string>(L, 1);
const int i = ghoul::lua::value<int>(L, 1);
double opacity = ghoul::lua::value<double>(L, 1);
auto [id, i, opacity] = ghoul::lua::values<std::string, int, double>(L);
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
if (module->getPair(id)) {
module->getPair(id)->setImageOpacity(i, opacity);
TargetBrowserPair* found = module->getPair(id);
if (found) {
found->setImageOpacity(i, opacity);
}
return 0;
@@ -444,23 +446,23 @@ int createTargetBrowserPair(lua_State* L) {
"FaceCamera = false,"
"}";
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.addScreenSpaceRenderable(" + browser + ");",
scripting::ScriptEngine::RemoteScripting::No
);
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.addScreenSpaceRenderable(" + target + ");",
scripting::ScriptEngine::RemoteScripting::No
);
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.skybrowser.addPairToSkyBrowserModule('" + idTarget + "','"
+ idBrowser + "');",
scripting::ScriptEngine::RemoteScripting::No
);
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.skybrowser.setSelectedBrowser('" + idBrowser + "');",
scripting::ScriptEngine::RemoteScripting::No
);
@@ -476,45 +478,42 @@ int removeTargetBrowserPair(lua_State* L) {
if (found) {
std::string browser = found->browserId();
std::string target = found->targetId();
found = nullptr;
module->removeTargetBrowserPair(id);
// Remove from engine
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.removeScreenSpaceRenderable('" + browser + "');",
scripting::ScriptEngine::RemoteScripting::Yes
);
openspace::global::scriptEngine->queueScript(
global::scriptEngine->queueScript(
"openspace.removeScreenSpaceRenderable('" + target + "');",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
return 0;
}
int translateScreenSpaceRenderable(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 5, "lua::translateScreenSpaceRenderable");
const std::string id = ghoul::lua::value<std::string>(L, 1);
float startX = ghoul::lua::value<float>(L, 1);
float startY = ghoul::lua::value<float>(L, 1);
float transX = ghoul::lua::value<float>(L, 1);
float transY = ghoul::lua::value<float>(L, 1);
auto [id, startX, startY, transX, transY] =
ghoul::lua::values<std::string, float, float, float, float>(L);
ScreenSpaceRenderable* renderable = global::renderEngine->screenSpaceRenderable(id);
renderable->translate(glm::vec2(transX, transY), glm::vec2(startX, startY));
if (renderable) {
renderable->translate(glm::vec2(transX, transY), glm::vec2(startX, startY));
}
return 0;
}
int removeSelectedImageInBrowser(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeSelectedImageInBrowser");
const std::string id = ghoul::lua::value<std::string>(L, 1);
// Image index
const int i = ghoul::lua::value<int>(L, 1);
auto [id, i] = ghoul::lua::values<std::string, int>(L);
// Get browser
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
const ImageData& image = module->getWwtDataHandler()->getImage(i);
@@ -529,10 +528,7 @@ int removeSelectedImageInBrowser(lua_State* L) {
int setEquatorialAim(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setEquatorialAim");
// Browser id
const std::string id = ghoul::lua::value<std::string>(L, 1);
double ra = ghoul::lua::value<double>(L, 1);
double dec = ghoul::lua::value<double>(L, 1);
auto [id, ra, dec] = ghoul::lua::values<std::string, double, double>(L);
// Get module
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
@@ -547,9 +543,7 @@ int setEquatorialAim(lua_State* L) {
int setVerticalFov(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setVerticalFov");
// Browser id
const std::string id = ghoul::lua::value<std::string>(L, 1);
float vfov = ghoul::lua::value<float>(L, 1);
auto [id, vfov] = ghoul::lua::values<std::string, float>(L);
// Get module
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
@@ -564,11 +558,8 @@ int setVerticalFov(lua_State* L) {
int setBorderColor(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::setBorderColor");
// Browser id
const std::string id = ghoul::lua::value<std::string>(L, 1);
int r = ghoul::lua::value<int>(L, 1);
int g = ghoul::lua::value<int>(L, 1);
int b = ghoul::lua::value<int>(L, 1);
auto [id, r, g, b] = ghoul::lua::values<std::string, int, int, int>(L);
glm::ivec3 color{ r, g, b };
// Get module
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
@@ -583,10 +574,7 @@ int setBorderColor(lua_State* L) {
int setScreenSpaceSize(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setScreenSpaceSize");
// Browser id
const std::string id = ghoul::lua::value<std::string>(L, 1);
float sizeX = ghoul::lua::value<float>(L, 1);
float sizeY = ghoul::lua::value<float>(L, 1);
auto [id, sizeX, sizeY] = ghoul::lua::values<std::string, float, float>(L);
// Get module
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
@@ -597,6 +585,5 @@ int setScreenSpaceSize(lua_State* L) {
}
return 0;
}
}
} // namespace openspace::skybrowser::luafunctions
+145 -137
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -32,7 +32,6 @@
#include <openspace/engine/moduleengine.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/logging/logmanager.h>
#include <apps\OpenSpace\ext\sgct\include\sgct\utils\box.h>
namespace {
constexpr const char* _loggerCat = "Browser";
@@ -42,6 +41,7 @@ namespace {
"Browser Dimensions",
"Set the dimensions of the web browser window."
};
const openspace::properties::Property::PropertyInfo UrlInfo = {
"Url",
"URL",
@@ -54,158 +54,166 @@ namespace {
"Reload the web browser"
};
struct [[codegen::Dictionary(Browser)]] Parameters {
// [[codegen::verbatim(DimensionsInfo.description)]]
std::optional<glm::vec2> dimensions;
// [[codegen::verbatim(UrlInfo.description)]]
std::optional<std::string> url;
// [[codegen::verbatim(ReloadInfo.description)]]
std::optional<bool> reload;
};
#include "browser_codegen.cpp"
} // namespace
namespace openspace {
void Browser::RenderHandler::draw() {}
void Browser::RenderHandler::draw() {}
void Browser::RenderHandler::render() {}
void Browser::RenderHandler::render() {}
void Browser::RenderHandler::setTexture(GLuint t) {
_texture = t;
void Browser::RenderHandler::setTexture(GLuint t) {
_texture = t;
}
Browser::Browser(const ghoul::Dictionary& dictionary)
: _url(UrlInfo)
, _browserPixeldimensions(DimensionsInfo, glm::vec2(500.f), glm::vec2(10.f), glm::vec2(3000.f))
, _reload(ReloadInfo)
{
if (dictionary.hasValue<std::string>(UrlInfo.identifier)) {
_url = dictionary.value<std::string>(UrlInfo.identifier);
}
// Handle target dimension property
const Parameters p = codegen::bake<Parameters>(dictionary);
_url = p.url.value_or(_url);
_browserPixeldimensions = p.dimensions.value_or(_browserPixeldimensions);
glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize();
_browserPixeldimensions = windowDimensions;
Browser::Browser(const ghoul::Dictionary& dictionary)
: _url(UrlInfo)
, _browserPixeldimensions(DimensionsInfo, glm::vec2(500.f), glm::vec2(10.f), glm::vec2(3000.f))
, _reload(ReloadInfo)
{
if (dictionary.hasValue<std::string>(UrlInfo.identifier)) {
_url = dictionary.value<std::string>(UrlInfo.identifier);
}
_url.onChange([this]() { _isUrlDirty = true; });
_browserPixeldimensions.onChange([this]() { _isDimensionsDirty = true; });
_reload.onChange([this]() { _shouldReload = true; });
glm::vec2 windowDimensions = global::windowDelegate->currentSubwindowSize();
_browserPixeldimensions = windowDimensions;
// Create browser and render handler
_renderHandler = new RenderHandler();
_keyboardHandler = new WebKeyboardHandler();
_browserInstance = std::make_unique<BrowserInstance>(
_renderHandler,
_keyboardHandler
);
_url.onChange([this]() { _isUrlDirty = true; });
_browserPixeldimensions.onChange([this]() { _isDimensionsDirty = true; });
_reload.onChange([this]() { _shouldReload = true; });
WebBrowserModule* webBrowser = global::moduleEngine->module<WebBrowserModule>();
if (webBrowser) {
webBrowser->addBrowser(_browserInstance.get());
}
}
// Create browser and render handler
_renderHandler = new RenderHandler();
_keyboardHandler = new WebKeyboardHandler();
_browserInstance = std::make_unique<BrowserInstance>(
_renderHandler,
_keyboardHandler
);
Browser::~Browser() {}
WebBrowserModule* webBrowser = global::moduleEngine->module<WebBrowserModule>();
if (webBrowser) {
webBrowser->addBrowser(_browserInstance.get());
}
}
Browser::~Browser() {
}
bool Browser::initializeGL() {
_texture = std::make_unique<ghoul::opengl::Texture>(
glm::uvec3(glm::ivec2(_browserPixeldimensions.value()), 1),
GL_TEXTURE_2D
);
bool Browser::initializeGL() {
_texture = std::make_unique<ghoul::opengl::Texture>(
glm::uvec3(glm::ivec2(_browserPixeldimensions.value()), 1),
GL_TEXTURE_2D
);
_renderHandler->setTexture(*_texture);
_renderHandler->setTexture(*_texture);
_browserInstance->initialize();
_browserInstance->initialize();
_browserInstance->loadUrl(_url);
return isReady();
}
bool Browser::deinitializeGL() {
_renderHandler->setTexture(0);
_texture = nullptr;
LDEBUG(fmt::format("Deinitializing browser: {}", _url.value()));
_browserInstance->close(true);
WebBrowserModule* webBrowser = global::moduleEngine->module<WebBrowserModule>();
if (webBrowser) {
webBrowser->removeBrowser(_browserInstance.get());
_browserInstance.reset();
}
else {
LWARNING("Could not find WebBrowserModule");
}
return true;
}
void Browser::render() {
if (!_renderHandler->isTextureReady()) {
return;
}
_renderHandler->updateTexture();
}
void Browser::update() {
if (_isUrlDirty) {
_browserInstance->loadUrl(_url);
return isReady();
_isUrlDirty = false;
}
bool Browser::deinitializeGL() {
_renderHandler->setTexture(0);
_texture = nullptr;
std::string urlString;
_url.getStringValue(urlString);
LDEBUG(fmt::format("Deinitializing browser: {}", urlString));
_browserInstance->close(true);
WebBrowserModule* webBrowser = global::moduleEngine->module<WebBrowserModule>();
if (webBrowser) {
webBrowser->removeBrowser(_browserInstance.get());
_browserInstance.reset();
}
else {
LWARNING("Could not find WebBrowserModule");
}
return true;
}
void Browser::render() {
if (!_renderHandler->isTextureReady()) {
return;
}
_renderHandler->updateTexture();
}
void Browser::update() {
if (_isUrlDirty) {
_browserInstance->loadUrl(_url);
_isUrlDirty = false;
}
if (_isDimensionsDirty) {
if (_browserPixeldimensions.value().x > 0 &&
_browserPixeldimensions.value().y > 0) {
_browserInstance->reshape(_browserPixeldimensions.value());
_isDimensionsDirty = false;
}
}
if (_shouldReload) {
_browserInstance->reloadBrowser();
_shouldReload = false;
}
}
bool Browser::isReady() const {
return _texture.get();
}
glm::vec2 Browser::browserPixelDimensions() const {
return _browserPixeldimensions.value();
}
// Updates the browser size to match the size of the texture
void Browser::updateBrowserSize() {
_browserPixeldimensions = _texture->dimensions();
}
float Browser::browserRatio() const
{
return static_cast<float>(_texture->dimensions().x) /
static_cast<float>(_texture->dimensions().y);
}
void Browser::setCallbackDimensions(
const std::function<void(const glm::dvec2&)>& function)
{
_browserPixeldimensions.onChange([&]() {
function(_browserPixeldimensions.value());
});
}
void Browser::executeJavascript(const std::string& script) const {
// Make sure that the browser has a main frame
const bool browserExists = _browserInstance && _browserInstance->getBrowser();
const bool frameIsLoaded = browserExists &&
_browserInstance->getBrowser()->GetMainFrame();
if (frameIsLoaded) {
_browserInstance->getBrowser()->GetMainFrame()->ExecuteJavaScript(
script,
_browserInstance->getBrowser()->GetMainFrame()->GetURL(),
0
);
if (_isDimensionsDirty) {
if (_browserPixeldimensions.value().x > 0 &&
_browserPixeldimensions.value().y > 0)
{
_browserInstance->reshape(_browserPixeldimensions.value());
_isDimensionsDirty = false;
}
}
if (_shouldReload) {
_browserInstance->reloadBrowser();
_shouldReload = false;
}
}
bool Browser::isReady() const {
return _texture.get();
}
glm::vec2 Browser::browserPixelDimensions() const {
return _browserPixeldimensions.value();
}
// Updates the browser size to match the size of the texture
void Browser::updateBrowserSize() {
_browserPixeldimensions = _texture->dimensions();
}
float Browser::browserRatio() const {
return static_cast<float>(_texture->dimensions().x) /
static_cast<float>(_texture->dimensions().y);
}
void Browser::setCallbackDimensions(
const std::function<void(const glm::dvec2&)>& function)
{
_browserPixeldimensions.onChange([&]() {
function(_browserPixeldimensions.value());
});
}
void Browser::executeJavascript(const std::string& script) const {
// Make sure that the browser has a main frame
const bool browserExists = _browserInstance && _browserInstance->getBrowser();
const bool frameIsLoaded = browserExists &&
_browserInstance->getBrowser()->GetMainFrame();
if (frameIsLoaded) {
_browserInstance->getBrowser()->GetMainFrame()->ExecuteJavaScript(
script,
_browserInstance->getBrowser()->GetMainFrame()->GetURL(),
0
);
}
}
} // namespace openspace
+204 -203
View File
@@ -1,3 +1,26 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/skybrowser/include/screenspaceskybrowser.h>
#include <modules/skybrowser/skybrowsermodule.h>
@@ -7,14 +30,12 @@
#include <openspace/engine/moduleengine.h>
#include <openspace/rendering/renderengine.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/dictionaryjsonformatter.h> // formatJson
#include <ghoul/misc/dictionaryjsonformatter.h>
#include <ghoul/opengl/texture.h>
#include <optional>
#include <glm/gtx/color_space.hpp> // For hsv color
#include <random> // For random color
#include <glm/gtx/color_space.hpp>
#include <random>
#include <glm/gtx/string_cast.hpp>
#pragma optimize("", off)
namespace {
constexpr const char* _loggerCat = "ScreenSpaceSkyBrowser";
@@ -34,7 +55,6 @@ namespace {
};
struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters {
// [[codegen::verbatim(AnimationSpeedInfo.description)]]
std::optional<double> animationSpeed;
@@ -42,7 +62,7 @@ namespace {
std::optional<float> textureQuality;
};
#include "ScreenSpaceSkyBrowser_codegen.cpp"
#include "screenspaceskybrowser_codegen.cpp"
} // namespace
glm::ivec3 randomBorderColor(glm::ivec3 highlight) {
@@ -67,209 +87,190 @@ glm::ivec3 randomBorderColor(glm::ivec3 highlight) {
namespace openspace {
ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary)
: ScreenSpaceRenderable(dictionary)
, WwtCommunicator(dictionary)
, _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0)
, _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f)
{
// Set a unique identifier
std::string identifier;
if (dictionary.hasValue<std::string>(KeyIdentifier)) {
identifier = dictionary.value<std::string>(KeyIdentifier);
}
else {
identifier = "ScreenSpaceSkyBrowser";
}
identifier = makeUniqueIdentifier(identifier);
setIdentifier(identifier);
ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary)
: ScreenSpaceRenderable(dictionary)
, WwtCommunicator(dictionary)
, _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0)
, _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f)
{
_identifier = makeUniqueIdentifier(_identifier);
// Handle target dimension property
const Parameters p = codegen::bake<Parameters>(dictionary);
_textureQuality = p.textureQuality.value_or(_textureQuality);
_animationSpeed = p.animationSpeed.value_or(_animationSpeed);
// Handle target dimension property
const Parameters p = codegen::bake<Parameters>(dictionary);
_textureQuality = p.textureQuality.value_or(_textureQuality);
_animationSpeed = p.animationSpeed.value_or(_animationSpeed);
addProperty(_url);
addProperty(_browserPixeldimensions);
addProperty(_reload);
addProperty(_textureQuality);
addProperty(_url);
addProperty(_browserPixeldimensions);
addProperty(_reload);
addProperty(_textureQuality);
_textureQuality.onChange([this]() {
_textureDimensionsIsDirty = true;
});
_textureQuality.onChange([this]() {
_textureDimensionsIsDirty = true;
});
// Ensure that the browser is placed at the z-coordinate of the screen space plane
glm::vec2 screenPosition = _cartesianPosition.value();
_cartesianPosition.setValue(glm::vec3(screenPosition, skybrowser::ScreenSpaceZ));
// Ensure that the browser is placed at the z-coordinate of the screen space plane
glm::vec2 screenPosition = _cartesianPosition.value();
_cartesianPosition = glm::vec3(screenPosition, skybrowser::ScreenSpaceZ);
if (global::windowDelegate->isMaster()) {
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
_borderColor = randomBorderColor(module->highlight());
}
}
ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() {
if (global::windowDelegate->isMaster()) {
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
_borderColor = randomBorderColor(module->highlight());
}
}
if (module && module->getPair(identifier())) {
module->removeTargetBrowserPair(identifier());
}
}
ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() {
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
bool ScreenSpaceSkyBrowser::initializeGL() {
WwtCommunicator::initializeGL();
ScreenSpaceRenderable::initializeGL();
updateTextureResolution();
return true;
}
glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) {
// Fine tuning of target
glm::dvec2 wwtFov = fieldsOfView();
glm::dvec2 openSpaceFOV = skybrowser::fovWindow();
glm::dvec2 browserDim = screenSpaceDimensions();
glm::dvec2 angleResult = wwtFov * (drag / browserDim);
glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV;
// Convert to screen space coordinate system
glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f };
glm::dvec2 result = - convertToScreenSpace * resultRelativeOs;
return result;
}
void ScreenSpaceSkyBrowser::setIdInBrowser() {
WwtCommunicator::setIdInBrowser(identifier());
}
void ScreenSpaceSkyBrowser::updateTextureResolution()
{
// Scale texture depending on the height of the window
// Set texture size to the actual pixel size it covers
glm::vec2 pixels = glm::vec2(global::windowDelegate->currentSubwindowSize());
// If the scale is 1, it covers half the window. Hence multiplication with 2
float newResY = pixels.y * 2.f * _scale;
float ratio = _size.x / _size.y;
float newResX = newResY * ratio;
glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value();
_browserPixeldimensions = glm::ivec2(newSize);
_texture->setDimensions(glm::ivec3(newSize, 1));
_objectSize = glm::ivec3(_texture->dimensions());
}
bool ScreenSpaceSkyBrowser::deinitializeGL() {
ScreenSpaceRenderable::deinitializeGL();
WwtCommunicator::deinitializeGL();
return true;
}
bool ScreenSpaceSkyBrowser::isAnimated()
{
return _isFovAnimated;
}
void ScreenSpaceSkyBrowser::startFovAnimation(float fov)
{
_isFovAnimated = true;
_endVfov = fov;
}
void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime)
{
// If distance too large, keep animating. Else, stop animation
float diff = _endVfov - verticalFov();
bool shouldAnimate = abs(diff) > FovThreshold;
if (shouldAnimate) {
float delta = _animationSpeed * (diff * deltaTime);
_verticalFov = std::clamp(_verticalFov + delta, 0.0001f, 70.0f);
}
else {
_isFovAnimated = false;
}
}
void ScreenSpaceSkyBrowser::render() {
WwtCommunicator::render();
draw(
globalRotationMatrix() *
translationMatrix() *
localRotationMatrix() *
scaleMatrix()
);
}
void ScreenSpaceSkyBrowser::update() {
// Texture of window is 1x1 when minimized
bool isWindow = global::windowDelegate->currentSubwindowSize() != glm::ivec2(1);
bool isWindowResized = global::windowDelegate->windowHasResized();
if ((isWindowResized && isWindow) || _textureDimensionsIsDirty) {
updateTextureResolution();
_textureDimensionsIsDirty = false;
}
if (_sizeIsDirty) {
updateScreenSpaceSize();
_sizeIsDirty = false;
}
WwtCommunicator::update();
ScreenSpaceRenderable::update();
}
void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) {
// Make scroll more sensitive the smaller the FOV
float x = _verticalFov;
float zoomFactor = atan(x / 50.0) + exp(x / 40) - 0.999999;
float zoom = scroll > 0.0 ? -zoomFactor : zoomFactor;
_verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f);
}
void ScreenSpaceSkyBrowser::bindTexture()
{
_texture->bind();
}
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: e.g. a browser that covers 0.25 of the
// height of the window will have scale = 0.25
glm::mat4 scale = glm::scale(
glm::mat4(1.f),
glm::vec3(browserRatio() * _scale, _scale, 1.f)
);
return scale;
}
void ScreenSpaceSkyBrowser::setOpacity(float opacity)
{
_opacity = opacity;
}
void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize)
{
_size = newSize;
_sizeIsDirty = true;
}
void ScreenSpaceSkyBrowser::updateScreenSpaceSize()
{
_scale = abs(_size.y) * 0.5f;
updateTextureResolution();
}
float ScreenSpaceSkyBrowser::opacity() const {
return _opacity;
}
glm::vec2 ScreenSpaceSkyBrowser::size() const
{
return _size;
if (module && module->getPair(identifier())) {
module->removeTargetBrowserPair(identifier());
}
}
bool ScreenSpaceSkyBrowser::initializeGL() {
WwtCommunicator::initializeGL();
ScreenSpaceRenderable::initializeGL();
updateTextureResolution();
return true;
}
glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(glm::dvec2 drag) {
// Fine tuning of target
glm::dvec2 wwtFov = fieldsOfView();
glm::dvec2 openSpaceFOV = skybrowser::fovWindow();
glm::dvec2 browserDim = screenSpaceDimensions();
glm::dvec2 angleResult = wwtFov * (drag / browserDim);
glm::dvec2 resultRelativeOs = angleResult / openSpaceFOV;
// Convert to screen space coordinate system
glm::dvec2 convertToScreenSpace{ (2 * skybrowser::windowRatio()), 2.f };
glm::dvec2 result = - convertToScreenSpace * resultRelativeOs;
return result;
}
void ScreenSpaceSkyBrowser::setIdInBrowser() {
WwtCommunicator::setIdInBrowser(identifier());
}
void ScreenSpaceSkyBrowser::updateTextureResolution() {
// Scale texture depending on the height of the window
// Set texture size to the actual pixel size it covers
glm::vec2 pixels = glm::vec2(global::windowDelegate->currentSubwindowSize());
// If the scale is 1, it covers half the window. Hence multiplication with 2
float newResY = pixels.y * 2.f * _scale;
float ratio = _size.x / _size.y;
float newResX = newResY * ratio;
glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value();
_browserPixeldimensions = glm::ivec2(newSize);
_texture->setDimensions(glm::ivec3(newSize, 1));
_objectSize = glm::ivec3(_texture->dimensions());
}
bool ScreenSpaceSkyBrowser::deinitializeGL() {
ScreenSpaceRenderable::deinitializeGL();
WwtCommunicator::deinitializeGL();
return true;
}
bool ScreenSpaceSkyBrowser::isAnimated() const{
return _isFovAnimated;
}
void ScreenSpaceSkyBrowser::startFovAnimation(float fov) {
_isFovAnimated = true;
_endVfov = fov;
}
void ScreenSpaceSkyBrowser::incrementallyAnimateToFov(float deltaTime) {
// If distance too large, keep animating. Else, stop animation
float diff = _endVfov - verticalFov();
bool shouldAnimate = abs(diff) > FovThreshold;
if (shouldAnimate) {
float delta = _animationSpeed * (diff * deltaTime);
_verticalFov = std::clamp(_verticalFov + delta, 0.0001f, 70.0f);
}
else {
_isFovAnimated = false;
}
}
void ScreenSpaceSkyBrowser::render() {
WwtCommunicator::render();
draw(
globalRotationMatrix() *
translationMatrix() *
localRotationMatrix() *
scaleMatrix()
);
}
void ScreenSpaceSkyBrowser::update() {
// Texture of window is 1x1 when minimized
bool isWindow = global::windowDelegate->currentSubwindowSize() != glm::ivec2(1);
bool isWindowResized = global::windowDelegate->windowHasResized();
if ((isWindowResized && isWindow) || _textureDimensionsIsDirty) {
updateTextureResolution();
_textureDimensionsIsDirty = false;
}
if (_sizeIsDirty) {
updateScreenSpaceSize();
_sizeIsDirty = false;
}
WwtCommunicator::update();
ScreenSpaceRenderable::update();
}
void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) {
// Make scroll more sensitive the smaller the FOV
float x = _verticalFov;
float zoomFactor = atan(x / 50.f) + exp(x / 40.f) - 0.999999f;
float zoom = scroll > 0.f ? -zoomFactor : zoomFactor;
_verticalFov = std::clamp(_verticalFov + zoom, 0.001f, 70.0f);
}
void ScreenSpaceSkyBrowser::bindTexture() {
_texture->bind();
}
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: e.g. a browser that covers 0.25 of the
// height of the window will have scale = 0.25
glm::mat4 scale = glm::scale(
glm::mat4(1.f),
glm::vec3(browserRatio() * _scale, _scale, 1.f)
);
return scale;
}
void ScreenSpaceSkyBrowser::setOpacity(float opacity) {
_opacity = opacity;
}
void ScreenSpaceSkyBrowser::setScreenSpaceSize(const glm::vec2& newSize) {
_size = newSize;
_sizeIsDirty = true;
}
void ScreenSpaceSkyBrowser::updateScreenSpaceSize() {
_scale = abs(_size.y) * 0.5f;
updateTextureResolution();
}
float ScreenSpaceSkyBrowser::opacity() const {
return _opacity;
}
glm::vec2 ScreenSpaceSkyBrowser::size() const {
return _size;
}
} // namespace openspace
+47 -42
View File
@@ -1,3 +1,26 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/skybrowser/include/screenspaceskytarget.h>
#include <modules/skybrowser/skybrowsermodule.h>
@@ -61,7 +84,6 @@ namespace {
};
struct [[codegen::Dictionary(ScreenSpaceSkyTarget)]] Parameters {
// [[codegen::verbatim(CrosshairThresholdInfo.description)]]
std::optional<float> crosshairThreshold;
@@ -76,7 +98,6 @@ namespace {
// [[codegen::verbatim(LineWidthInfo.description)]]
std::optional<float> lineWidth;
};
#include "screenspaceskytarget_codegen.cpp"
@@ -118,10 +139,11 @@ namespace openspace {
setIdentifier(identifier);
// Set the position to screen space z
glm::dvec3 startPos{ _cartesianPosition.value().x, _cartesianPosition.value().y,
skybrowser::ScreenSpaceZ };
_cartesianPosition.setValue(startPos);
_cartesianPosition = glm::dvec3(
_cartesianPosition.value().x,
_cartesianPosition.value().y,
skybrowser::ScreenSpaceZ
);
}
@@ -134,16 +156,13 @@ namespace openspace {
}
// Pure virtual in the screen space renderable class and hence must be defined
void ScreenSpaceSkyTarget::bindTexture() {
}
void ScreenSpaceSkyTarget::bindTexture() {}
bool ScreenSpaceSkyTarget::isReady() const {
return _shader != nullptr;
}
bool ScreenSpaceSkyTarget::initializeGL() {
glGenVertexArrays(1, &_vertexArray);
glGenBuffers(1, &_vertexBuffer);
createShaders();
@@ -151,8 +170,7 @@ namespace openspace {
return isReady();
}
bool ScreenSpaceSkyTarget::deinitializeGL()
{
bool ScreenSpaceSkyTarget::deinitializeGL() {
return ScreenSpaceRenderable::deinitializeGL();
}
@@ -173,7 +191,6 @@ namespace openspace {
void ScreenSpaceSkyTarget::createShaders() {
_shader = global::renderEngine->buildRenderProgram(
"ScreenSpaceProgram",
absPath("${MODULE_SKYBROWSER}/shaders/target_vs.glsl"),
@@ -185,7 +202,7 @@ namespace openspace {
}
void ScreenSpaceSkyTarget::setColor(glm::ivec3 color) {
_borderColor = color;
_borderColor = std::move(color);
}
glm::ivec3 ScreenSpaceSkyTarget::borderColor() const {
@@ -193,7 +210,6 @@ namespace openspace {
}
void ScreenSpaceSkyTarget::render() {
bool showCrosshair = _verticalFov < _showCrosshairThreshold;
bool showRectangle = _verticalFov > _showRectangleThreshold;
@@ -224,8 +240,7 @@ namespace openspace {
_shader->deactivate();
}
void ScreenSpaceSkyTarget::update()
{
void ScreenSpaceSkyTarget::update() {
if (_isLocked) {
glm::dvec3 localCamera = skybrowser::equatorialToLocalCamera(
_lockedCoordinates
@@ -252,11 +267,9 @@ namespace openspace {
}
glm::dvec3 ScreenSpaceSkyTarget::directionGalactic() const {
glm::vec3 localCamera = _cartesianPosition.value();
if (_useRadiusAzimuthElevation) {
localCamera = raeToCartesian(_raePosition.value());
}
@@ -281,8 +294,7 @@ namespace openspace {
_scale = std::max(heightRatio, smallestHeightRatio);
}
void ScreenSpaceSkyTarget::setFovFromScale()
{
void ScreenSpaceSkyTarget::setFovFromScale() {
glm::dvec2 fovs = skybrowser::fovWindow();
_verticalFov = _scale * fovs.y;
}
@@ -291,14 +303,12 @@ namespace openspace {
return _isLocked;
}
bool ScreenSpaceSkyTarget::isAnimated()
{
bool ScreenSpaceSkyTarget::isAnimated() {
return _isAnimated;
}
void ScreenSpaceSkyTarget::startAnimation(glm::dvec3 equatorialCoordsEnd,
bool shouldLockAfter)
{
bool shouldLockAfter) {
_animationStart = glm::normalize(
skybrowser::sphericalToCartesian(equatorialAim())
);
@@ -308,8 +318,7 @@ namespace openspace {
_isLocked = false;
}
void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime)
{
void ScreenSpaceSkyTarget::incrementallyAnimateToCoordinate(float deltaTime) {
// At fps that are too low, the animation stops working. Just place target instead
bool fpsTooLow = deltaTime > DeltaTimeThreshold;
// Find smallest angle between the two vectors
@@ -362,52 +371,48 @@ namespace openspace {
}
glm::dvec2 ScreenSpaceSkyTarget::equatorialAim() const {
glm::dvec3 cartesian;
// Get the local camera coordinates of the target
if (_useRadiusAzimuthElevation) {
glm::vec3 cartesian = raeToCartesian(_raePosition.value());
cartesian = raeToCartesian(_raePosition.value());
glm::dvec3 equatorial = skybrowser::localCameraToEquatorial(cartesian);
return skybrowser::cartesianToSpherical(equatorial);
}
else {
glm::dvec3 cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value());
cartesian = skybrowser::localCameraToEquatorial(_cartesianPosition.value());
return skybrowser::cartesianToSpherical(cartesian);
}
}
void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition)
{
void ScreenSpaceSkyTarget::highlight(glm::ivec3 addition) {
_borderColor += addition;
}
void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal)
{
void ScreenSpaceSkyTarget::removeHighlight(glm::ivec3 removal) {
_borderColor -= removal;
}
float ScreenSpaceSkyTarget::opacity() const {
return _opacity.value();
return _opacity;
}
glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const
{
glm::dvec2 ScreenSpaceSkyTarget::lockedCoordinates() const {
return skybrowser::cartesianToSpherical(_lockedCoordinates);
}
void ScreenSpaceSkyTarget::setOpacity(float opacity) {
_opacity = opacity;
}
void ScreenSpaceSkyTarget::setLock(bool isLocked)
{
void ScreenSpaceSkyTarget::setLock(bool isLocked) {
_isLocked = isLocked;
if (_isLocked) {
_lockedCoordinates = skybrowser::sphericalToCartesian(equatorialAim());
}
}
void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim)
{
void ScreenSpaceSkyTarget::setEquatorialAim(const glm::dvec2& aim) {
_isAnimated = false;
_isLocked = false;
+52 -93
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -37,15 +37,15 @@
namespace openspace {
TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser, ScreenSpaceSkyTarget* target)
TargetBrowserPair::TargetBrowserPair(ScreenSpaceSkyBrowser* browser,
ScreenSpaceSkyTarget* target)
: _target(target), _browser(browser)
{
ghoul_assert(browser != nullptr, "Sky browser is null pointer!");
ghoul_assert(target != nullptr, "Sky target is null pointer!");
}
TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other)
{
TargetBrowserPair& TargetBrowserPair::operator=(TargetBrowserPair other) {
std::swap(_target, other._target);
std::swap(_browser, other._browser);
return *this;
@@ -64,34 +64,29 @@ namespace openspace {
_browser->setImageOrder(i, order);
}
void TargetBrowserPair::removeHighlight(glm::ivec3 color)
{
void TargetBrowserPair::removeHighlight(glm::ivec3 color) {
_target->removeHighlight(color);
_browser->removeHighlight(color);
}
void TargetBrowserPair::highlight(glm::ivec3 color)
{
void TargetBrowserPair::highlight(glm::ivec3 color) {
_browser->highlight(color);
_target->highlight(color);
}
bool TargetBrowserPair::isTargetFadeFinished(float goalState) const
{
bool TargetBrowserPair::isTargetFadeFinished(float goalState) const {
// Is fading finished?
float targetDiff = abs(_target->opacity() - goalState);
return targetDiff < FadeThreshold;
}
bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const
{
bool TargetBrowserPair::isBrowserFadeFinished(float goalState) const {
float browserDiff = abs(_browser->opacity() - goalState);
return browserDiff < FadeThreshold;
}
bool TargetBrowserPair::checkMouseIntersection(glm::vec2 mousePosition)
{
bool TargetBrowserPair::checkMouseIntersection(glm::vec2 mousePosition) {
bool onBrowser = _browser->intersection(mousePosition);
bool onTarget = _target->intersection(mousePosition);
if (onBrowser) {
@@ -109,50 +104,46 @@ namespace openspace {
return onBrowser || onTarget;
}
glm::vec2 TargetBrowserPair::selectedScreenSpacePosition()
{
glm::vec2 TargetBrowserPair::selectedScreenSpacePosition() {
return _selected->screenSpacePosition();
}
bool TargetBrowserPair::isBrowserSelected()
{
bool TargetBrowserPair::isBrowserSelected() {
return _isSelectedBrowser;
}
bool TargetBrowserPair::isTargetSelected()
{
bool TargetBrowserPair::isTargetSelected() {
return _selected && !_isSelectedBrowser;
}
void TargetBrowserPair::fineTuneTarget(const glm::vec2& start,
const glm::vec2& translation)
{
glm::vec2 fineTune = -_browser->fineTuneVector(translation);
glm::vec2 fineTune = _browser->fineTuneVector(translation);
openspace::global::scriptEngine->queueScript(
"openspace.skybrowser.translateScreenSpaceRenderable(\"" + targetId() + "\","
+ std::to_string(start.x) + "," + std::to_string(start.y) + ","
+ std::to_string(translation.x) + "," + std::to_string(translation.y) + ")",
+ std::to_string(fineTune.x) + "," + std::to_string(fineTune.y) + ")",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
void TargetBrowserPair::translateSelected(const glm::vec2& start,
const glm::vec2& translation)
const glm::vec2& trans)
{
if (this && _selected) {
std::string id = _selected->identifier();
openspace::global::scriptEngine->queueScript(
"openspace.skybrowser.translateScreenSpaceRenderable(\"" + id + "\","
+ std::to_string(start.x) + "," + std::to_string(start.y) + ","
+ std::to_string(translation.x) + "," + std::to_string(translation.y) + ")",
+ std::to_string(trans.x) + "," + std::to_string(trans.y) + ")",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
}
void TargetBrowserPair::synchronizeAim()
{
void TargetBrowserPair::synchronizeAim() {
if (!_target->isAnimated()) {
glm::dvec2 aim;
// To remove the lag effect when moving the camera while having a locked
@@ -169,82 +160,67 @@ namespace openspace {
}
}
void TargetBrowserPair::setEnabled(bool enable)
{
void TargetBrowserPair::setEnabled(bool enable) {
_browser->setEnabled(enable);
_target->setEnabled(enable);
}
bool TargetBrowserPair::isEnabled() const
{
bool TargetBrowserPair::isEnabled() const {
return _target->isEnabled() && _browser->isEnabled();
}
bool TargetBrowserPair::isLocked() const
{
bool TargetBrowserPair::isLocked() const {
return _target->isLocked();
}
void TargetBrowserPair::initialize()
{
void TargetBrowserPair::initialize() {
_target->setColor(_browser->borderColor());
_target->setDimensions(_browser->browserPixelDimensions());
_target->setScaleFromVfov(_browser->verticalFov());
_browser->updateBorderColor();
}
glm::ivec3 TargetBrowserPair::borderColor() const
{
glm::ivec3 TargetBrowserPair::borderColor() const {
return _browser->borderColor();
}
glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const
{
glm::dvec2 TargetBrowserPair::targetDirectionEquatorial() const {
return _target->equatorialAim();
}
glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const
{
glm::dvec3 TargetBrowserPair::targetDirectionGalactic() const {
return _target->directionGalactic();
}
std::string TargetBrowserPair::browserGuiName() const
{
std::string TargetBrowserPair::browserGuiName() const {
return _browser->guiName();
}
std::string TargetBrowserPair::browserId() const
{
std::string TargetBrowserPair::browserId() const {
return _browser->identifier();
}
std::string TargetBrowserPair::targetId() const
{
std::string TargetBrowserPair::targetId() const {
return _target->identifier();
}
std::string TargetBrowserPair::selectedId()
{
std::string TargetBrowserPair::selectedId() {
return _selected->identifier();
}
glm::vec2 TargetBrowserPair::size() const
{
glm::vec2 TargetBrowserPair::size() const {
return _browser->size();
}
float TargetBrowserPair::verticalFov() const
{
float TargetBrowserPair::verticalFov() const {
return _browser->verticalFov();
}
const std::deque<int>& TargetBrowserPair::getSelectedImages() const
{
const std::deque<int>& TargetBrowserPair::getSelectedImages() const {
return _browser->getSelectedImages();
}
void TargetBrowserPair::selectImage(const ImageData& image, int i)
{
void TargetBrowserPair::selectImage(const ImageData& image, int i) {
// Load image into browser
_browser->displayImage(image.imageUrl, i);
@@ -257,28 +233,23 @@ namespace openspace {
}
}
void TargetBrowserPair::removeSelectedImage(int i)
{
void TargetBrowserPair::removeSelectedImage(int i) {
_browser->removeSelectedImage(i);
}
void TargetBrowserPair::loadImageCollection(const std::string& collection)
{
void TargetBrowserPair::loadImageCollection(const std::string& collection) {
_browser->loadImageCollection(collection);
}
void TargetBrowserPair::setImageOpacity(int i, float opacity)
{
void TargetBrowserPair::setImageOpacity(int i, float opacity) {
_browser->setImageOpacity(i, opacity);
}
void TargetBrowserPair::hideChromeInterface(bool shouldHide)
{
void TargetBrowserPair::hideChromeInterface(bool shouldHide) {
_browser->hideChromeInterface(shouldHide);
}
void TargetBrowserPair::sendIdToBrowser()
{
void TargetBrowserPair::sendIdToBrowser() {
_browser->setIdInBrowser();
}
@@ -286,46 +257,39 @@ namespace openspace {
_browser->updateBrowserSize();
}
void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced)
{
void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) {
_browser->setIsSyncedWithWwt(isSynced);
}
void TargetBrowserPair::setVerticalFov(float vfov)
{
void TargetBrowserPair::setVerticalFov(float vfov) {
_verticalFov = vfov;
_browser->setVerticalFov(vfov);
_target->setScaleFromVfov(vfov);
}
void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim)
{
void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) {
_equatorialAim = aim;
_target->setEquatorialAim(aim);
_browser->setEquatorialAim(aim);
}
void TargetBrowserPair::setBorderColor(const glm::ivec3& color)
{
void TargetBrowserPair::setBorderColor(const glm::ivec3& color) {
_borderColor = color;
_target->setColor(color);
_browser->setBorderColor(color);
}
void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions)
{
void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) {
_dimensions = dimensions;
_target->setDimensions(dimensions);
_browser->setScreenSpaceSize(dimensions);
}
void TargetBrowserPair::setVerticalFovWithScroll(float scroll)
{
void TargetBrowserPair::setVerticalFovWithScroll(float scroll) {
_browser->setVerticalFovWithScroll(scroll);
}
void TargetBrowserPair::setSelectedWithId(const std::string& id)
{
void TargetBrowserPair::setSelectedWithId(const std::string& id) {
if (browserId() == id) {
_isSelectedBrowser = true;
_selected = _browser;
@@ -340,8 +304,7 @@ namespace openspace {
}
}
void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime)
{
void TargetBrowserPair::incrementallyAnimateToCoordinate(double deltaTime) {
// Animate the target before the field of view starts to animate
if (_target->isAnimated()) {
_target->incrementallyAnimateToCoordinate(static_cast<float>(deltaTime));
@@ -358,8 +321,7 @@ namespace openspace {
_browser->startFovAnimation(fovEnd);
}
void TargetBrowserPair::centerTargetOnScreen()
{
void TargetBrowserPair::centerTargetOnScreen() {
// Animate the target to the center of the screen
unlock();
// Get camera direction in celestial spherical coordinates
@@ -369,18 +331,15 @@ namespace openspace {
startAnimation(viewDirection, currentFov, false);
}
bool TargetBrowserPair::hasFinishedFading(float goalState) const
{
bool TargetBrowserPair::hasFinishedFading(float goalState) const {
return isTargetFadeFinished(goalState) && isBrowserFadeFinished(goalState);
}
bool TargetBrowserPair::isFacingCamera() const
{
bool TargetBrowserPair::isFacingCamera() const {
return _browser->isFacingCamera() || _target->isFacingCamera();
}
bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const
{
bool TargetBrowserPair::isUsingRadiusAzimuthElevation() const {
return _browser->isUsingRaeCoords() || _target->isUsingRaeCoords();
}
@@ -392,7 +351,8 @@ namespace openspace {
return _browser;
}
void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime, float deltaTime)
void TargetBrowserPair::incrementallyFade(float goalState, float fadeTime,
float deltaTime)
{
float opacityDelta = static_cast<float>(deltaTime / fadeTime);
if (_target->opacity() > goalState) {
@@ -417,9 +377,8 @@ namespace openspace {
bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) {
return lhs._target == rhs._target && lhs._browser == rhs._browser;
}
bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) {
return !(lhs == rhs);
}
} // namespace openspace
+195 -177
View File
@@ -1,3 +1,26 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/skybrowser/include/utility.h>
#include <openspace/engine/globals.h>
@@ -5,191 +28,186 @@
#include <openspace/navigation/navigationhandler.h>
#include <openspace/camera/camera.h>
#include <glm/gtx/vector_angle.hpp>
#include <cmath> // For atan2
#define _USE_MATH_DEFINES
#include <math.h> // For M_PI
#include <cmath>
namespace openspace::skybrowser {
// Converts from spherical coordinates in the unit of degrees to cartesian coordianates
glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) {
// Converts from spherical coordinates in the unit of degrees to cartesian coordianates
glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) {
glm::dvec2 coordsRadians = glm::radians(coords);
glm::dvec2 coordsRadians = glm::radians(coords);
glm::dvec3 cartesian = glm::dvec3(
cos(coordsRadians.x) * cos(coordsRadians.y),
sin(coordsRadians.x) * cos(coordsRadians.y),
sin(coordsRadians.y)
);
return cartesian;
}
// Converts from cartesian coordianates to spherical in the unit of degrees
glm::dvec2 cartesianToSpherical(const 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);
glm::dvec2 celestialCoords{ ra, dec };
return glm::degrees(celestialCoords);
}
glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) {
return glm::transpose(conversionMatrix) * glm::normalize(coords);
}
glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) {
// On the unit sphere
glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords);
return rGalactic * CelestialSphereRadius;
}
glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) {
// Ensure that if the coord is behind the camera,
// the converted coordinate will be there too
double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ;
// Calculate screen space coords x and y
double tan_x = coords.x / coords.z;
double tan_y = coords.y / coords.z;
glm::dvec3 screenSpace = glm::dvec3(zCoord * tan_x, zCoord * tan_y, zCoord);
return screenSpace;
}
glm::dvec3 localCameraToGalactic(const 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 localCameraToEquatorial(const 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::localCameraToGalactic(coords);
return skybrowser::galacticToEquatorial(galactic);
}
glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords)
{
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 galactic = equatorialToGalactic(coords);
glm::dvec3 localCamera = galacticToLocalCamera(galactic);
return localCamera;
}
glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) {
// Transform vector to camera's local coordinate system
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix();
glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos);
glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0);
return glm::normalize(viewDirectionLocal);
}
double cameraRoll() {
openspace::Camera* camera = global::navigationHandler->camera();
glm::dvec3 upWorld = camera->lookUpVectorWorldSpace();
glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace();
glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld);
glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld);
glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole);
double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000);
double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000);
return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
}
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();
glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace();
glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view);
return galCoord;
}
float windowRatio() {
glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
return windowRatio.x / windowRatio.y;
}
bool isCoordinateInView(const glm::dvec3& equatorial) {
// Check if image coordinate is within current FOV
glm::dvec3 localCamera = equatorialToLocalCamera(equatorial);
glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera);
double r = static_cast<float>(windowRatio());
bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f &&
coordsScreen.z < 0;
// If the coordinate is not in view, rotate camera
return isCoordInView;
}
// Transforms a pixel coordinate to a screen space coordinate
glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) {
glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize());
// Change origin to middle of the window
glm::vec2 screenSpacePos = 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;
}
// The horizontal and vertical fov of the OpenSpace window
glm::dvec2 fovWindow() {
// OpenSpace FOV
glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize());
double windowRatio = windowDim.y / windowDim.x;
double hFov = global::windowDelegate->getHorizFieldOfView();
glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio);
return OpenSpaceFOV;
}
double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) {
// Find smallest angle between the two vectors
double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end));
return std::acos(cos);
}
glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start,
const glm::dvec3& end, double deltaTime,
double speedFactor) {
double smallestAngle = angleBetweenVectors(start, end);
// Calculate rotation this frame
double rotationAngle = smallestAngle * deltaTime * speedFactor;
// Create the rotation matrix for local camera space
glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end));
return glm::rotate(rotationAngle, rotationAxis);
}
glm::dvec3 cartesian = glm::dvec3(
cos(coordsRadians.x) * cos(coordsRadians.y),
sin(coordsRadians.x) * cos(coordsRadians.y),
sin(coordsRadians.y)
);
return cartesian;
}
// Converts from cartesian coordianates to spherical in the unit of degrees
glm::dvec2 cartesianToSpherical(const 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.0 * glm::pi<double>());
glm::dvec2 celestialCoords{ ra, dec };
return glm::degrees(celestialCoords);
}
glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) {
return glm::transpose(conversionMatrix) * glm::normalize(coords);
}
glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) {
// On the unit sphere
glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords);
return rGalactic * CelestialSphereRadius;
}
glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) {
// Ensure that if the coord is behind the camera,
// the converted coordinate will be there too
double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ;
// Calculate screen space coords x and y
double tanX = coords.x / coords.z;
double tanY = coords.y / coords.z;
glm::dvec3 screenSpace = glm::dvec3(zCoord * tanX, zCoord * tanY, zCoord);
return screenSpace;
}
glm::dvec3 localCameraToGalactic(const 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 localCameraToEquatorial(const 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::localCameraToGalactic(coords);
return skybrowser::galacticToEquatorial(galactic);
}
glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords)
{
// Transform equatorial J2000 to galactic coord with infinite radius
glm::dvec3 galactic = equatorialToGalactic(coords);
glm::dvec3 localCamera = galacticToLocalCamera(galactic);
return localCamera;
}
glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) {
// Transform vector to camera's local coordinate system
glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
glm::dmat4 camMat = global::navigationHandler->camera()->viewRotationMatrix();
glm::dvec3 viewDirectionWorld = glm::normalize(coords - camPos);
glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(viewDirectionWorld, 1.0);
return glm::normalize(viewDirectionLocal);
}
double cameraRoll() {
openspace::Camera* camera = global::navigationHandler->camera();
glm::dvec3 upWorld = camera->lookUpVectorWorldSpace();
glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace();
glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld);
glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld);
glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole);
double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000);
double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000);
return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
}
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();
glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace();
glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view);
return galCoord;
}
float windowRatio() {
glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
return windowRatio.x / windowRatio.y;
}
bool isCoordinateInView(const glm::dvec3& equatorial) {
// Check if image coordinate is within current FOV
glm::dvec3 localCamera = equatorialToLocalCamera(equatorial);
glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera);
double r = static_cast<float>(windowRatio());
bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f &&
coordsScreen.z < 0;
// If the coordinate is not in view, rotate camera
return isCoordInView;
}
// Transforms a pixel coordinate to a screen space coordinate
glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) {
glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize());
// Change origin to middle of the window
glm::vec2 screenSpacePos = 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;
}
// The horizontal and vertical fov of the OpenSpace window
glm::dvec2 fovWindow() {
// OpenSpace FOV
glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize());
double windowRatio = windowDim.y / windowDim.x;
double hFov = global::windowDelegate->getHorizFieldOfView();
glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio);
return OpenSpaceFOV;
}
double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) {
// Find smallest angle between the two vectors
double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end));
return std::acos(cos);
}
glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start,
const glm::dvec3& end, double deltaTime,
double speedFactor) {
double smallestAngle = angleBetweenVectors(start, end);
// Calculate rotation this frame
double rotationAngle = smallestAngle * deltaTime * speedFactor;
// Create the rotation matrix for local camera space
glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end));
return glm::rotate(rotationAngle, rotationAxis);
}
} // namespace openspace
+248 -284
View File
@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
@@ -27,327 +27,291 @@
#include <modules/webbrowser/webbrowsermodule.h>
#include <modules/webbrowser/include/webkeyboardhandler.h>
#include <modules/webbrowser/include/browserinstance.h>
#include <ghoul/misc/dictionaryjsonformatter.h> // formatJson
#include <ghoul/misc/dictionaryjsonformatter.h>
#include <modules/skybrowser/include/utility.h>
#include <glm/gtx/vector_angle.hpp>
#include <cmath> // For atan2
#define _USE_MATH_DEFINES
#include <math.h> // For M_PI
namespace {
constexpr const char* _loggerCat = "WwtCommunicator";
} // namespace
namespace openspace {
WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary)
: Browser(dictionary) {}
WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary)
: Browser(dictionary) {}
WwtCommunicator::~WwtCommunicator() {
WwtCommunicator::~WwtCommunicator() {}
void WwtCommunicator::displayImage(const std::string& url, int i) {
// Ensure there are no duplicates
auto it = std::find(_selectedImages.begin(), _selectedImages.end(), i);
if (it == _selectedImages.end()) {
// 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(addImageMessage(std::to_string(i), url));
sendMessageToWwt(setImageOpacityMessage(std::to_string(i), 1.0));
}
}
void WwtCommunicator::removeSelectedImage(int i) {
// Remove from selected list
auto it = std::find(_selectedImages.begin(), _selectedImages.end(), i);
if (it != std::end(_selectedImages)) {
_selectedImages.erase(it);
sendMessageToWwt(removeImageMessage(std::to_string(i)));
}
}
void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) {
std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");";
executeJavascript(script);
}
const std::deque<int>& WwtCommunicator::getSelectedImages() const {
return _selectedImages;
}
void WwtCommunicator::setVerticalFov(float vfov) {
_verticalFov = vfov;
_equatorialAimIsDirty = true;
}
void WwtCommunicator::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);
}
void WwtCommunicator::setIsSyncedWithWwt(bool isSynced) {
_isSyncedWithWwt = isSynced;
}
void WwtCommunicator::setEquatorialAim(glm::dvec2 equatorial) {
_equatorialAim = std::move(equatorial);
_equatorialAimIsDirty = true;
}
void WwtCommunicator::setBorderColor(glm::ivec3 color) {
_borderColor = std::move(color);
_borderColorIsDirty = true;
}
void WwtCommunicator::highlight(glm::ivec3 addition) {
setWebpageBorderColor(_borderColor + addition);
}
void WwtCommunicator::removeHighlight(glm::ivec3 removal) {
setWebpageBorderColor(_borderColor - removal);
}
void WwtCommunicator::updateBorderColor() {
setWebpageBorderColor(_borderColor);
}
void WwtCommunicator::updateAim() {
double roll = _isSyncedWithWwt ? skybrowser::cameraRoll() : 0.0;
// Message WorldWide Telescope current view
ghoul::Dictionary message = moveCameraMessage(
_equatorialAim,
_verticalFov,
roll
);
sendMessageToWwt(message);
}
glm::dvec2 WwtCommunicator::fieldsOfView() const {
glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio(), verticalFov());
return browserFov;
}
bool WwtCommunicator::hasLoadedImages() const {
return _hasLoadedImages;
}
glm::dvec2 WwtCommunicator::equatorialAim() const {
return _equatorialAim;
}
void WwtCommunicator::setImageOrder(int i, int order) {
// Find in selected images list
auto current = std::find(
_selectedImages.begin(),
_selectedImages.end(),
i
);
auto target = std::begin(_selectedImages) + order;
// Make sure the image was found in the list
if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) {
// Swap the two images
std::iter_swap(current, target);
}
void WwtCommunicator::displayImage(const std::string& url, int i)
{
// Ensure 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);
// Index of image is used as layer ID as it is unique in the image data set
sendMessageToWwt(addImage(std::to_string(i), url));
sendMessageToWwt(setImageOpacity(std::to_string(i), 1.0));
int reverseOrder = _selectedImages.size() - order - 1;
ghoul::Dictionary message = setLayerOrderMessage(std::to_string(i), reverseOrder);
sendMessageToWwt(message);
}
void WwtCommunicator::loadImageCollection(const std::string& collection) {
sendMessageToWwt(loadCollectionMessage(collection));
_hasLoadedImages = true;
}
void WwtCommunicator::setImageOpacity(int i, float opacity) {
ghoul::Dictionary msg = setImageOpacityMessage(std::to_string(i), opacity);
sendMessageToWwt(msg);
}
void WwtCommunicator::hideChromeInterface(bool shouldHide) {
ghoul::Dictionary msg = hideChromeGuiMessage(shouldHide);
sendMessageToWwt(msg);
}
void WwtCommunicator::update() {
Browser::update();
// Cap how messages are passed
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime;
if (timeSinceLastUpdate > TimeUpdateInterval) {
if (_equatorialAimIsDirty) {
updateAim();
_equatorialAimIsDirty = false;
}
}
void WwtCommunicator::removeSelectedImage(int i) {
// Remove from selected list
auto it = std::find(std::begin(_selectedImages), std::end(_selectedImages), i);
if (it != std::end(_selectedImages)) {
_selectedImages.erase(it);
sendMessageToWwt(removeImage(std::to_string(i)));
if (_borderColorIsDirty) {
updateBorderColor();
_borderColorIsDirty = false;
}
_lastUpdateTime = std::chrono::system_clock::now();
}
}
void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) {
std::string script = "sendMessageToWWT(" + ghoul::formatJson(msg) + ");";
executeJavascript(script);
}
void WwtCommunicator::render() {
Browser::render();
}
const std::deque<int>& WwtCommunicator::getSelectedImages() {
return _selectedImages;
}
void WwtCommunicator::initializeGL() {
Browser::initializeGL();
}
void WwtCommunicator::setVerticalFov(float vfov) {
_verticalFov = vfov;
_equatorialAimIsDirty = true;
}
void WwtCommunicator::deinitializeGL() {
Browser::deinitializeGL();
}
void WwtCommunicator::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);
}
void WwtCommunicator::setHasLoadedImages(bool isLoaded) {
_hasLoadedImages = isLoaded;
}
void WwtCommunicator::setIsSyncedWithWwt(bool isSynced)
{
_isSyncedWithWwt = isSynced;
}
void WwtCommunicator::setIdInBrowser(const std::string& id) {
// Send ID to it's browser
executeJavascript("setId('" + id + "')");
}
void WwtCommunicator::setEquatorialAim(const glm::dvec2& equatorial)
{
_equatorialAim = equatorial;
_equatorialAimIsDirty = true;
}
glm::ivec3 WwtCommunicator::borderColor() const {
return _borderColor;
}
void WwtCommunicator::setBorderColor(const glm::ivec3& color)
{
_borderColor = color;
_borderColorIsDirty = true;
}
float WwtCommunicator::verticalFov() const {
return _verticalFov;
}
void WwtCommunicator::highlight(glm::ivec3 addition)
{
setWebpageBorderColor(_borderColor + addition);
}
// WWT messages
ghoul::Dictionary WwtCommunicator::moveCameraMessage(const glm::dvec2& celestCoords,
double fov, double roll,
bool shouldMoveInstantly) {
using namespace std::string_literals;
ghoul::Dictionary msg;
void WwtCommunicator::removeHighlight(glm::ivec3 removal)
{
setWebpageBorderColor(_borderColor - removal);
}
// Create message
msg.setValue("event", "center_on_coordinates"s);
msg.setValue("ra", celestCoords.x);
msg.setValue("dec", celestCoords.y);
msg.setValue("fov", fov);
msg.setValue("roll", roll);
msg.setValue("instant", shouldMoveInstantly);
void WwtCommunicator::updateBorderColor()
{
setWebpageBorderColor(_borderColor);
}
return msg;
}
void WwtCommunicator::updateAim()
{
double roll = _isSyncedWithWwt ? skybrowser::cameraRoll() : 0.0;
// Message WorldWide Telescope current view
ghoul::Dictionary message = moveCamera(
_equatorialAim,
_verticalFov,
roll
);
sendMessageToWwt(message);
}
ghoul::Dictionary WwtCommunicator::loadCollectionMessage(const std::string& url) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "load_image_collection"s);
msg.setValue("url", url);
msg.setValue("loadChildFolders", true);
glm::dvec2 WwtCommunicator::fieldsOfView() {
glm::dvec2 browserFov = glm::dvec2(verticalFov() * browserRatio(), verticalFov());
return msg;
}
return browserFov;
}
ghoul::Dictionary WwtCommunicator::setForegroundMessage(const std::string& name) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_by_name"s);
msg.setValue("name", name);
bool WwtCommunicator::hasLoadedImages() const {
return _hasLoadedImages;
}
return msg;
}
glm::dvec2 WwtCommunicator::equatorialAim() const
{
return _equatorialAim;
}
ghoul::Dictionary WwtCommunicator::addImageMessage(const std::string& id,
const std::string& url) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_create"s);
msg.setValue("id", id);
msg.setValue("url", url);
msg.setValue("mode", "preloaded"s);
msg.setValue("goto", false);
void WwtCommunicator::setImageOrder(int i, int order) {
// Find in selected images list
auto current = std::find(
std::begin(_selectedImages),
std::end(_selectedImages),
i
);
auto target = std::begin(_selectedImages) + order;
return msg;
}
// Make sure the image was found in the list
if (current != std::end(_selectedImages) && target != std::end(_selectedImages)) {
// Swap the two images
std::iter_swap(current, target);
}
ghoul::Dictionary WwtCommunicator::removeImageMessage(const std::string& imageId) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_remove"s);
msg.setValue("id", imageId);
int reverseOrder = _selectedImages.size() - order - 1;
ghoul::Dictionary message = setLayerOrder(std::to_string(i),
reverseOrder);
sendMessageToWwt(message);
}
return msg;
}
void WwtCommunicator::loadImageCollection(const std::string& collection) {
sendMessageToWwt(loadCollection(collection));
_hasLoadedImages = true;
}
ghoul::Dictionary WwtCommunicator::setImageOpacityMessage(const std::string& imageId,
double opacity) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_set"s);
msg.setValue("id", imageId);
msg.setValue("setting", "opacity"s);
msg.setValue("value", opacity);
void WwtCommunicator::setImageOpacity(int i, float opacity) {
ghoul::Dictionary msg = setImageOpacity(std::to_string(i), opacity);
sendMessageToWwt(msg);
}
return msg;
}
void WwtCommunicator::hideChromeInterface(bool shouldHide)
{
ghoul::Dictionary msg = hideChromeGui(shouldHide);
sendMessageToWwt(msg);
}
ghoul::Dictionary WwtCommunicator::setLayerOrderMessage(const std::string& id, int order) {
// The lower the layer order, the more towards the back the image is placed
// 0 is the background
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_order"s);
msg.setValue("id", id);
msg.setValue("order", order);
msg.setValue("version", messageCounter);
void WwtCommunicator::update()
{
Browser::update();
// Cap how messages are passed
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime;
messageCounter++;
if (timeSinceLastUpdate > _timeUpdateInterval) {
return msg;
}
if (_equatorialAimIsDirty) {
updateAim();
_equatorialAimIsDirty = false;
}
if (_borderColorIsDirty) {
updateBorderColor();
_borderColorIsDirty = false;
}
_lastUpdateTime = std::chrono::system_clock::now();
}
}
void WwtCommunicator::render()
{
Browser::render();
}
void WwtCommunicator::initializeGL()
{
Browser::initializeGL();
}
void WwtCommunicator::deinitializeGL()
{
Browser::deinitializeGL();
}
void WwtCommunicator::setHasLoadedImages(bool isLoaded) {
_hasLoadedImages = isLoaded;
}
void WwtCommunicator::setIdInBrowser(const std::string& id) {
// Send ID to it's browser
executeJavascript("setId('" + id + "')");
}
glm::ivec3 WwtCommunicator::borderColor() const {
return _borderColor;
}
float WwtCommunicator::verticalFov() const {
return _verticalFov;
}
// WWT messages
ghoul::Dictionary WwtCommunicator::moveCamera(const glm::dvec2& celestCoords,
double fov, double roll,
bool shouldMoveInstantly) {
using namespace std::string_literals;
ghoul::Dictionary msg;
// Create message
msg.setValue("event", "center_on_coordinates"s);
msg.setValue("ra", celestCoords.x);
msg.setValue("dec", celestCoords.y);
msg.setValue("fov", fov);
msg.setValue("roll", roll);
msg.setValue("instant", shouldMoveInstantly);
return msg;
}
ghoul::Dictionary WwtCommunicator::loadCollection(const std::string& url) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "load_image_collection"s);
msg.setValue("url", url);
msg.setValue("loadChildFolders", true);
return msg;
}
ghoul::Dictionary WwtCommunicator::setForeground(const std::string& name) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_by_name"s);
msg.setValue("name", name);
return msg;
}
ghoul::Dictionary WwtCommunicator::addImage(const std::string& id,
const std::string& url) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_create"s);
msg.setValue("id", id);
msg.setValue("url", url);
msg.setValue("mode", "preloaded"s);
msg.setValue("goto", false);
return msg;
}
ghoul::Dictionary WwtCommunicator::removeImage(const std::string& imageId) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_remove"s);
msg.setValue("id", imageId);
return msg;
}
ghoul::Dictionary WwtCommunicator::setImageOpacity(const std::string& imageId,
double opacity) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_set"s);
msg.setValue("id", imageId);
msg.setValue("setting", "opacity"s);
msg.setValue("value", opacity);
return msg;
}
ghoul::Dictionary WwtCommunicator::setForegroundOpacity(double val) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "set_foreground_opacity"s);
msg.setValue("value", val);
return msg;
}
ghoul::Dictionary WwtCommunicator::setLayerOrder(const std::string& id, int order) {
// The lower the layer order, the more towards the back the image is placed
// 0 is the background
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "image_layer_order"s);
msg.setValue("id", id);
msg.setValue("order", order);
msg.setValue("version", messageCounter);
messageCounter++;
return msg;
}
ghoul::Dictionary WwtCommunicator::hideChromeGui(bool isHidden)
{
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "modify_settings"s);
msg.setValue("settings", "[[\"hideAllChrome\", true]]"s);
msg.setValue("target", "app"s);
return msg;
}
ghoul::Dictionary WwtCommunicator::hideChromeGuiMessage(bool isHidden) {
using namespace std::string_literals;
ghoul::Dictionary msg;
msg.setValue("event", "modify_settings"s);
msg.setValue("settings", "[[\"hideAllChrome\", true]]"s);
msg.setValue("target", "app"s);
return msg;
}
} // namespace openspace
+343 -334
View File
@@ -1,11 +1,34 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/skybrowser/include/wwtdatahandler.h>
#include <modules/skybrowser/include/utility.h>
#include <modules/space/speckloader.h>
#include <openspace/util/httprequest.h> // For downloading files from url
#include <openspace/util/httprequest.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <filesystem> // To iterate through files in directory
#include <filesystem>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
@@ -16,351 +39,337 @@ namespace {
namespace openspace {
bool hasAttribute(const tinyxml2::XMLElement* element, const std::string& name) {
return element->FindAttribute(name.c_str());
bool hasAttribute(const tinyxml2::XMLElement* element, const std::string_view& name) {
return element->FindAttribute(std::string(name).c_str());
}
std::string attribute(const tinyxml2::XMLElement* element, const std::string& name) {
if (hasAttribute(element, name)) {
return element->FindAttribute(name.c_str())->Value();
}
std::string attribute(const tinyxml2::XMLElement* element, const std::string& name) {
if (hasAttribute(element, name)) {
return element->FindAttribute(name.c_str())->Value();
}
else {
return wwt::Undefined;
}
else {
return wwt::Undefined;
}
}
// Parsing and downloading of wtml files
bool downloadFile(const std::string& url, const std::string& fileDestination) {
// Get the web page and save to file
HttpFileDownload wtml_root(
url, fileDestination, HttpFileDownload::Overwrite::Yes
);
wtml_root.start(std::chrono::milliseconds(5));
return wtml_root.hasSucceeded();
// Parsing and downloading of wtml files
bool downloadFile(const std::string& url, const std::filesystem::path& fileDestination) {
// Get the web page and save to file
HttpFileDownload wtmlRoot(
url,
fileDestination,
HttpFileDownload::Overwrite::Yes
);
wtmlRoot.start(std::chrono::milliseconds(10000));
return wtmlRoot.wait();
}
bool directoryExists(const std::filesystem::path& path) {
return std::filesystem::exists(path) && std::filesystem::is_directory(path);
}
std::string createSearchableString(std::string str) {
// Remove white spaces and all special characters
str.erase(std::remove_if(str.begin(), str.end(), [](char c) {
const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c);
return !isNumberOrLetter;
}),
std::end(str));
// Make the word lower case
std::transform(str.begin(), str.end(), str.begin(), [](char c) {
return std::tolower(c);
});
return str;
}
tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node,
const std::string& name)
{
while (node && node->Name() != name) {
node = node->FirstChildElement();
}
return node;
}
bool directoryExists(const std::string& path)
{
struct stat info;
int statRC = stat(path.c_str(), &info);
if (statRC != 0)
{
// 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;
}
const bool directoryExists = (info.st_mode & S_IFDIR);
return directoryExists;
}
std::string createSearchableString(std::string str) {
// Remove white spaces and all special characters
str.erase(std::remove_if(std::begin(str), std::end(str), [](char c) {
const bool isNumberOrLetter = std::isdigit(c) || std::isalpha(c);
return !isNumberOrLetter;
}),
std::end(str));
// Make the word lower case
std::transform(std::begin(str), std::end(str), std::begin(str), [](char c) {
return std::tolower(c);
});
return str;
}
tinyxml2::XMLElement* getDirectChildNode(tinyxml2::XMLElement* node,
const std::string& name) {
while (node && node->Name() != name) {
node = node->FirstChildElement();
}
return node;
}
tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node,
const std::string& name) {
tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node,
const std::string& name)
{
tinyxml2::XMLElement* child = node->FirstChildElement();
tinyxml2::XMLElement* imageSet = nullptr;
tinyxml2::XMLElement* child = node->FirstChildElement();
tinyxml2::XMLElement* imageSet = nullptr;
// Traverse the children and look at all their first child to find ImageSet
while (child) {
imageSet = getDirectChildNode(child, name);
// Found
if (imageSet) {
break;
}
child = child->NextSiblingElement();
}
return imageSet;
}
std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet,
const 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()
);
if (imageSetChild && imageSetChild->GetText()) {
return imageSetChild->GetText();
}
else {
return wwt::Undefined;
}
}
std::string getUrlFromPlace(tinyxml2::XMLElement* place) {
// If the place has a thumbnail url, return it
if (hasAttribute(place, wwt::Thumbnail)) {
return attribute(place, wwt::Thumbnail);
}
// If the place doesn't have a thumbnail url data attribute,
// Load the image set it stores instead
tinyxml2::XMLElement* imageSet = getChildNode(place, wwt::ImageSet);
// If there is an imageSet, collect thumbnail url
// Traverse the children and look at all their first child to find ImageSet
while (child) {
imageSet = getDirectChildNode(child, name);
// Found
if (imageSet) {
return getChildNodeContentFromImageSet(imageSet, wwt::ThumbnailUrl);
break;
}
else {
// If it doesn't contain an ImageSet, it doesn't have an url
return wwt::Undefined;
}
}
child = child->NextSiblingElement();
}
return imageSet;
}
std::string getChildNodeContentFromImageSet(tinyxml2::XMLElement* imageSet,
const 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()
);
if (imageSetChild && imageSetChild->GetText()) {
return imageSetChild->GetText();
}
else {
return wwt::Undefined;
}
}
std::string getUrlFromPlace(tinyxml2::XMLElement* place) {
// If the place has a thumbnail url, return it
if (hasAttribute(place, wwt::Thumbnail)) {
return attribute(place, wwt::Thumbnail);
}
// If the place doesn't have a thumbnail url data attribute,
// Load the image set it stores instead
tinyxml2::XMLElement* imageSet = getChildNode(place, wwt::ImageSet);
// If there is an imageSet, collect thumbnail url
if (imageSet) {
return getChildNodeContentFromImageSet(imageSet, wwt::ThumbnailUrl);
}
else {
// If it doesn't contain an ImageSet, it doesn't have an url
return wwt::Undefined;
}
}
void parseWtmlsFromDisc(std::vector<tinyxml2::XMLDocument*>& _xmls,
const std::string& directory) {
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
void parseWtmlsFromDisc(std::vector<tinyxml2::XMLDocument*>& _xmls,
const std::filesystem::path& directory)
{
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument();
std::string path = entry.path().u8string();
tinyxml2::XMLError successCode = document->LoadFile(path.c_str());
tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument();
std::string path = entry.path().u8string();
tinyxml2::XMLError successCode = document->LoadFile(path.c_str());
if (successCode == tinyxml2::XMLError::XML_SUCCESS) {
_xmls.push_back(document);
}
if (successCode == tinyxml2::XMLError::XML_SUCCESS) {
_xmls.push_back(document);
}
}
bool downloadAndParseWtmlFilesFromUrl(std::vector<tinyxml2::XMLDocument*>& _xmls,
const std::string& directory, const std::string& url,
const std::string& fileName)
{
// Look for WWT image data folder, create folder if it doesn't exist
if (!directoryExists(directory)) {
std::string newDir = directory;
// Remove the '/' at the end
newDir.pop_back();
LINFO("Creating directory WWTimagedata");
std::filesystem::create_directory(newDir);
}
// Download file from url
std::string file = directory.c_str() + fileName + ".aspx";
if (!downloadFile(url, file)) {
LINFO("Couldn't download file " + url);
return false;
}
// Parse file to XML
using namespace tinyxml2;
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
doc->LoadFile(file.c_str());
// Search XML file for folders with urls
XMLElement* root = doc->RootElement();
XMLElement* element = root->FirstChildElement(wwt::Folder.c_str());
const bool folderExists = element;
const bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url);
// If the file contains no folders, or there are folders but without urls,
// stop recursion
if (!folderExists || folderContainNoUrls) {
_xmls.push_back(doc);
LINFO("Saving " + url);
return true;
}
// Iterate through all the folders in the XML file
while (element && std::string(element->Value()) == wwt::Folder) {
// If folder contains urls, download and parse those urls
if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) {
std::string url = attribute(element, wwt::Url);
std::string fileName = attribute(element, wwt::Name);
downloadAndParseWtmlFilesFromUrl(_xmls, directory, url, fileName);
}
element = element->NextSiblingElement();
}
}
WwtDataHandler::~WwtDataHandler() {
// Call destructor of all allocated xmls
_xmls.clear();
}
void WwtDataHandler::loadImages(const std::string& root,
const std::string& directory) {
// Collect the wtml files, either by reading from disc or from a url
if (directoryExists(directory)) {
parseWtmlsFromDisc(_xmls, directory);
LINFO("Loading images from directory");
}
else {
downloadAndParseWtmlFilesFromUrl(_xmls, directory, root, "root");
LINFO("Loading images from url");
}
// Traverse through the collected wtml documents and collect the images
for (tinyxml2::XMLDocument* doc : _xmls) {
tinyxml2::XMLElement* root = doc->FirstChildElement();
std::string collectionName = attribute(root, wwt::Name);
saveImagesFromXml(root, collectionName);
}
// 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]);
}
if (std::islower(b.name[0])) {
b.name[0] = ::toupper(b.name[0]);
}
return a.name < b.name;
});
LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope "
"images.");
}
int WwtDataHandler::nLoadedImages() const
{
return _images.size();
}
const ImageData& WwtDataHandler::getImage(const int i) const
{
assert(i < _images.size(), "Index outside of image vector boundaries!");
return _images[i];
}
void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node,
std::string collection) {
// Collect the image set of the node. The structure is different depending on if
// it is a Place or an ImageSet
std::string thumbnailUrl = { wwt::Undefined };
tinyxml2::XMLElement* imageSet{ nullptr };
std::string type = std::string(node->Name());
if (type == wwt::ImageSet) {
thumbnailUrl = getChildNodeContentFromImageSet(node, wwt::ThumbnailUrl);
imageSet = node;
} // Place
else if (type == wwt::Place) {
thumbnailUrl = getUrlFromPlace(node);
imageSet = getChildNode(node, wwt::ImageSet);
}
// Only collect the images that have a thumbnail image, that are sky images and
// that have an image
const bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined;
const bool isSkyImage = attribute(node, wwt::DataSetType) == wwt::Sky;
const bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false;
if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) {
return;
}
// Collect name, image url and credits
std::string name = attribute(node, wwt::Name);
std::string imageUrl = attribute(imageSet, wwt::Url);
std::string credits = getChildNodeContentFromImageSet(imageSet, wwt::Credits);
std::string creditsUrl = getChildNodeContentFromImageSet(
imageSet, wwt::CreditsUrl
);
// Collect equatorial coordinates. All-sky surveys do not have this kind of
// coordinate
bool hasCelestialCoords = hasAttribute(node, wwt::RA) &&
hasAttribute(node, wwt::Dec);
glm::dvec2 equatorialSpherical{ 0.0 };
glm::dvec3 equatorialCartesian{ 0.0 };
if (hasCelestialCoords) {
// The RA from WWT is in the unit hours:
// to convert to degrees, multiply with 360 (deg) /24 (h) = 15
double ra = 15.0 * std::stod(attribute(node, wwt::RA));
double dec = std::stod(attribute(node, wwt::Dec));
equatorialSpherical = { ra, dec };
equatorialCartesian = skybrowser::sphericalToCartesian(
equatorialSpherical
);
}
// Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6
float fov{ 0.f };
if (hasAttribute(node, wwt::ZoomLevel)) {
fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0;
}
ImageData image = {
name,
thumbnailUrl,
imageUrl,
credits,
creditsUrl,
collection,
hasCelestialCoords,
fov,
equatorialSpherical,
equatorialCartesian,
};
_images.push_back(image);
}
void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root,
std::string collection) {
// Get direct child of node called Place
using namespace tinyxml2;
XMLElement* node = root->FirstChildElement();
// Iterate through all siblings of node. If sibling is folder, open recursively.
// If sibling is image, save it.
while (node) {
const std::string name = node->Name();
// If node is an image or place, load it
if (name == wwt::ImageSet || name == wwt::Place) {
saveImageFromNode(node, collection);
}
// If node is another folder, open recursively
else if (name == wwt::Folder) {
std::string newCollectionName = collection + "/";
newCollectionName += attribute(node, wwt::Name);
saveImagesFromXml(node, newCollectionName);
}
node = node->NextSiblingElement();
}
}
}
bool downloadAndParseWtmlFilesFromUrl(std::vector<tinyxml2::XMLDocument*>& _xmls,
const std::filesystem::path& directory, const std::string& url,
const std::string& fileName)
{
// Look for WWT image data folder, create folder if it doesn't exist
if (!directoryExists(directory)) {
std::string newDir = directory.string();
// Remove the '/' at the end
newDir.pop_back();
LINFO("Creating directory WWTimagedata");
std::filesystem::create_directory(newDir);
}
// Download file from url
std::filesystem::path file = directory.string() + fileName + ".aspx";
if (!downloadFile(url, file)) {
LINFO("Couldn't download file " + url + " to directory " + directory.string());
return false;
}
// Parse file to XML
using namespace tinyxml2;
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
doc->LoadFile(file.string().c_str());
// Search XML file for folders with urls
XMLElement* root = doc->RootElement();
XMLElement* element = root->FirstChildElement(wwt::Folder.c_str());
const bool folderExists = element;
const bool folderContainNoUrls = folderExists && !hasAttribute(element, wwt::Url);
// If the file contains no folders, or there are folders but without urls,
// stop recursion
if (!folderExists || folderContainNoUrls) {
_xmls.push_back(doc);
LINFO("Saving " + url);
return true;
}
// Iterate through all the folders in the XML file
while (element && std::string(element->Value()) == wwt::Folder) {
// If folder contains urls, download and parse those urls
if (hasAttribute(element, wwt::Url) && hasAttribute(element, wwt::Name)) {
std::string url = attribute(element, wwt::Url);
std::string fileName = attribute(element, wwt::Name);
downloadAndParseWtmlFilesFromUrl(_xmls, directory, url, fileName);
}
element = element->NextSiblingElement();
}
return true;
}
WwtDataHandler::~WwtDataHandler() {
// Call destructor of all allocated xmls
_xmls.clear();
}
void WwtDataHandler::loadImages(const std::string& root,
const std::filesystem::path& directory) {
// Collect the wtml files, either by reading from disc or from a url
if (directoryExists(directory)) {
parseWtmlsFromDisc(_xmls, directory);
LINFO("Loading images from directory");
}
else {
downloadAndParseWtmlFilesFromUrl(_xmls, directory, root, "root");
LINFO("Loading images from url");
}
// Traverse through the collected wtml documents and collect the images
for (tinyxml2::XMLDocument* doc : _xmls) {
tinyxml2::XMLElement* root = doc->FirstChildElement();
std::string collectionName = attribute(root, wwt::Name);
saveImagesFromXml(root, collectionName);
}
// 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]);
}
if (std::islower(b.name[0])) {
b.name[0] = ::toupper(b.name[0]);
}
return a.name < b.name;
});
LINFO("Loaded " + std::to_string(_images.size()) + " WorldWide Telescope "
"images.");
}
int WwtDataHandler::nLoadedImages() const
{
return _images.size();
}
const ImageData& WwtDataHandler::getImage(const int i) const
{
ghoul_assert(i < _images.size(), "Index outside of image vector boundaries!");
return _images[i];
}
void WwtDataHandler::saveImageFromNode(tinyxml2::XMLElement* node,
std::string collection) {
// Collect the image set of the node. The structure is different depending on if
// it is a Place or an ImageSet
std::string thumbnailUrl = { wwt::Undefined };
tinyxml2::XMLElement* imageSet{ nullptr };
std::string type = std::string(node->Name());
if (type == wwt::ImageSet) {
thumbnailUrl = getChildNodeContentFromImageSet(node, wwt::ThumbnailUrl);
imageSet = node;
} // Place
else if (type == wwt::Place) {
thumbnailUrl = getUrlFromPlace(node);
imageSet = getChildNode(node, wwt::ImageSet);
}
// Only collect the images that have a thumbnail image, that are sky images and
// that have an image
const bool hasThumbnailUrl = thumbnailUrl != wwt::Undefined;
const bool isSkyImage = attribute(node, wwt::DataSetType) == wwt::Sky;
const bool hasImageUrl = imageSet ? hasAttribute(imageSet, wwt::Url) : false;
if (!(hasThumbnailUrl && isSkyImage && hasImageUrl)) {
return;
}
// Collect name, image url and credits
std::string name = attribute(node, wwt::Name);
std::string imageUrl = attribute(imageSet, wwt::Url);
std::string credits = getChildNodeContentFromImageSet(imageSet, wwt::Credits);
std::string creditsUrl = getChildNodeContentFromImageSet(
imageSet, wwt::CreditsUrl
);
// Collect equatorial coordinates. All-sky surveys do not have this kind of
// coordinate
bool hasCelestialCoords = hasAttribute(node, wwt::RA) &&
hasAttribute(node, wwt::Dec);
glm::dvec2 equatorialSpherical{ 0.0 };
glm::dvec3 equatorialCartesian{ 0.0 };
if (hasCelestialCoords) {
// The RA from WWT is in the unit hours:
// to convert to degrees, multiply with 360 (deg) /24 (h) = 15
double ra = 15.0 * std::stod(attribute(node, wwt::RA));
double dec = std::stod(attribute(node, wwt::Dec));
equatorialSpherical = { ra, dec };
equatorialCartesian = skybrowser::sphericalToCartesian(
equatorialSpherical
);
}
// Collect field of view. The WWT definition of ZoomLevel is: VFOV = ZoomLevel / 6
float fov{ 0.f };
if (hasAttribute(node, wwt::ZoomLevel)) {
fov = std::stof(attribute(node, wwt::ZoomLevel)) / 6.0f;
}
ImageData image = {
name,
thumbnailUrl,
imageUrl,
credits,
creditsUrl,
collection,
hasCelestialCoords,
fov,
equatorialSpherical,
equatorialCartesian,
};
_images.push_back(image);
}
void WwtDataHandler::saveImagesFromXml(tinyxml2::XMLElement* root,
std::string collection)
{
// Get direct child of node called Place
using namespace tinyxml2;
XMLElement* node = root->FirstChildElement();
// Iterate through all siblings of node. If sibling is folder, open recursively.
// If sibling is image, save it.
while (node) {
const std::string name = node->Name();
// If node is an image or place, load it
if (name == wwt::ImageSet || name == wwt::Place) {
saveImageFromNode(node, collection);
}
// If node is another folder, open recursively
else if (name == wwt::Folder) {
std::string newCollectionName = collection + "/";
newCollectionName += attribute(node, wwt::Name);
saveImagesFromXml(node, newCollectionName);
}
node = node->NextSiblingElement();
}
}
} // namespace openspace