From ebc6fbef11060f5b3668903d5b3b446705bc698b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 23 Jul 2025 15:18:32 +0200 Subject: [PATCH] Support relative paths in GeoJSON SpriteTexture (#3761) --- ...geojson_points_relative_texture_path.asset | 51 +++++++++++++++++++ modules/globebrowsing/globebrowsingmodule.cpp | 4 +- modules/globebrowsing/globebrowsingmodule.h | 2 +- .../src/geojson/geojsoncomponent.cpp | 10 +++- .../src/geojson/geojsonproperties.cpp | 8 +-- .../src/geojson/geojsonproperties.h | 4 +- .../src/geojson/globegeometryfeature.cpp | 7 ++- src/rendering/texturecomponent.cpp | 16 ++---- 8 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 data/assets/examples/geojson/geojson_points_relative_texture_path.asset diff --git a/data/assets/examples/geojson/geojson_points_relative_texture_path.asset b/data/assets/examples/geojson/geojson_points_relative_texture_path.asset new file mode 100644 index 0000000000..0a020e2fd6 --- /dev/null +++ b/data/assets/examples/geojson/geojson_points_relative_texture_path.asset @@ -0,0 +1,51 @@ +local earth = asset.require("scene/solarsystem/planets/earth/earth") + + + +-- These two files are downloaded from the servers when the asset gets loaded. Specifying +-- these two URLs in this way will cause them to be downloaded into the same folder on the +-- harddisk. For this example this is important as the points-relative.geojson will ask +-- for the image.png in the same folder by specifying "./image.png" +local data = asset.resource({ + Name = "GeoJSON Example Relative Texture Path", + Type = "UrlSynchronization", + Identifier = "geojson_example_points_relative_path", + Url = { + "http://liu-se.cdn.openspaceproject.com/files/examples/geojson/points-relative.geojson", + "http://liu-se.cdn.openspaceproject.com/files/examples/geojson/image.png" + } +}) + + +local ExamplePoints = { + Identifier = "Points-Example-RelativeTexturePath", + File = data .. "points-relative.geojson", + HeightOffset = 20000.0, + DefaultProperties = { + PointSize = 10.0 + }, + Name = "Example Points (Relative Texture Path)" +} + + +asset.onInitialize(function() + openspace.globebrowsing.addGeoJson(earth.Earth.Identifier, ExamplePoints) +end) + +asset.onDeinitialize(function() + openspace.globebrowsing.deleteGeoJson(earth.Earth.Identifier, ExamplePoints) +end) + +asset.export(ExamplePoints) + + + +asset.meta = { + Name = "GeoJson Example - Points (Relative Texture Path)", + Description = [[GeoJson example asset with points that are facing the camera + (default). This example is using a relative path to specify the location of the image + that is to be used.]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 770899abef..bfdc111f01 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -496,8 +496,8 @@ bool GlobeBrowsingModule::hasDefaultGeoPointTexture() const { return _hasDefaultGeoPointTexture; } -std::string_view GlobeBrowsingModule::defaultGeoPointTexture() const { - return _defaultGeoPointTexturePath; +std::filesystem::path GlobeBrowsingModule::defaultGeoPointTexture() const { + return _defaultGeoPointTexturePath.value(); } scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 4617cd7b98..bdfd7af503 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -90,7 +90,7 @@ public: std::string mrfCacheLocation() const; bool hasDefaultGeoPointTexture() const; - std::string_view defaultGeoPointTexture() const; + std::filesystem::path defaultGeoPointTexture() const; protected: void internalInitialize(const ghoul::Dictionary&) override; diff --git a/modules/globebrowsing/src/geojson/geojsoncomponent.cpp b/modules/globebrowsing/src/geojson/geojsoncomponent.cpp index 5469b17978..ce525284fd 100644 --- a/modules/globebrowsing/src/geojson/geojsoncomponent.cpp +++ b/modules/globebrowsing/src/geojson/geojsoncomponent.cpp @@ -587,7 +587,7 @@ void GeoJsonComponent::update() { } void GeoJsonComponent::readFile() { - std::ifstream file(_geoJsonFile); + std::ifstream file = std::ifstream(_geoJsonFile); if (!file.good()) { LERROR(std::format("Failed to open GeoJSON file: {}", _geoJsonFile.value())); @@ -601,6 +601,14 @@ void GeoJsonComponent::readFile() { std::istreambuf_iterator() ); + // For the loading, we want to assume that the current working directory is where the + // GeoJSON file is located + const std::filesystem::path cwd = std::filesystem::current_path(); + std::filesystem::path jsonDir = + std::filesystem::path(_geoJsonFile.value()).parent_path(); + std::filesystem::current_path(jsonDir); + defer { std::filesystem::current_path(cwd); }; + // Parse GeoJSON string into GeoJSON objects try { const geos::io::GeoJSONReader reader; diff --git a/modules/globebrowsing/src/geojson/geojsonproperties.cpp b/modules/globebrowsing/src/geojson/geojsonproperties.cpp index 6d41ea216f..760c18b943 100644 --- a/modules/globebrowsing/src/geojson/geojsonproperties.cpp +++ b/modules/globebrowsing/src/geojson/geojsonproperties.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -527,7 +528,8 @@ GeoJsonOverrideProperties propsFromGeoJson(const geos::io::GeoJSONFeature& featu result.pointSize = static_cast(value.getNumber()); } else if (keyMatches(key, propertykeys::Texture, PointTextureInfo)) { - result.pointTexture = value.getString(); + std::string texture = value.getString(); + result.pointTexture = absPath(texture); } else if (keyMatches(key, propertykeys::PointTextureAnchor, PointAnchorOptionInfo)) { @@ -628,8 +630,8 @@ float PropertySet::pointSize() const { return overrideValues.pointSize.value_or(defaultValues.pointSize); } -std::string PropertySet::pointTexture() const { - return overrideValues.pointTexture.value_or(defaultValues.pointTexture); +std::filesystem::path PropertySet::pointTexture() const { + return overrideValues.pointTexture.value_or(defaultValues.pointTexture.value()); } GeoJsonProperties::PointTextureAnchor PropertySet::pointTextureAnchor() const { diff --git a/modules/globebrowsing/src/geojson/geojsonproperties.h b/modules/globebrowsing/src/geojson/geojsonproperties.h index c66cabe201..98cfb6f25a 100644 --- a/modules/globebrowsing/src/geojson/geojsonproperties.h +++ b/modules/globebrowsing/src/geojson/geojsonproperties.h @@ -107,7 +107,7 @@ struct GeoJsonOverrideProperties { std::optional lineWidth; std::optional pointSize; - std::optional pointTexture; + std::optional pointTexture; std::optional pointTextureAnchor; std::optional extrude; @@ -135,7 +135,7 @@ struct PropertySet { float lineWidth() const; float pointSize() const; - std::string pointTexture() const; + std::filesystem::path pointTexture() const; GeoJsonProperties::PointTextureAnchor pointTextureAnchor() const; bool extrude() const; diff --git a/modules/globebrowsing/src/geojson/globegeometryfeature.cpp b/modules/globebrowsing/src/geojson/globegeometryfeature.cpp index 80e4c3b8ab..cfa22849f7 100644 --- a/modules/globebrowsing/src/geojson/globegeometryfeature.cpp +++ b/modules/globebrowsing/src/geojson/globegeometryfeature.cpp @@ -115,7 +115,7 @@ bool GlobeGeometryFeature::useHeightMap() const { } void GlobeGeometryFeature::updateTexture(bool isInitializeStep) { - std::string texture; + std::filesystem::path texture; GlobeBrowsingModule* m = global::moduleEngine->module(); if (!isInitializeStep && _properties.hasOverrideTexture()) { @@ -144,15 +144,14 @@ void GlobeGeometryFeature::updateTexture(bool isInitializeStep) { _pointTexture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge); } - std::filesystem::path texturePath = absPath(texture); - if (std::filesystem::is_regular_file(texturePath)) { + if (std::filesystem::is_regular_file(texture)) { _hasTexture = true; _pointTexture->loadFromFile(texture); _pointTexture->uploadToGpu(); } else { LERROR(std::format( - "Trying to use texture file that does not exist: {}", texturePath + "Trying to use texture file that does not exist: {}", texture )); } } diff --git a/src/rendering/texturecomponent.cpp b/src/rendering/texturecomponent.cpp index 46f27a46f3..6f80abd8b0 100644 --- a/src/rendering/texturecomponent.cpp +++ b/src/rendering/texturecomponent.cpp @@ -94,18 +94,12 @@ void TextureComponent::loadFromFile(const std::filesystem::path& path) { using namespace ghoul::io; using namespace ghoul::opengl; - std::filesystem::path absolutePath = absPath(path); + std::unique_ptr tex = TextureReader::ref().loadTexture(path, _nDimensions); + if (tex) { + LDEBUG(std::format("Loaded texture from '{}'", path)); + _texture = std::move(tex); - std::unique_ptr texture = TextureReader::ref().loadTexture( - absolutePath, - _nDimensions - ); - - if (texture) { - LDEBUG(std::format("Loaded texture from '{}'", absolutePath)); - _texture = std::move(texture); - - _textureFile = std::make_unique(absolutePath); + _textureFile = std::make_unique(path); if (_shouldWatchFile) { _textureFile->setCallback([this]() { _fileIsDirty = true; }); }