From 42f1b4837256347517ae112f87222095e1058ed9 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 16 Dec 2022 11:28:08 -0500 Subject: [PATCH 1/5] Change sky browser to use id's instead of indices to get the images --- .../skybrowser/include/targetbrowserpair.h | 12 ++-- modules/skybrowser/include/wwtcommunicator.h | 17 +++--- modules/skybrowser/include/wwtdatahandler.h | 10 ++-- modules/skybrowser/skybrowsermodule.cpp | 4 +- modules/skybrowser/skybrowsermodule.h | 2 +- modules/skybrowser/skybrowsermodule_lua.inl | 51 +++++++++-------- modules/skybrowser/src/targetbrowserpair.cpp | 32 +++++++---- modules/skybrowser/src/wwtcommunicator.cpp | 56 ++++++++++--------- modules/skybrowser/src/wwtdatahandler.cpp | 36 ++++++------ 9 files changed, 121 insertions(+), 99 deletions(-) diff --git a/modules/skybrowser/include/targetbrowserpair.h b/modules/skybrowser/include/targetbrowserpair.h index cecc046544..223264e218 100644 --- a/modules/skybrowser/include/targetbrowserpair.h +++ b/modules/skybrowser/include/targetbrowserpair.h @@ -87,17 +87,17 @@ public: std::string targetNodeId() const; ScreenSpaceSkyBrowser* browser() const; - std::vector selectedImages() const; + std::vector selectedImages() const; ghoul::Dictionary dataAsDictionary() const; // WorldWide Telescope image handling - void setImageOrder(int i, int order); - void selectImage(const ImageData& image, int i); - void addImageLayerToWwt(const std::string& url, int i); - void removeSelectedImage(int i); + void setImageOrder(const std::string& imageUrl, int order); + void selectImage(const ImageData& image); + void addImageLayerToWwt(const std::string& imageUrl); + void removeSelectedImage(const std::string& imageUrl); void loadImageCollection(const std::string& collection); - void setImageOpacity(int i, float opacity); + void setImageOpacity(const std::string& imageUrl, float opacity); void hideChromeInterface(); private: diff --git a/modules/skybrowser/include/wwtcommunicator.h b/modules/skybrowser/include/wwtcommunicator.h index c28dbb7c94..7204b1ebf4 100644 --- a/modules/skybrowser/include/wwtcommunicator.h +++ b/modules/skybrowser/include/wwtcommunicator.h @@ -31,6 +31,7 @@ #include namespace openspace { +using SelectedImageDeque = std::deque>; class WwtCommunicator : public Browser { public: @@ -40,12 +41,12 @@ public: void update(); // WorldWide Telescope communication - void selectImage(const std::string& url, int i); - void addImageLayerToWwt(const std::string& url, int i); - void removeSelectedImage(int i); - void setImageOrder(int i, int order); + void selectImage(const std::string& imageUrl); + void addImageLayerToWwt(const std::string& imageUrl); + void removeSelectedImage(const std::string& imageUrl); + void setImageOrder(const std::string& imageUrl, int order); void loadImageCollection(const std::string& collection); - void setImageOpacity(int i, float opacity); + void setImageOpacity(const std::string& imageUrl, float opacity); void hideChromeInterface() const; bool isImageCollectionLoaded() const; @@ -54,7 +55,7 @@ public: glm::ivec3 borderColor() const; glm::dvec2 equatorialAim() const; glm::dvec2 fieldsOfView() const; - std::vector selectedImages() const; + std::vector selectedImages() const; std::vector opacities() const; double borderRadius() const; @@ -70,7 +71,7 @@ public: protected: void setIdInBrowser(const std::string& id) const; - std::deque>::iterator findSelectedImage(int i); + SelectedImageDeque::iterator findSelectedImage(const std::string& id); properties::DoubleProperty _verticalFov; @@ -79,7 +80,7 @@ protected: glm::dvec2 _equatorialAim = glm::dvec2(0.0); double _targetRoll = 0.0; bool _isImageCollectionLoaded = false; - std::deque> _selectedImages; + SelectedImageDeque _selectedImages; private: void sendMessageToWwt(const ghoul::Dictionary& msg) const; diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index fe7d289879..922f19fa0a 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -35,9 +35,9 @@ namespace openspace { namespace documentation { struct Documentation; } struct ImageData { - std::string name; + std::string name = ""; std::string thumbnailUrl; - std::string imageUrl; + std::string imageUrl = ""; std::string credits; std::string creditsUrl; std::string collection; @@ -45,19 +45,21 @@ struct ImageData { float fov = 0.f; glm::dvec2 equatorialSpherical = glm::dvec2(0.0); glm::dvec3 equatorialCartesian = glm::dvec3(0.0); + std::string identifier; }; class WwtDataHandler { public: void loadImages(const std::string& root, const std::filesystem::path& directory); int nLoadedImages() const; - const ImageData& image(int i) const; + const ImageData& image(const std::string& imageUrl) const; + const std::map& images() const; private: void saveImagesFromXml(const tinyxml2::XMLElement* root, std::string collection); // Images - std::vector _images; + std::map _images; }; } // namespace openspace diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 7307a1d41e..9e8175f97c 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -318,8 +318,8 @@ void SkyBrowserModule::setHoverCircle(SceneGraphNode* circle) { disableHoverCircle(); } -void SkyBrowserModule::moveHoverCircle(int i, bool useScript) { - const ImageData& image = _dataHandler.image(i); +void SkyBrowserModule::moveHoverCircle(const std::string& imageUrl, bool useScript) { + const ImageData& image = _dataHandler.image(imageUrl); // Only move and show circle if the image has coordinates if (!(_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem)) { diff --git a/modules/skybrowser/skybrowsermodule.h b/modules/skybrowser/skybrowsermodule.h index 04810aff33..343dc7d36a 100644 --- a/modules/skybrowser/skybrowsermodule.h +++ b/modules/skybrowser/skybrowsermodule.h @@ -76,7 +76,7 @@ public: void addTargetBrowserPair(const std::string& targetId, const std::string& browserId); // Hover circle - void moveHoverCircle(int i, bool useScript = true); + void moveHoverCircle(const std::string& imageUrl, bool useScript = true); void disableHoverCircle(bool useScript = true); // Image collection handling diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 30bdf3d243..4ffd73c4b7 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -74,7 +74,7 @@ namespace { * Takes an index to an image and selects that image in the currently * selected sky browser. */ -[[codegen::luawrap]] void selectImage(int imageIndex) { +[[codegen::luawrap]] void selectImage(std::string imageUrl) { using namespace openspace; // Load image @@ -83,7 +83,13 @@ namespace { if (module->isCameraInSolarSystem()) { TargetBrowserPair* selected = module->pair(module->selectedBrowserId()); if (selected) { - const ImageData& image = module->wwtDataHandler().image(imageIndex); + const ImageData& image = module->wwtDataHandler().image(imageUrl); + if (image.name == "") { + LINFO(fmt::format( + "No image with identifier {} was found in the collection.", imageUrl + )); + return; + } // Load image into browser std::string str = image.name; // Check if character is ASCII - if it isn't, remove @@ -97,7 +103,7 @@ namespace { str.end() ); LINFO("Loading image " + str); - selected->selectImage(image, imageIndex); + selected->selectImage(image); bool isInView = skybrowser::isCoordinateInView(image.equatorialCartesian); // If the coordinate is not in view, rotate camera @@ -130,10 +136,10 @@ namespace { /** * Moves the hover circle to the coordinate specified by the image index. */ -[[codegen::luawrap]] void moveCircleToHoverImage(int imageIndex) { +[[codegen::luawrap]] void moveCircleToHoverImage(std::string imageUrl) { using namespace openspace; - global::moduleEngine->module()->moveHoverCircle(imageIndex, false); + global::moduleEngine->module()->moveHoverCircle(imageUrl, false); } /** @@ -150,7 +156,7 @@ namespace { * which it should have in the selected image list. The image is then changed to have this * order. */ -[[codegen::luawrap]] void setImageLayerOrder(std::string identifier, int imageIndex, +[[codegen::luawrap]] void setImageLayerOrder(std::string identifier, std::string imageUrl, int imageOrder) { using namespace openspace; @@ -158,7 +164,7 @@ namespace { SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* pair = module->pair(identifier); if (pair) { - pair->setImageOrder(imageIndex, imageOrder); + pair->setImageOrder(imageUrl, imageOrder); } } @@ -296,10 +302,9 @@ namespace { // Create Lua table to send to the GUI ghoul::Dictionary list; - - for (int i = 0; i < module->nLoadedImages(); i++) { - const ImageData& img = module->wwtDataHandler().image(i); - + for (auto const& [id, img] : module->wwtDataHandler().images()) { + const ImageData& img = module->wwtDataHandler().image(id); + // Push ("Key", value) ghoul::Dictionary image; image.setValue("name", img.name); @@ -312,11 +317,9 @@ namespace { image.setValue("hasCelestialCoords", img.hasCelestialCoords); image.setValue("credits", img.credits); image.setValue("creditsUrl", img.creditsUrl); - image.setValue("identifier", std::to_string(i)); + image.setValue("identifier", img.identifier); - // Index for current ImageData - // Set table for the current ImageData - list.setValue(std::to_string(i + 1), image); + list.setValue(img.identifier, image); } return list; @@ -409,15 +412,15 @@ namespace { * Takes an identifier to a sky browser or sky target, an index to an image and a value * for the opacity. */ -[[codegen::luawrap]] void setOpacityOfImageLayer(std::string identifier, int imageIndex, - float opacity) +[[codegen::luawrap]] void setOpacityOfImageLayer(std::string identifier, + std::string imageUrl, float opacity) { using namespace openspace; SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* pair = module->pair(identifier); if (pair) { - pair->setImageOpacity(imageIndex, opacity); + pair->setImageOpacity(imageUrl, opacity); } } @@ -590,14 +593,14 @@ namespace { * image from that sky browser. */ [[codegen::luawrap]] void removeSelectedImageInBrowser(std::string identifier, - int imageIndex) + std::string imageUrl) { using namespace openspace; SkyBrowserModule* module = global::moduleEngine->module(); TargetBrowserPair* pair = module->pair(identifier); if (pair) { - pair->browser()->removeSelectedImage(imageIndex); + pair->browser()->removeSelectedImage(imageUrl); } } @@ -768,13 +771,13 @@ namespace { LINFO("Image collection is loaded in Screen Space Sky Browser " + identifier); pair->setImageCollectionIsLoaded(true); // Add all selected images to WorldWide Telescope - const std::vector& images = pair->selectedImages(); + const std::vector& images = pair->selectedImages(); std::for_each( images.rbegin(), images.rend(), - [&](int index) { - const ImageData& image = module->wwtDataHandler().image(index); + [&](std::string imageUrl) { + const ImageData& image = module->wwtDataHandler().image(imageUrl); // Index of image is used as layer ID as it's unique in the image data set - pair->browser()->addImageLayerToWwt(image.imageUrl, index); + pair->browser()->addImageLayerToWwt(image.imageUrl); } ); } diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index bb776c0671..ba1eeac821 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -69,8 +69,8 @@ TargetBrowserPair::TargetBrowserPair(SceneGraphNode* targetNode, _targetRenderable = dynamic_cast(_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() { @@ -151,13 +151,21 @@ double TargetBrowserPair::verticalFov() const { return _browser->verticalFov(); } -std::vector TargetBrowserPair::selectedImages() const { +std::vector 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(); + std::vector selectedImagesIndices; + + for (const std::string& imageUrl : selectedImages()) { + selectedImagesIndices.push_back( + module->wwtDataHandler().image(imageUrl).identifier + ); + } ghoul::Dictionary res; res.setValue("id", browserId()); @@ -172,7 +180,7 @@ ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const { res.setValue("ratio", static_cast(_browser->browserRatio())); res.setValue("isFacingCamera", isFacingCamera()); res.setValue("isUsingRae", isUsingRadiusAzimuthElevation()); - res.setValue("selectedImages", selectedImages()); + res.setValue("selectedImages", selectedImagesIndices); res.setValue("scale", static_cast(_browser->scale())); res.setValue("opacities", _browser->opacities()); res.setValue("borderRadius", _browser->borderRadius()); @@ -193,9 +201,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) { @@ -205,20 +213,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() { diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 08263b68e2..834f2892e1 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -68,12 +68,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 +100,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 +109,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 +164,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(i, 1.0)); + _selectedImages.push_front(std::pair(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 +199,14 @@ void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) const { executeJavascript(fmt::format("sendMessageToWWT({});", m)); } -std::vector WwtCommunicator::selectedImages() const { - std::vector selectedImagesVector; +std::vector WwtCommunicator::selectedImages() const { + std::vector selectedImagesVector; selectedImagesVector.resize(_selectedImages.size()); std::transform( _selectedImages.cbegin(), _selectedImages.cend(), selectedImagesVector.begin(), - [](const std::pair& image) { return image.first; } + [](const std::pair& image) { return image.first; } ); return selectedImagesVector; } @@ -218,7 +218,7 @@ std::vector WwtCommunicator::opacities() const { _selectedImages.cbegin(), _selectedImages.cend(), opacities.begin(), - [](const std::pair& image) { return image.second; } + [](const std::pair& image) { return image.second; } ); return opacities; } @@ -276,11 +276,15 @@ bool WwtCommunicator::isImageCollectionLoaded() const { return _isImageCollectionLoaded; } -std::deque>::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& pair) { return pair.first == i; } + [imageUrl](const std::pair& pair) { + return pair.first == imageUrl; + } ); return it; } @@ -289,9 +293,9 @@ 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 current = findSelectedImage(imageUrl); auto target = _selectedImages.begin() + order; // Make sure the image was found in the list @@ -301,7 +305,7 @@ void WwtCommunicator::setImageOrder(int i, int order) { } int reverseOrder = static_cast(_selectedImages.size()) - order - 1; - ghoul::Dictionary message = setLayerOrderMessage(std::to_string(i), reverseOrder); + ghoul::Dictionary message = setLayerOrderMessage(imageUrl, reverseOrder); sendMessageToWwt(message); } @@ -311,11 +315,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); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 5416a1fa92..4198530e51 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -182,9 +182,9 @@ namespace { return true; } - std::optional loadImageFromNode( - const tinyxml2::XMLElement* node, - std::string collection) + std::optional + loadImageFromNode(const tinyxml2::XMLElement* node, const std::string& collection, + const std::string& identifier) { using namespace openspace; @@ -254,7 +254,8 @@ namespace { hasCelestialCoords, fov, equatorialSpherical, - equatorialCartesian + equatorialCartesian, + identifier }; } } //namespace @@ -330,13 +331,6 @@ void WwtDataHandler::loadImages(const std::string& root, } } - // Sort images in alphabetical order - std::sort( - _images.begin(), - _images.end(), - [](ImageData& a, ImageData& b) { return a.name < b.name; } - ); - LINFO(fmt::format("Loaded {} WorldWide Telescope images", _images.size())); } @@ -344,9 +338,16 @@ int WwtDataHandler::nLoadedImages() const { return static_cast(_images.size()); } -const ImageData& WwtDataHandler::image(int i) const { - ghoul_assert(i < static_cast(_images.size()), "Index outside of vector size"); - return _images[i]; +const ImageData& WwtDataHandler::image(const std::string& imageUrl) const { + auto it = _images.find(imageUrl); + if (it == _images.end()) { + return ImageData(); + } + return it->second; +} + +const std::map& WwtDataHandler::images() const { + return _images; } void WwtDataHandler::saveImagesFromXml(const tinyxml2::XMLElement* root, @@ -361,9 +362,12 @@ 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 image = loadImageFromNode(node, collection); + std::string identifier = std::to_string(_images.size()); + std::optional image = loadImageFromNode( + node, collection, identifier + ); if (image.has_value()) { - _images.push_back(std::move(*image)); + _images.insert({ image.value().imageUrl, std::move(*image) }); } } From 29fe0e7975be253d72c9870ceb5a286796c9a0cb Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 16 Dec 2022 16:44:09 -0500 Subject: [PATCH 2/5] Make image get function return std::optional if the image is not found --- modules/skybrowser/include/wwtdatahandler.h | 6 +++--- modules/skybrowser/skybrowsermodule.cpp | 7 +++++-- modules/skybrowser/skybrowsermodule_lua.inl | 11 ++++++----- modules/skybrowser/src/targetbrowserpair.cpp | 2 +- modules/skybrowser/src/wwtdatahandler.cpp | 4 ++-- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/modules/skybrowser/include/wwtdatahandler.h b/modules/skybrowser/include/wwtdatahandler.h index 922f19fa0a..175f5cb514 100644 --- a/modules/skybrowser/include/wwtdatahandler.h +++ b/modules/skybrowser/include/wwtdatahandler.h @@ -35,9 +35,9 @@ namespace openspace { namespace documentation { struct Documentation; } struct ImageData { - std::string name = ""; + std::string name; std::string thumbnailUrl; - std::string imageUrl = ""; + std::string imageUrl; std::string credits; std::string creditsUrl; std::string collection; @@ -52,7 +52,7 @@ class WwtDataHandler { public: void loadImages(const std::string& root, const std::filesystem::path& directory); int nLoadedImages() const; - const ImageData& image(const std::string& imageUrl) const; + std::optional image(const std::string& imageUrl) const; const std::map& images() const; private: diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index 9e8175f97c..5a718950ee 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -319,8 +319,11 @@ void SkyBrowserModule::setHoverCircle(SceneGraphNode* circle) { } void SkyBrowserModule::moveHoverCircle(const std::string& imageUrl, bool useScript) { - const ImageData& image = _dataHandler.image(imageUrl); - + std::optional found = _dataHandler.image(imageUrl); + if (!found.has_value()) { + return; + } + const ImageData image = found.value(); // Only move and show circle if the image has coordinates if (!(_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem)) { return; diff --git a/modules/skybrowser/skybrowsermodule_lua.inl b/modules/skybrowser/skybrowsermodule_lua.inl index 4ffd73c4b7..e4d3f3836c 100644 --- a/modules/skybrowser/skybrowsermodule_lua.inl +++ b/modules/skybrowser/skybrowsermodule_lua.inl @@ -83,14 +83,17 @@ namespace { if (module->isCameraInSolarSystem()) { TargetBrowserPair* selected = module->pair(module->selectedBrowserId()); if (selected) { - const ImageData& image = module->wwtDataHandler().image(imageUrl); - if (image.name == "") { + std::optional found = module->wwtDataHandler().image( + imageUrl + ); + if (!found.has_value()) { LINFO(fmt::format( "No image with identifier {} was found in the collection.", imageUrl )); return; } // Load image into browser + const ImageData& image = found.value(); std::string str = image.name; // Check if character is ASCII - if it isn't, remove str.erase( @@ -303,8 +306,6 @@ namespace { // Create Lua table to send to the GUI ghoul::Dictionary list; for (auto const& [id, img] : module->wwtDataHandler().images()) { - const ImageData& img = module->wwtDataHandler().image(id); - // Push ("Key", value) ghoul::Dictionary image; image.setValue("name", img.name); @@ -775,7 +776,7 @@ namespace { std::for_each( images.rbegin(), images.rend(), [&](std::string imageUrl) { - const ImageData& image = module->wwtDataHandler().image(imageUrl); + const ImageData& image = module->wwtDataHandler().image(imageUrl).value(); // Index of image is used as layer ID as it's unique in the image data set pair->browser()->addImageLayerToWwt(image.imageUrl); } diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index ba1eeac821..8421964f1c 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -163,7 +163,7 @@ ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const { for (const std::string& imageUrl : selectedImages()) { selectedImagesIndices.push_back( - module->wwtDataHandler().image(imageUrl).identifier + module->wwtDataHandler().image(imageUrl).value().identifier ); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index 4198530e51..eaba94a547 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -338,10 +338,10 @@ int WwtDataHandler::nLoadedImages() const { return static_cast(_images.size()); } -const ImageData& WwtDataHandler::image(const std::string& imageUrl) const { +std::optional WwtDataHandler::image(const std::string& imageUrl) const { auto it = _images.find(imageUrl); if (it == _images.end()) { - return ImageData(); + return std::nullopt; } return it->second; } From 3698300d78cf74d5be4573e7860cc1862af3092a Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 27 Jan 2023 21:49:16 +0100 Subject: [PATCH 3/5] Update Ghoul repository --- ext/ghoul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ghoul b/ext/ghoul index e2d607f75a..50846bc21a 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit e2d607f75a128914585b21f9bd70e1c1ccf06580 +Subproject commit 50846bc21aa087c0843c6f3107200680dda8c3e2 From b7ca19dff7f54926032d87e1afca5290d94ca265 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Fri, 27 Jan 2023 17:06:22 -0500 Subject: [PATCH 4/5] Address comments on PR --- modules/skybrowser/skybrowsermodule.cpp | 2 +- modules/skybrowser/src/targetbrowserpair.cpp | 4 +++- modules/skybrowser/src/wwtdatahandler.cpp | 23 +++++++++++++++----- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/modules/skybrowser/skybrowsermodule.cpp b/modules/skybrowser/skybrowsermodule.cpp index ae14dc40dd..ef1d2593a7 100644 --- a/modules/skybrowser/skybrowsermodule.cpp +++ b/modules/skybrowser/skybrowsermodule.cpp @@ -323,7 +323,7 @@ void SkyBrowserModule::moveHoverCircle(const std::string& imageUrl, bool useScri if (!found.has_value()) { return; } - const ImageData image = found.value(); + const ImageData image = *found; // Only move and show circle if the image has coordinates if (!(_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem)) { return; diff --git a/modules/skybrowser/src/targetbrowserpair.cpp b/modules/skybrowser/src/targetbrowserpair.cpp index e1bef63dfc..e72311d49f 100644 --- a/modules/skybrowser/src/targetbrowserpair.cpp +++ b/modules/skybrowser/src/targetbrowserpair.cpp @@ -162,8 +162,10 @@ ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const { std::vector 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).value().identifier + module->wwtDataHandler().image(imageUrl)->identifier ); } diff --git a/modules/skybrowser/src/wwtdatahandler.cpp b/modules/skybrowser/src/wwtdatahandler.cpp index aef4f02e9c..b331840a44 100644 --- a/modules/skybrowser/src/wwtdatahandler.cpp +++ b/modules/skybrowser/src/wwtdatahandler.cpp @@ -183,8 +183,7 @@ namespace { } std::optional - loadImageFromNode(const tinyxml2::XMLElement* node, const std::string& collection, - const std::string& identifier) + loadImageFromNode(const tinyxml2::XMLElement* node, const std::string& collection) { using namespace openspace; @@ -255,7 +254,7 @@ namespace { fov, equatorialSpherical, equatorialCartesian, - identifier + "" }; } } //namespace @@ -330,6 +329,21 @@ void WwtDataHandler::loadImages(const std::string& root, saveImagesFromXml(rootNode, collectionName); } } + // Sort images. Copy images to vector + std::vector _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())); } @@ -362,9 +376,8 @@ 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::string identifier = std::to_string(_images.size()); std::optional image = loadImageFromNode( - node, collection, identifier + node, collection ); if (image.has_value()) { _images.insert({ image.value().imageUrl, std::move(*image) }); From 3de5c1b75cfa73865877c79396c79e1ced3baf72 Mon Sep 17 00:00:00 2001 From: Ylva Selling Date: Thu, 9 Feb 2023 16:29:54 -0500 Subject: [PATCH 5/5] Update hash to updated GUI --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 1e5501383a..5edcc06087 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require("./static_server") local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "5011a84942cee1567565a4be250501f4453f26a2" +local frontendHash = "644f308be66309c2089bf6f94929205b24d56a8f" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({