Move the WWT data handling to class WWTDataHandler and add pointer in module

This commit is contained in:
Ylva Selling
2021-03-31 17:02:51 +02:00
parent b95d6e5b94
commit f99f3e88a9
6 changed files with 277 additions and 228 deletions

View File

@@ -29,6 +29,7 @@ set(HEADER_FILES
skybrowsermodule.h
include/screenspaceskybrowser.h
include/screenspaceskytarget.h
include/wwtdatahandler.h
tinyxml2/tinyxml2.h
)
@@ -40,6 +41,7 @@ set(SOURCE_FILES
skybrowsermodule_lua.inl
src/screenspaceskybrowser.cpp
src/screenspaceskytarget.cpp
src/wwtdatahandler.cpp
tinyxml2/tinyxml2.cpp
)

View File

@@ -0,0 +1,44 @@
#ifndef __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__
#define __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__
#include <openspace/documentation/documentation.h>
#include <modules/skybrowser/tinyxml2/tinyxml2.h>
namespace openspace::documentation { struct Documentation; }
namespace openspace {
struct ImageData {
std::string name;
std::string thumbnailUrl;
glm::vec2 celestCoords;
std::string collection;
};
class WWTDataHandler {
public:
WWTDataHandler() = default;
~WWTDataHandler();
// Image downloading and xml parsing
bool downloadFile(std::string& url, std::string& fileDestination);
void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName);
void loadWTMLCollectionsFromURL(std::string url, std::string fileName);
void loadWTMLCollectionsFromDirectory(std::string directory);
int loadAllImagesFromXMLs();
void printAllUrls();
private:
int loadPlace(tinyxml2::XMLElement* place, std::string collectionName);
int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName);
std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet);
tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name);
std::vector<ImageData> images;
std::vector<std::string> imageUrls;
std::vector<tinyxml2::XMLDocument*> xmls;
};
}
#endif // __OPENSPACE_MODULE_SKYBROWSER___WWTDATAHANDLER___H__

View File

@@ -23,8 +23,7 @@
****************************************************************************************/
#include <modules/skybrowser/skybrowsermodule.h>
#include <modules/skybrowser/tinyxml2/tinyxml2.h>
#include <modules/skybrowser/include/wwtdatahandler.h>
//#include <modules/webbrowser/webbrowsermodule.h>
//#include <modules/webbrowser/include/screenspacebrowser.h>
#include <openspace/rendering/screenspacerenderable.h>
@@ -43,10 +42,9 @@
#include <ghoul/opengl/texture.h>
#include <cmath> // For atan2
#include <glm/gtx/string_cast.hpp> // For printing glm data
#include <ghoul/filesystem/filesystem.h>
#include <openspace/util/httprequest.h> // For downloading files from url
#include <fstream>
#include <filesystem> // To iterate through files in directory
namespace {
struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters {
@@ -243,13 +241,9 @@ SkyBrowserModule::SkyBrowserModule()
}
);
}
SkyBrowserModule::~SkyBrowserModule() {
// Call destructor of all allocated xmls
xmls.clear();
}
void SkyBrowserModule::internalDeinitialize() {
delete dataHandler;
}
@@ -266,6 +260,7 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) {
ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created");
fScreenSpaceRenderable->registerClass<ScreenSpaceSkyTarget>("ScreenSpaceSkyTarget");
dataHandler = new WWTDataHandler();
}
glm::vec2 SkyBrowserModule::getMousePositionInScreenSpaceCoords(glm::vec2& mousePos) {
@@ -292,196 +287,10 @@ ScreenSpaceSkyTarget* SkyBrowserModule::to_target(ScreenSpaceRenderable* ptr) {
return dynamic_cast<ScreenSpaceSkyTarget*>(ptr);
}
bool SkyBrowserModule::downloadFile(std::string& url, std::string& fileDestination) {
// Get the webpage and save to file
HttpRequest::RequestOptions opt{ 5 };
SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes);
wtml_root.download(opt);
return wtml_root.hasSucceeded();
WWTDataHandler* SkyBrowserModule::getWWTDataHandler() {
return dataHandler;
}
void SkyBrowserModule::loadWTMLCollectionsFromURL(std::string url, std::string fileName) {
// Get file
std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/") + fileName + ".aspx";
if (!downloadFile(url, fileDestination)) {
LINFO("Couldn't download file " + url);
return;
}
// Parse to XML
using namespace tinyxml2;
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
doc->LoadFile(fileDestination.c_str());
XMLElement* root = doc->RootElement();
XMLElement* element = root->FirstChildElement(std::string("Folder").c_str());
// If there are no folders, or there are folder but without urls, stop recursion
if (!element || (element && !element->FindAttribute("Url"))) {
imageUrls.push_back(url);
xmls.push_back(doc);
LINFO("Saving " + url);
return;
}
// Iterate through all the folders
while (element && std::string(element->Value()) == "Folder") {
// Get all attributes for the <Folder>
std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : "";
std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : "";
if (subUrl != "" && subName != "") {
loadWTMLCollectionsFromURL(subUrl, subName);
}
element = element->NextSiblingElement();
}
}
void SkyBrowserModule::loadWTMLCollectionsFromDirectory(std::string directory) {
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
std::cout << entry.path().u8string().c_str() << std::endl;
if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) {
xmls.push_back(doc);
}
}
}
std::ostream& operator<<(std::ostream& os, const ImageData& img) {
os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl;
os << "Thumbnail: " << img.thumbnailUrl << std::endl;
os << "Collection: " << img.collection << std::endl << std::endl;
return os;
}
int SkyBrowserModule::loadAllImagesFromXMLs() {
for(tinyxml2::XMLDocument* doc : xmls) {
tinyxml2::XMLElement* root = doc->FirstChildElement();
std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : "";
loadImagesFromXML(root, collectionName);
}
for (ImageData img : images) {
std::cout << img;
}
return images.size();
}
void SkyBrowserModule::printAllUrls() {
for (auto it = imageUrls.begin(); it != imageUrls.end(); it++) {
LINFO(*it);
}
}
void SkyBrowserModule::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) {
// Get direct child of node called "Place"
using namespace tinyxml2;
XMLElement* folder = getChildNode(node->FirstChildElement(), "Folder");
// Terminate recursion if no folders
if (!folder) {
// When we are at leaf folder
// Iterate through all the places and load as images
// Prefer places over Image Sets as they contain same info
XMLElement* place = getChildNode(node->FirstChildElement(), "Place");
// No place found - look for images instead
if (!place) {
XMLElement* imageSet = getChildNode(node->FirstChildElement(), "ImageSet");
while (imageSet) {
loadImageSet(imageSet, collectionName);
imageSet = imageSet->NextSiblingElement();
}
}
// Place found - look through places
while (place) {
loadPlace(place, collectionName);
place = place->NextSiblingElement();
}
}
else {
// Open all folders at same level
while (folder) {
std::string newCollectionName = collectionName + "/";
if (folder->FindAttribute("Name")) {
newCollectionName += std::string(folder->FindAttribute("Name")->Value());
}
loadImagesFromXML(folder, newCollectionName);
folder = folder->NextSiblingElement();
}
}
}
int SkyBrowserModule::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) {
// Only load "Sky" type images
if (std::string(place->FindAttribute("DataSetType")->Value()) != "Sky")
return - 1;
std::string url = "";
// If the place doesn't have a thumbnail url data attribute,
// Load the containing image set instead
if (!place->FindAttribute("Thumbnail")) {
// Traverse the children and look at all their first child to find ImageSet
tinyxml2::XMLElement* child = place->FirstChildElement();
tinyxml2::XMLElement* imageSet = nullptr;
while (child) {
imageSet = getChildNode(child, "ImageSet");
if (imageSet) break;
child = child->NextSiblingElement();
}
// If the place doesn't contain an image, nothing to add
if (!imageSet) return -1;
// Collect thumbnail url from ImageSet
url = getURLFromImageSet(imageSet);
if (url == "") return -1;
}
ImageData image;
// Get attributes for the image
image.name = place->FindAttribute("Name") ? place->FindAttribute("Name")->Value() : "";
image.celestCoords.x = place->FindAttribute("RA") ? std::stof(place->FindAttribute("RA")->Value()) : 0.f;
image.celestCoords.y = place->FindAttribute("Dec") ? std::stof(place->FindAttribute("Dec")->Value()) : 0.f;
image.thumbnailUrl = url == "" ? place->FindAttribute("Thumbnail")->Value() : url;
image.collection = collectionName;
images.push_back(image);
// Return index of image in vector
return images.size();
}
int SkyBrowserModule::loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName) {
std::string type = imageSet->FindAttribute("DataSetType") ? imageSet->FindAttribute("DataSetType")->Value() : "";
// Only load "Sky" type images
if (type != "Sky")
return - 1;
ImageData image;
// Get attributes for the image
image.name = imageSet->FindAttribute("Name") ? imageSet->FindAttribute("Name")->Value() : "";
image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f;
image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f;
image.thumbnailUrl = getURLFromImageSet(imageSet);
image.collection = collectionName;
images.push_back(image);
// Return index of image in vector
return images.size();
}
std::string SkyBrowserModule::getURLFromImageSet(tinyxml2::XMLElement* imageSet) {
// FInd the thumbnail image url
// The thumbnail is the last node so traverse backwards for speed
tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement("ThumbnailUrl");
return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : "";
}
tinyxml2::XMLElement* SkyBrowserModule::getChildNode(tinyxml2::XMLElement* node, std::string name) {
while (node && std::string(node->Name()) != name) {
node = node->FirstChildElement();
}
return node;
}
/*
std::vector<documentation::Documentation> SkyBrowserModule::documentations() const {
return {

View File

@@ -26,7 +26,7 @@
#define __OPENSPACE_MODULE_SKYBROWSER___SKYBROWSERMODULE___H__
#include <openspace/util/openspacemodule.h>
#include <modules/skybrowser/tinyxml2/tinyxml2.h>
#include <openspace/documentation/documentation.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
@@ -38,40 +38,25 @@ namespace openspace {
class ScreenSpaceSkyBrowser;
class ScreenSpaceSkyTarget;
class ScreenSpaceRenderable;
class WWTDataHandler;
struct ImageData {
std::string name;
std::string thumbnailUrl;
glm::vec2 celestCoords;
std::string collection;
};
class SkyBrowserModule : public OpenSpaceModule {
public:
constexpr static const char* Name = "SkyBrowser";
SkyBrowserModule();
virtual ~SkyBrowserModule();
virtual ~SkyBrowserModule() = default;
glm::vec2 getMousePositionInScreenSpaceCoords(glm::vec2& mousePos);
void addRenderable(ScreenSpaceRenderable* object);
// Image downloading and xml parsing
bool downloadFile(std::string& url, std::string& fileDestination);
void loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName);
void loadWTMLCollectionsFromURL(std::string url, std::string fileName);
void loadWTMLCollectionsFromDirectory(std::string directory);
int loadAllImagesFromXMLs();
void printAllUrls();
WWTDataHandler* getWWTDataHandler();
scripting::LuaLibrary luaLibrary() const override;
//std::vector<documentation::Documentation> documentations() const override;
protected:
void internalInitialize(const ghoul::Dictionary& dict) override;
void internalDeinitialize() override;
int loadPlace(tinyxml2::XMLElement* place, std::string collectionName);
int loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName);
std::string getURLFromImageSet(tinyxml2::XMLElement* imageSet);
tinyxml2::XMLElement* getChildNode(tinyxml2::XMLElement* node, std::string name);
// Using snake case on these casting functions to make them similar to eg std::to_string
ScreenSpaceSkyBrowser* to_browser(ScreenSpaceRenderable* ptr);
ScreenSpaceSkyTarget* to_target(ScreenSpaceRenderable* ptr);
@@ -92,10 +77,7 @@ protected:
// Current interaction status
bool currentlyResizingBrowser;
bool currentlyDraggingObject;
std::vector<ImageData> images;
std::vector<std::string> imageUrls;
std::vector<tinyxml2::XMLDocument*> xmls;
WWTDataHandler* dataHandler;
};
} // namespace openspace

View File

@@ -49,9 +49,9 @@ namespace openspace::skybrowser::luascriptfunctions {
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/wwt-web-client/master/assets/webclient-explore-root.wtml";
module->loadWTMLCollectionsFromURL(root, "root");
module->printAllUrls();
LINFO(std::to_string( module->loadAllImagesFromXMLs()));
module->getWWTDataHandler()->loadWTMLCollectionsFromURL(root, "root");
module->getWWTDataHandler()->printAllUrls();
LINFO(std::to_string( module->getWWTDataHandler()->loadAllImagesFromXMLs()));
return 1;
}
@@ -59,9 +59,9 @@ namespace openspace::skybrowser::luascriptfunctions {
int moveBrowser(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::moveBrowser");
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
module->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/"));
module->printAllUrls();
LINFO(std::to_string(module->loadAllImagesFromXMLs()));
module->getWWTDataHandler()->loadWTMLCollectionsFromDirectory(absPath("${MODULE_SKYBROWSER}/WWTimagedata/"));
module->getWWTDataHandler()->printAllUrls();
LINFO(std::to_string(module->getWWTDataHandler()->loadAllImagesFromXMLs()));
return 1;
}

View File

@@ -0,0 +1,212 @@
#include <modules/skybrowser/include/wwtdatahandler.h>
#include <openspace/util/httprequest.h> // For downloading files from url
#include <filesystem> // To iterate through files in directory
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* _loggerCat = "WWTDataHandler";
} //namespace
namespace openspace {
WWTDataHandler::~WWTDataHandler() {
// Call destructor of all allocated xmls
xmls.clear();
}
bool WWTDataHandler::downloadFile(std::string& url, std::string& fileDestination) {
// Get the webpage and save to file
HttpRequest::RequestOptions opt{ 5 };
SyncHttpFileDownload wtml_root(url, fileDestination, HttpFileDownload::Overwrite::Yes);
wtml_root.download(opt);
return wtml_root.hasSucceeded();
}
void WWTDataHandler::loadWTMLCollectionsFromURL(std::string url, std::string fileName) {
// Get file
std::string fileDestination = absPath("${MODULE_SKYBROWSER}/WWTimagedata/") + fileName + ".aspx";
if (!downloadFile(url, fileDestination)) {
LINFO("Couldn't download file " + url);
return;
}
// Parse to XML
using namespace tinyxml2;
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
doc->LoadFile(fileDestination.c_str());
XMLElement* root = doc->RootElement();
XMLElement* element = root->FirstChildElement(std::string("Folder").c_str());
// If there are no folders, or there are folder but without urls, stop recursion
if (!element || (element && !element->FindAttribute("Url"))) {
imageUrls.push_back(url);
xmls.push_back(doc);
LINFO("Saving " + url);
return;
}
// Iterate through all the folders
while (element && std::string(element->Value()) == "Folder") {
// Get all attributes for the <Folder>
std::string subUrl = element->FindAttribute("Url") ? element->FindAttribute("Url")->Value() : "";
std::string subName = element->FindAttribute("Name") ? element->FindAttribute("Name")->Value() : "";
if (subUrl != "" && subName != "") {
loadWTMLCollectionsFromURL(subUrl, subName);
}
element = element->NextSiblingElement();
}
}
void WWTDataHandler::loadWTMLCollectionsFromDirectory(std::string directory) {
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
std::cout << entry.path().u8string().c_str() << std::endl;
if (doc->LoadFile(entry.path().u8string().c_str()) == tinyxml2::XMLError::XML_SUCCESS) {
xmls.push_back(doc);
}
}
}
std::ostream& operator<<(std::ostream& os, const ImageData& img) {
os << "Name: " << img.name << " Coords: ra: " << img.celestCoords.x << " dec: " << img.celestCoords.y << std::endl;
os << "Thumbnail: " << img.thumbnailUrl << std::endl;
os << "Collection: " << img.collection << std::endl << std::endl;
return os;
}
int WWTDataHandler::loadAllImagesFromXMLs() {
for (tinyxml2::XMLDocument* doc : xmls) {
tinyxml2::XMLElement* root = doc->FirstChildElement();
std::string collectionName = root->FindAttribute("Name") ? root->FindAttribute("Name")->Value() : "";
loadImagesFromXML(root, collectionName);
}
for (ImageData img : images) {
std::cout << img;
}
return images.size();
}
void WWTDataHandler::printAllUrls() {
for (auto it = imageUrls.begin(); it != imageUrls.end(); it++) {
LINFO(*it);
}
}
void WWTDataHandler::loadImagesFromXML(tinyxml2::XMLElement* node, std::string collectionName) {
// Get direct child of node called "Place"
using namespace tinyxml2;
XMLElement* folder = getChildNode(node->FirstChildElement(), "Folder");
// Terminate recursion if no folders
if (!folder) {
// When we are at leaf folder
// Iterate through all the places and load as images
// Prefer places over Image Sets as they contain same info
XMLElement* place = getChildNode(node->FirstChildElement(), "Place");
// No place found - look for images instead
if (!place) {
XMLElement* imageSet = getChildNode(node->FirstChildElement(), "ImageSet");
while (imageSet) {
loadImageSet(imageSet, collectionName);
imageSet = imageSet->NextSiblingElement();
}
}
// Place found - look through places
while (place) {
loadPlace(place, collectionName);
place = place->NextSiblingElement();
}
}
else {
// Open all folders at same level
while (folder) {
std::string newCollectionName = collectionName + "/";
if (folder->FindAttribute("Name")) {
newCollectionName += std::string(folder->FindAttribute("Name")->Value());
}
loadImagesFromXML(folder, newCollectionName);
folder = folder->NextSiblingElement();
}
}
}
int WWTDataHandler::loadPlace(tinyxml2::XMLElement* place, std::string collectionName) {
// Only load "Sky" type images
if (std::string(place->FindAttribute("DataSetType")->Value()) != "Sky")
return -1;
std::string url = "";
// If the place doesn't have a thumbnail url data attribute,
// Load the containing image set instead
if (!place->FindAttribute("Thumbnail")) {
// Traverse the children and look at all their first child to find ImageSet
tinyxml2::XMLElement* child = place->FirstChildElement();
tinyxml2::XMLElement* imageSet = nullptr;
while (child) {
imageSet = getChildNode(child, "ImageSet");
if (imageSet) break;
child = child->NextSiblingElement();
}
// If the place doesn't contain an image, nothing to add
if (!imageSet) return -1;
// Collect thumbnail url from ImageSet
url = getURLFromImageSet(imageSet);
if (url == "") return -1;
}
ImageData image;
// Get attributes for the image
image.name = place->FindAttribute("Name") ? place->FindAttribute("Name")->Value() : "";
image.celestCoords.x = place->FindAttribute("RA") ? std::stof(place->FindAttribute("RA")->Value()) : 0.f;
image.celestCoords.y = place->FindAttribute("Dec") ? std::stof(place->FindAttribute("Dec")->Value()) : 0.f;
image.thumbnailUrl = url == "" ? place->FindAttribute("Thumbnail")->Value() : url;
image.collection = collectionName;
images.push_back(image);
// Return index of image in vector
return images.size();
}
int WWTDataHandler::loadImageSet(tinyxml2::XMLElement* imageSet, std::string collectionName) {
std::string type = imageSet->FindAttribute("DataSetType") ? imageSet->FindAttribute("DataSetType")->Value() : "";
// Only load "Sky" type images
if (type != "Sky")
return -1;
ImageData image;
// Get attributes for the image
image.name = imageSet->FindAttribute("Name") ? imageSet->FindAttribute("Name")->Value() : "";
image.celestCoords.x = imageSet->FindAttribute("RA") ? std::stof(imageSet->FindAttribute("RA")->Value()) : 0.f;
image.celestCoords.y = imageSet->FindAttribute("Dec") ? std::stof(imageSet->FindAttribute("Dec")->Value()) : 0.f;
image.thumbnailUrl = getURLFromImageSet(imageSet);
image.collection = collectionName;
images.push_back(image);
// Return index of image in vector
return images.size();
}
std::string WWTDataHandler::getURLFromImageSet(tinyxml2::XMLElement* imageSet) {
// FInd the thumbnail image url
// The thumbnail is the last node so traverse backwards for speed
tinyxml2::XMLElement* imageSetChild = imageSet->FirstChildElement("ThumbnailUrl");
return imageSetChild ? imageSetChild->GetText() ? imageSetChild->GetText() : "" : "";
}
tinyxml2::XMLElement* WWTDataHandler::getChildNode(tinyxml2::XMLElement* node, std::string name) {
while (node && std::string(node->Name()) != name) {
node = node->FirstChildElement();
}
return node;
}
}