mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-23 12:39:24 -05:00
Merge remote-tracking branch 'origin/master' into issue/2313
# Conflicts: # modules/skybrowser/skybrowsermodule_lua.inl
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -55,6 +55,9 @@ namespace {
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(Browser)]] Parameters {
|
||||
// [[codegen::verbatim(DimensionsInfo.description)]]
|
||||
std::optional<glm::ivec2> dimensions;
|
||||
|
||||
// [[codegen::verbatim(UrlInfo.description)]]
|
||||
std::optional<std::string> url;
|
||||
|
||||
@@ -78,7 +81,7 @@ void Browser::RenderHandler::setTexture(GLuint t) {
|
||||
Browser::Browser(const ghoul::Dictionary& dictionary)
|
||||
: _browserDimensions(
|
||||
DimensionsInfo,
|
||||
global::windowDelegate->currentSubwindowSize(),
|
||||
glm::vec2(1000.f),
|
||||
glm::vec2(10.f),
|
||||
glm::vec2(3000.f)
|
||||
)
|
||||
@@ -89,8 +92,10 @@ Browser::Browser(const ghoul::Dictionary& dictionary)
|
||||
|
||||
_url = p.url.value_or(_url);
|
||||
_url.onChange([this]() { _isUrlDirty = true; });
|
||||
|
||||
|
||||
_browserDimensions = p.dimensions.value_or(_browserDimensions);
|
||||
_browserDimensions.onChange([this]() { _isDimensionsDirty = true; });
|
||||
|
||||
_reload.onChange([this]() { _shouldReload = true; });
|
||||
|
||||
// Create browser and render handler
|
||||
@@ -119,6 +124,9 @@ void Browser::initializeGL() {
|
||||
|
||||
_browserInstance->initialize();
|
||||
_browserInstance->loadUrl(_url);
|
||||
// Update the dimensions upon initialization. Do this with flag as it affects
|
||||
// derived classes as well
|
||||
_isDimensionsDirty = true;
|
||||
}
|
||||
|
||||
void Browser::deinitializeGL() {
|
||||
@@ -153,11 +161,7 @@ void Browser::update() {
|
||||
}
|
||||
|
||||
if (_isDimensionsDirty) {
|
||||
glm::vec2 dim = _browserDimensions;
|
||||
if (dim.x > 0 && dim.y > 0) {
|
||||
_browserInstance->reshape(dim);
|
||||
_isDimensionsDirty = false;
|
||||
}
|
||||
updateBrowserDimensions();
|
||||
}
|
||||
|
||||
if (_shouldReload) {
|
||||
@@ -170,10 +174,6 @@ bool Browser::isReady() const {
|
||||
return _texture.get();
|
||||
}
|
||||
|
||||
glm::vec2 Browser::browserPixelDimensions() const {
|
||||
return _browserDimensions;
|
||||
}
|
||||
|
||||
// Updates the browser size to match the size of the texture
|
||||
void Browser::updateBrowserSize() {
|
||||
_browserDimensions = _texture->dimensions();
|
||||
@@ -183,15 +183,26 @@ void Browser::reload() {
|
||||
_reload.set(true);
|
||||
}
|
||||
|
||||
void Browser::setRatio(float ratio) {
|
||||
float relativeRatio = ratio / browserRatio();
|
||||
float newX = static_cast<float>(_browserDimensions.value().x) * relativeRatio;
|
||||
glm::ivec2 newDims = { static_cast<int>(floor(newX)), _browserDimensions.value().y };
|
||||
_browserDimensions = newDims;
|
||||
_isDimensionsDirty = true;
|
||||
}
|
||||
|
||||
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&)>& func) {
|
||||
_browserDimensions.onChange([&]() {
|
||||
func(_browserDimensions.value());
|
||||
});
|
||||
void Browser::updateBrowserDimensions() {
|
||||
glm::ivec2 dim = _browserDimensions;
|
||||
if (dim.x > 0 && dim.y > 0) {
|
||||
_texture->setDimensions(glm::uvec3(_browserDimensions.value(), 1));
|
||||
_browserInstance->reshape(dim);
|
||||
_isDimensionsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Browser::executeJavascript(const std::string& script) const {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -58,7 +58,7 @@ namespace {
|
||||
constexpr openspace::properties::Property::PropertyInfo RectangleThresholdInfo = {
|
||||
"RectangleThreshold",
|
||||
"Rectangle Threshold",
|
||||
"When the field of view is larger than the rectangle threshold, a rectangle will"
|
||||
"When the field of view is larger than the rectangle threshold, a rectangle will "
|
||||
"be rendered in the target"
|
||||
};
|
||||
|
||||
@@ -188,7 +188,7 @@ void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) {
|
||||
ZoneScoped
|
||||
const bool showRectangle = _verticalFov > _showRectangleThreshold;
|
||||
|
||||
glm::vec4 color = { glm::vec3(_borderColor) / 255.f, 1.0 };
|
||||
glm::vec4 color = glm::vec4(glm::vec3(_borderColor) / 255.f, 1.0);
|
||||
|
||||
_shader->activate();
|
||||
_shader->setUniform("opacity", opacity());
|
||||
@@ -208,8 +208,8 @@ void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) {
|
||||
|
||||
glm::dvec3 normal = glm::normalize(data.camera.positionVec3() - _worldPosition);
|
||||
// There are two modes - 1) target rolls to have its up vector parallel to the
|
||||
// cameras up vector or 2) it is decoupled from the camera, in which case it needs to
|
||||
// be initialized once
|
||||
// cameras up vector or 2) it is decoupled from the camera, in which case it needs to
|
||||
// be initialized once
|
||||
if (!_isInitialized || _applyRoll) {
|
||||
applyRoll();
|
||||
_isInitialized = true;
|
||||
@@ -221,7 +221,7 @@ void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) {
|
||||
glm::cross(_upVector, normal)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
glm::dmat4 cameraOrientedRotation = glm::dmat4(1.0);
|
||||
cameraOrientedRotation[0] = glm::dvec4(_rightVector, 0.0);
|
||||
cameraOrientedRotation[1] = glm::dvec4(_upVector, 0.0);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -51,9 +51,10 @@ namespace {
|
||||
constexpr openspace::properties::Property::PropertyInfo DisplayCopyInfo = {
|
||||
"DisplayCopy",
|
||||
"Display Copy Position",
|
||||
"Display a copy of this sky browser at an additional position. This copy will not "
|
||||
"be interactive. The position is in RAE (Radius, Azimuth, Elevation) coordinates "
|
||||
"or Cartesian, depending on if the browser uses RAE or Cartesian coordinates"
|
||||
"Display a copy of this sky browser at an additional position. This copy will "
|
||||
"not be interactive. The position is in RAE (Radius, Azimuth, Elevation) "
|
||||
"coordinates or Cartesian, depending on if the browser uses RAE or Cartesian "
|
||||
"coordinates"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DisplayCopyShowInfo = {
|
||||
@@ -104,7 +105,7 @@ documentation::Documentation ScreenSpaceSkyBrowser::Documentation() {
|
||||
ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary)
|
||||
: ScreenSpaceRenderable(dictionary)
|
||||
, WwtCommunicator(dictionary)
|
||||
, _textureQuality(TextureQualityInfo, 0.5f, 0.25f, 1.f)
|
||||
, _textureQuality(TextureQualityInfo, 1.f, 0.25f, 1.f)
|
||||
, _isHidden(IsHiddenInfo, true)
|
||||
{
|
||||
_identifier = makeUniqueIdentifier(_identifier);
|
||||
@@ -121,17 +122,12 @@ ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary
|
||||
addProperty(_textureQuality);
|
||||
addProperty(_verticalFov);
|
||||
|
||||
_textureQuality.onChange([this]() { _textureDimensionsIsDirty = true; });
|
||||
_textureQuality.onChange([this]() { _isDimensionsDirty = true; });
|
||||
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
_borderColor = randomBorderColor();
|
||||
}
|
||||
|
||||
_scale.onChange([this]() {
|
||||
updateTextureResolution();
|
||||
_borderRadiusTimer = 0;
|
||||
});
|
||||
|
||||
_useRadiusAzimuthElevation.onChange(
|
||||
[this]() {
|
||||
std::for_each(
|
||||
@@ -159,7 +155,6 @@ ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() {
|
||||
bool ScreenSpaceSkyBrowser::initializeGL() {
|
||||
WwtCommunicator::initializeGL();
|
||||
ScreenSpaceRenderable::initializeGL();
|
||||
updateTextureResolution();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -192,19 +187,18 @@ void ScreenSpaceSkyBrowser::setIsInitialized(bool isInitialized) {
|
||||
}
|
||||
|
||||
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());
|
||||
// Check if texture quality has changed. If it has, adjust accordingly
|
||||
if (std::abs(_textureQuality.value() - _lastTextureQuality) > glm::epsilon<float>()) {
|
||||
float diffTextureQuality = _textureQuality / _lastTextureQuality;
|
||||
glm::vec2 newRes = glm::vec2(_browserDimensions.value()) * diffTextureQuality;
|
||||
_browserDimensions = glm::ivec2(newRes);
|
||||
_lastTextureQuality = _textureQuality.value();
|
||||
}
|
||||
_objectSize = glm::ivec3(_browserDimensions.value(), 1);
|
||||
|
||||
// If the scale is 1, it covers half the window. Hence multiplication with 2
|
||||
float newResY = pixels.y * 2.f * _scale;
|
||||
float newResX = newResY * _ratio;
|
||||
glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value();
|
||||
|
||||
_browserDimensions = glm::ivec2(newSize);
|
||||
_texture->setDimensions(glm::ivec3(newSize, 1));
|
||||
_objectSize = glm::ivec3(_texture->dimensions());
|
||||
// The radius has to be updated when the texture resolution has changed
|
||||
_radiusIsDirty = true;
|
||||
_borderRadiusTimer = 0;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::addDisplayCopy(const glm::vec3& raePosition, int nCopies) {
|
||||
@@ -313,16 +307,9 @@ void ScreenSpaceSkyBrowser::render() {
|
||||
}
|
||||
|
||||
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) {
|
||||
// Check for dirty flags
|
||||
if (_isDimensionsDirty) {
|
||||
updateTextureResolution();
|
||||
_textureDimensionsIsDirty = false;
|
||||
}
|
||||
if (_ratioIsDirty) {
|
||||
updateTextureResolution();
|
||||
_ratioIsDirty = false;
|
||||
}
|
||||
if (_shouldReload) {
|
||||
_isInitialized = false;
|
||||
@@ -369,11 +356,6 @@ void ScreenSpaceSkyBrowser::setOpacity(float opacity) {
|
||||
_opacity = opacity;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::setRatio(float ratio) {
|
||||
_ratio = ratio;
|
||||
_ratioIsDirty = true;
|
||||
}
|
||||
|
||||
float ScreenSpaceSkyBrowser::opacity() const {
|
||||
return _opacity;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -69,8 +69,8 @@ TargetBrowserPair::TargetBrowserPair(SceneGraphNode* targetNode,
|
||||
_targetRenderable = dynamic_cast<RenderableSkyTarget*>(_targetNode->renderable());
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setImageOrder(int i, int order) {
|
||||
_browser->setImageOrder(i, order);
|
||||
void TargetBrowserPair::setImageOrder(const std::string& imageUrl, int order) {
|
||||
_browser->setImageOrder(imageUrl, order);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::startFinetuningTarget() {
|
||||
@@ -87,10 +87,7 @@ void TargetBrowserPair::fineTuneTarget(const glm::vec2& translation) {
|
||||
glm::dvec3 up = _targetRenderable->upVector() * percentage.y;
|
||||
|
||||
glm::dvec3 newPosition = _startTargetPosition - (right - up);
|
||||
aimTargetGalactic(
|
||||
_targetNode->identifier(),
|
||||
newPosition
|
||||
);
|
||||
aimTargetGalactic(_targetNode->identifier(), newPosition);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::synchronizeAim() {
|
||||
@@ -154,13 +151,23 @@ double TargetBrowserPair::verticalFov() const {
|
||||
return _browser->verticalFov();
|
||||
}
|
||||
|
||||
std::vector<int> TargetBrowserPair::selectedImages() const {
|
||||
std::vector<std::string> TargetBrowserPair::selectedImages() const {
|
||||
return _browser->selectedImages();
|
||||
}
|
||||
|
||||
ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const {
|
||||
glm::dvec2 spherical = targetDirectionEquatorial();
|
||||
glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical);
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
std::vector<std::string> selectedImagesIndices;
|
||||
|
||||
for (const std::string& imageUrl : selectedImages()) {
|
||||
bool imageExists = module->wwtDataHandler().image(imageUrl).has_value();
|
||||
ghoul_assert(imageExists, "Image doesn't exist in the wwt catalog!");
|
||||
selectedImagesIndices.push_back(
|
||||
module->wwtDataHandler().image(imageUrl)->identifier
|
||||
);
|
||||
}
|
||||
|
||||
ghoul::Dictionary res;
|
||||
res.setValue("id", browserId());
|
||||
@@ -175,7 +182,7 @@ ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const {
|
||||
res.setValue("ratio", static_cast<double>(_browser->browserRatio()));
|
||||
res.setValue("isFacingCamera", isFacingCamera());
|
||||
res.setValue("isUsingRae", isUsingRadiusAzimuthElevation());
|
||||
res.setValue("selectedImages", selectedImages());
|
||||
res.setValue("selectedImages", selectedImagesIndices);
|
||||
res.setValue("scale", static_cast<double>(_browser->scale()));
|
||||
res.setValue("opacities", _browser->opacities());
|
||||
res.setValue("borderRadius", _browser->borderRadius());
|
||||
@@ -196,9 +203,9 @@ ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
void TargetBrowserPair::selectImage(const ImageData& image, int i) {
|
||||
void TargetBrowserPair::selectImage(const ImageData& image) {
|
||||
// Load image into browser
|
||||
_browser->selectImage(image.imageUrl, i);
|
||||
_browser->selectImage(image.imageUrl);
|
||||
|
||||
// If the image has coordinates, move the target
|
||||
if (image.hasCelestialCoords) {
|
||||
@@ -208,20 +215,20 @@ void TargetBrowserPair::selectImage(const ImageData& image, int i) {
|
||||
}
|
||||
}
|
||||
|
||||
void TargetBrowserPair::addImageLayerToWwt(const std::string& url, int i) {
|
||||
_browser->addImageLayerToWwt(url, i);
|
||||
void TargetBrowserPair::addImageLayerToWwt(const std::string& imageUrl) {
|
||||
_browser->addImageLayerToWwt(imageUrl);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::removeSelectedImage(int i) {
|
||||
_browser->removeSelectedImage(i);
|
||||
void TargetBrowserPair::removeSelectedImage(const std::string& imageUrl) {
|
||||
_browser->removeSelectedImage(imageUrl);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::loadImageCollection(const std::string& collection) {
|
||||
_browser->loadImageCollection(collection);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setImageOpacity(int i, float opacity) {
|
||||
_browser->setImageOpacity(i, opacity);
|
||||
void TargetBrowserPair::setImageOpacity(const std::string& imageUrl, float opacity) {
|
||||
_browser->setImageOpacity(imageUrl, opacity);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::hideChromeInterface() {
|
||||
@@ -286,11 +293,18 @@ void TargetBrowserPair::incrementallyAnimateToCoordinate() {
|
||||
aimTargetGalactic(_targetNode->identifier(), _targetAnimation.newValue());
|
||||
_fovAnimation.start();
|
||||
_targetIsAnimating = false;
|
||||
_fovIsAnimating = true;
|
||||
}
|
||||
// After the target has animated to its position, animate the field of view
|
||||
if (_fovAnimation.isAnimating()) {
|
||||
_browser->setVerticalFov(_fovAnimation.newValue());
|
||||
_targetRenderable->setVerticalFov(_browser->verticalFov());
|
||||
}
|
||||
else if (!_fovAnimation.isAnimating() && _fovIsAnimating) {
|
||||
// Set the finished field of view
|
||||
setVerticalFov(_fovAnimation.newValue());
|
||||
_fovIsAnimating = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TargetBrowserPair::startFading(float goal, float fadeTime) {
|
||||
@@ -315,7 +329,7 @@ void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd)
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
double fovSpeed = module->browserAnimationSpeed();
|
||||
// The speed is given degrees /sec
|
||||
double fovTime = abs(_browser->verticalFov() - fovEnd) / fovSpeed;
|
||||
double fovTime = std::abs(_browser->verticalFov() - fovEnd) / fovSpeed;
|
||||
// Fov animation
|
||||
_fovAnimation = skybrowser::Animation(_browser->verticalFov(), fovEnd, fovTime);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -132,7 +132,7 @@ glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) {
|
||||
|
||||
double targetRoll(const glm::dvec3& up, const glm::dvec3& forward) {
|
||||
constexpr glm::dvec3 NorthPole = glm::dvec3(0.0, 0.0, 1.0);
|
||||
|
||||
|
||||
glm::dvec3 upJ2000 = galacticToEquatorial(up);
|
||||
glm::dvec3 forwardJ2000 = galacticToEquatorial(forward);
|
||||
|
||||
@@ -170,7 +170,9 @@ bool isCoordinateInView(const glm::dvec3& equatorial) {
|
||||
double r = windowRatio();
|
||||
|
||||
bool isCoordInView =
|
||||
abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f && coordsScreen.z < 0.f;
|
||||
std::abs(coordsScreen.x) < r &&
|
||||
std::abs(coordsScreen.y) < 1.f &&
|
||||
coordsScreen.z < 0.f;
|
||||
return isCoordInView;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <modules/webbrowser/include/webkeyboardhandler.h>
|
||||
#include <modules/webbrowser/webbrowsermodule.h>
|
||||
#include <ghoul/misc/dictionaryjsonformatter.h>
|
||||
#include <deque>
|
||||
|
||||
namespace {
|
||||
constexpr std::string_view _loggerCat = "WwtCommunicator";
|
||||
@@ -68,12 +69,12 @@ namespace {
|
||||
return msg;
|
||||
}
|
||||
|
||||
ghoul::Dictionary addImageMessage(const std::string& id, const std::string& url) {
|
||||
ghoul::Dictionary addImageMessage(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("id", url);
|
||||
msg.setValue("url", url);
|
||||
msg.setValue("mode", "preloaded"s);
|
||||
msg.setValue("goto", false);
|
||||
@@ -100,7 +101,7 @@ namespace {
|
||||
return msg;
|
||||
}
|
||||
|
||||
ghoul::Dictionary setLayerOrderMessage(const std::string& id, int order) {
|
||||
ghoul::Dictionary setLayerOrderMessage(const std::string& imageUrl, int order) {
|
||||
static int MessageCounter = 0;
|
||||
|
||||
// The lower the layer order, the more towards the back the image is placed
|
||||
@@ -109,7 +110,7 @@ namespace {
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "image_layer_order"s);
|
||||
msg.setValue("id", id);
|
||||
msg.setValue("id", imageUrl);
|
||||
msg.setValue("order", order);
|
||||
msg.setValue("version", MessageCounter);
|
||||
|
||||
@@ -164,33 +165,33 @@ void WwtCommunicator::update() {
|
||||
Browser::update();
|
||||
}
|
||||
|
||||
void WwtCommunicator::selectImage(const std::string& url, int i) {
|
||||
void WwtCommunicator::selectImage(const std::string& url) {
|
||||
// Ensure there are no duplicates
|
||||
auto it = findSelectedImage(i);
|
||||
auto it = findSelectedImage(url);
|
||||
|
||||
if (it == _selectedImages.end()) {
|
||||
// Push newly selected image to front
|
||||
_selectedImages.push_front(std::pair<int, double>(i, 1.0));
|
||||
_selectedImages.push_front(std::pair<std::string, double>(url, 1.0));
|
||||
|
||||
// If wwt has not loaded the collection yet, wait with passing the message
|
||||
if (_isImageCollectionLoaded) {
|
||||
addImageLayerToWwt(url, i);
|
||||
addImageLayerToWwt(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WwtCommunicator::addImageLayerToWwt(const std::string& url, int i) {
|
||||
void WwtCommunicator::addImageLayerToWwt(const std::string& imageUrl) {
|
||||
// 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));
|
||||
sendMessageToWwt(addImageMessage(imageUrl));
|
||||
sendMessageToWwt(setImageOpacityMessage(imageUrl, 1.0));
|
||||
}
|
||||
|
||||
void WwtCommunicator::removeSelectedImage(int i) {
|
||||
void WwtCommunicator::removeSelectedImage(const std::string& imageUrl) {
|
||||
// Remove from selected list
|
||||
auto it = findSelectedImage(i);
|
||||
auto it = findSelectedImage(imageUrl);
|
||||
if (it != _selectedImages.end()) {
|
||||
_selectedImages.erase(it);
|
||||
sendMessageToWwt(removeImageMessage(std::to_string(i)));
|
||||
sendMessageToWwt(removeImageMessage(imageUrl));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,14 +200,14 @@ void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) const {
|
||||
executeJavascript(fmt::format("sendMessageToWWT({});", m));
|
||||
}
|
||||
|
||||
std::vector<int> WwtCommunicator::selectedImages() const {
|
||||
std::vector<int> selectedImagesVector;
|
||||
std::vector<std::string> WwtCommunicator::selectedImages() const {
|
||||
std::vector<std::string> selectedImagesVector;
|
||||
selectedImagesVector.resize(_selectedImages.size());
|
||||
std::transform(
|
||||
_selectedImages.cbegin(),
|
||||
_selectedImages.cend(),
|
||||
selectedImagesVector.begin(),
|
||||
[](const std::pair<int, double>& image) { return image.first; }
|
||||
[](const std::pair<std::string, double>& image) { return image.first; }
|
||||
);
|
||||
return selectedImagesVector;
|
||||
}
|
||||
@@ -218,7 +219,7 @@ std::vector<double> WwtCommunicator::opacities() const {
|
||||
_selectedImages.cbegin(),
|
||||
_selectedImages.cend(),
|
||||
opacities.begin(),
|
||||
[](const std::pair<int, double>& image) { return image.second; }
|
||||
[](const std::pair<std::string, double>& image) { return image.second; }
|
||||
);
|
||||
return opacities;
|
||||
}
|
||||
@@ -276,11 +277,15 @@ bool WwtCommunicator::isImageCollectionLoaded() const {
|
||||
return _isImageCollectionLoaded;
|
||||
}
|
||||
|
||||
std::deque<std::pair<int, double>>::iterator WwtCommunicator::findSelectedImage(int i) {
|
||||
SelectedImageDeque::iterator WwtCommunicator::findSelectedImage(
|
||||
const std::string& imageUrl)
|
||||
{
|
||||
auto it = std::find_if(
|
||||
_selectedImages.begin(),
|
||||
_selectedImages.end(),
|
||||
[i](const std::pair<int, double>& pair) { return pair.first == i; }
|
||||
[imageUrl](const std::pair<std::string, double>& pair) {
|
||||
return pair.first == imageUrl;
|
||||
}
|
||||
);
|
||||
return it;
|
||||
}
|
||||
@@ -289,19 +294,35 @@ glm::dvec2 WwtCommunicator::equatorialAim() const {
|
||||
return _equatorialAim;
|
||||
}
|
||||
|
||||
void WwtCommunicator::setImageOrder(int i, int order) {
|
||||
void WwtCommunicator::setImageOrder(const std::string& imageUrl, int order) {
|
||||
// Find in selected images list
|
||||
auto current = findSelectedImage(i);
|
||||
auto target = _selectedImages.begin() + order;
|
||||
auto current = findSelectedImage(imageUrl);
|
||||
int currentIndex = static_cast<int>(std::distance(_selectedImages.begin(), current));
|
||||
|
||||
// Make sure the image was found in the list
|
||||
if (current != _selectedImages.end() && target != _selectedImages.end()) {
|
||||
// Swap the two images
|
||||
std::iter_swap(current, target);
|
||||
std::deque<std::pair<std::string, double>> newDeque;
|
||||
|
||||
for (int i = 0; i < static_cast<int>(_selectedImages.size()); i++) {
|
||||
if (i == currentIndex) {
|
||||
continue;
|
||||
}
|
||||
else if (i == order) {
|
||||
if (order < currentIndex) {
|
||||
newDeque.push_back(*current);
|
||||
newDeque.push_back(_selectedImages[i]);
|
||||
}
|
||||
else {
|
||||
newDeque.push_back(_selectedImages[i]);
|
||||
newDeque.push_back(*current);
|
||||
}
|
||||
}
|
||||
else {
|
||||
newDeque.push_back(_selectedImages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_selectedImages = newDeque;
|
||||
int reverseOrder = static_cast<int>(_selectedImages.size()) - order - 1;
|
||||
ghoul::Dictionary message = setLayerOrderMessage(std::to_string(i), reverseOrder);
|
||||
ghoul::Dictionary message = setLayerOrderMessage(imageUrl, reverseOrder);
|
||||
sendMessageToWwt(message);
|
||||
}
|
||||
|
||||
@@ -311,11 +332,11 @@ void WwtCommunicator::loadImageCollection(const std::string& collection) {
|
||||
}
|
||||
}
|
||||
|
||||
void WwtCommunicator::setImageOpacity(int i, float opacity) {
|
||||
auto it = findSelectedImage(i);
|
||||
void WwtCommunicator::setImageOpacity(const std::string& imageUrl, float opacity) {
|
||||
auto it = findSelectedImage(imageUrl);
|
||||
it->second = opacity;
|
||||
|
||||
ghoul::Dictionary msg = setImageOpacityMessage(std::to_string(i), opacity);
|
||||
ghoul::Dictionary msg = setImageOpacityMessage(imageUrl, opacity);
|
||||
sendMessageToWwt(msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -28,18 +28,7 @@
|
||||
#include <openspace/util/httprequest.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <string_view>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
||||
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
|
||||
#include <modules/skybrowser/ext/tinyxml2/tinyxml2.h>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#include <tinyxml2.h>
|
||||
|
||||
namespace {
|
||||
constexpr std::string_view _loggerCat = "WwtDataHandler";
|
||||
@@ -182,9 +171,8 @@ namespace {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<openspace::ImageData> loadImageFromNode(
|
||||
const tinyxml2::XMLElement* node,
|
||||
std::string collection)
|
||||
std::optional<openspace::ImageData>
|
||||
loadImageFromNode(const tinyxml2::XMLElement* node, const std::string& collection)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
@@ -254,7 +242,8 @@ namespace {
|
||||
hasCelestialCoords,
|
||||
fov,
|
||||
equatorialSpherical,
|
||||
equatorialCartesian
|
||||
equatorialCartesian,
|
||||
""
|
||||
};
|
||||
}
|
||||
} //namespace
|
||||
@@ -295,7 +284,7 @@ void WwtDataHandler::loadImages(const std::string& root,
|
||||
if (std::filesystem::exists(localHashFile)) {
|
||||
std::ifstream(localHashFile) >> localHash;
|
||||
}
|
||||
|
||||
|
||||
// Check if the hash has changed. This will be ignored if either the local of remote
|
||||
// hash does not exist
|
||||
if (!localHash.empty() && !remoteHash.empty() && localHash != remoteHash) {
|
||||
@@ -307,7 +296,7 @@ void WwtDataHandler::loadImages(const std::string& root,
|
||||
std::filesystem::remove_all(directory);
|
||||
std::filesystem::create_directory(directory);
|
||||
}
|
||||
|
||||
|
||||
// If there is no directory (either because it is the first start, or the previous
|
||||
// contents were deleted because of a change in hash) we have to download the files
|
||||
if (std::filesystem::is_empty(directory)) {
|
||||
@@ -329,13 +318,21 @@ void WwtDataHandler::loadImages(const std::string& root,
|
||||
saveImagesFromXml(rootNode, collectionName);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort images in alphabetical order
|
||||
std::sort(
|
||||
_images.begin(),
|
||||
_images.end(),
|
||||
[](ImageData& a, ImageData& b) { return a.name < b.name; }
|
||||
// Sort images. Copy images to vector
|
||||
std::vector<ImageData> _imageVector;
|
||||
for (const auto& [id, img] : _images) {
|
||||
_imageVector.push_back(img);
|
||||
}
|
||||
// Sort
|
||||
std::sort(_imageVector.begin(), _imageVector.end(),
|
||||
[](const ImageData& lhs, const ImageData& rhs) {
|
||||
return lhs.name < rhs.name;
|
||||
}
|
||||
);
|
||||
// Set the identifiers to the correct order
|
||||
for (int i = 0; i < _imageVector.size(); i++) {
|
||||
_images[_imageVector[i].imageUrl].identifier = std::to_string(i);
|
||||
}
|
||||
|
||||
LINFO(fmt::format("Loaded {} WorldWide Telescope images", _images.size()));
|
||||
}
|
||||
@@ -344,9 +341,16 @@ int WwtDataHandler::nLoadedImages() const {
|
||||
return static_cast<int>(_images.size());
|
||||
}
|
||||
|
||||
const ImageData& WwtDataHandler::image(int i) const {
|
||||
ghoul_assert(i < static_cast<int>(_images.size()), "Index outside of vector size");
|
||||
return _images[i];
|
||||
std::optional<const ImageData> WwtDataHandler::image(const std::string& imageUrl) const {
|
||||
auto it = _images.find(imageUrl);
|
||||
if (it == _images.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const std::map<std::string, ImageData>& WwtDataHandler::images() const {
|
||||
return _images;
|
||||
}
|
||||
|
||||
void WwtDataHandler::saveImagesFromXml(const tinyxml2::XMLElement* root,
|
||||
@@ -361,9 +365,11 @@ void WwtDataHandler::saveImagesFromXml(const tinyxml2::XMLElement* root,
|
||||
const std::string name = node->Name();
|
||||
// If node is an image or place, load it
|
||||
if (name == ImageSet || name == Place) {
|
||||
std::optional<ImageData> image = loadImageFromNode(node, collection);
|
||||
std::optional<ImageData> image = loadImageFromNode(
|
||||
node, collection
|
||||
);
|
||||
if (image.has_value()) {
|
||||
_images.push_back(std::move(*image));
|
||||
_images.insert({ image.value().imageUrl, std::move(*image) });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user