From 34cff7142698e52017296d1156c2d48e3b45d8f8 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Tue, 19 Nov 2024 21:47:50 +1100 Subject: [PATCH] Add ITilesetHeightQuery. --- .../EllipsoidTilesetLoader.h | 9 ++++- .../TilesetContentLoader.h | 39 +++++++++++++++++++ .../src/EllipsoidTilesetLoader.cpp | 17 ++++++++ Cesium3DTilesSelection/src/Tileset.cpp | 1 + .../src/TilesetHeightQuery.cpp | 27 +++++++++++++ .../src/TilesetHeightQuery.h | 4 ++ 6 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/EllipsoidTilesetLoader.h b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/EllipsoidTilesetLoader.h index 9f7e2231e..5e6798108 100644 --- a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/EllipsoidTilesetLoader.h +++ b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/EllipsoidTilesetLoader.h @@ -8,7 +8,8 @@ namespace Cesium3DTilesSelection { * @brief A loader that will generate a tileset by tesselating the surface of an * ellipsoid, producing a simple globe tileset without any terrain features. */ -class EllipsoidTilesetLoader : public TilesetContentLoader { +class EllipsoidTilesetLoader : public TilesetContentLoader, + public ITilesetHeightQuery { public: /** * @brief Constructs a new instance. @@ -35,6 +36,12 @@ class EllipsoidTilesetLoader : public TilesetContentLoader { const CesiumGeospatial::Ellipsoid& ellipsoid CESIUM_DEFAULT_ELLIPSOID) override; + ITilesetHeightQuery* getHeightQuery() override; + + CesiumAsync::Future queryHeights( + const CesiumAsync::AsyncSystem& asyncSystem, + std::vector&& positions) override; + private: struct Geometry { std::vector indices; diff --git a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetContentLoader.h b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetContentLoader.h index 42de995d1..577555fe4 100644 --- a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetContentLoader.h +++ b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetContentLoader.h @@ -6,6 +6,7 @@ #include "TileLoadResult.h" #include "TilesetOptions.h" +#include #include #include #include @@ -108,6 +109,25 @@ struct CESIUM3DTILESSELECTION_API TileChildrenResult { TileLoadResultState state; }; +/** + * @brief An interface to query heights from a tileset that can do so + * efficiently without necessarily downloading individual tiles. + */ +class CESIUM3DTILESSELECTION_API ITilesetHeightQuery { +public: + /** + * @brief Queries the heights at a list of locations. + * + * @param asyncSystem The async system used to do work in threads. + * @param positions The positions at which to query heights. The height field + * of each {@link Cartographic} is ignored. + * @return A future that will be resolved when the heights have been queried. + */ + virtual CesiumAsync::Future queryHeights( + const CesiumAsync::AsyncSystem& asyncSystem, + std::vector&& positions) = 0; +}; + /** * @brief The loader interface to load the tile content */ @@ -145,5 +165,24 @@ class CESIUM3DTILESSELECTION_API TilesetContentLoader { const Tile& tile, const CesiumGeospatial::Ellipsoid& ellipsoid CESIUM_DEFAULT_ELLIPSOID) = 0; + + /** + * @brief Gets an interface that can be used to efficiently query heights from + * this tileset. + * + * Some loaders may be able to query heights very efficiently by using a web + * service or by using an analytical model, e.g., when the "terrain" is a + * simple ellipsoid. + * + * For loaders that have no particular way to query heights, this method will + * return `nullptr`, signaling that heights should be computed by downloading + * and sampling individual tiles. + * + * @return The interface that can be used to efficiently query heights from + * this loader, or `nullptr` if this loader has no particular way to do that. + * The returned instance must have a lifetime that is at least as long as the + * loader itself. + */ + virtual ITilesetHeightQuery* getHeightQuery() { return nullptr; } }; } // namespace Cesium3DTilesSelection diff --git a/Cesium3DTilesSelection/src/EllipsoidTilesetLoader.cpp b/Cesium3DTilesSelection/src/EllipsoidTilesetLoader.cpp index c15a35f56..f0d3ad064 100644 --- a/Cesium3DTilesSelection/src/EllipsoidTilesetLoader.cpp +++ b/Cesium3DTilesSelection/src/EllipsoidTilesetLoader.cpp @@ -89,6 +89,23 @@ TileChildrenResult EllipsoidTilesetLoader::createTileChildren( return TileChildrenResult{{}, TileLoadResultState::Failed}; } +ITilesetHeightQuery* EllipsoidTilesetLoader::getHeightQuery() { return this; } + +CesiumAsync::Future EllipsoidTilesetLoader::queryHeights( + const CesiumAsync::AsyncSystem& asyncSystem, + std::vector&& positions) { + SampleHeightResult result; + + result.positions = std::move(positions); + result.sampleSuccess.resize(result.positions.size(), true); + + for (Cartographic& position : result.positions) { + position.height = 0.0; + } + + return asyncSystem.createResolvedFuture(std::move(result)); +} + void EllipsoidTilesetLoader::createChildTile( const Tile& parent, std::vector& children, diff --git a/Cesium3DTilesSelection/src/Tileset.cpp b/Cesium3DTilesSelection/src/Tileset.cpp index 0b7df6cd0..fd7165c9e 100644 --- a/Cesium3DTilesSelection/src/Tileset.cpp +++ b/Cesium3DTilesSelection/src/Tileset.cpp @@ -391,6 +391,7 @@ Tileset::updateView(const std::vector& frustums, float deltaTime) { } TilesetHeightRequest::processHeightRequests( + this->getAsyncSystem(), *this->_pTilesetContentManager, this->_options, this->_loadedTiles, diff --git a/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp b/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp index ea81dd76a..7e26e577d 100644 --- a/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp +++ b/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp @@ -200,6 +200,7 @@ void TilesetHeightQuery::findCandidateTiles( } /*static*/ void TilesetHeightRequest::processHeightRequests( + const AsyncSystem& asyncSystem, TilesetContentManager& contentManager, const TilesetOptions& options, Tile::LoadedLinkedList& loadedTiles, @@ -214,6 +215,7 @@ void TilesetHeightQuery::findCandidateTiles( for (auto it = heightRequests.begin(); it != heightRequests.end();) { TilesetHeightRequest& request = *it; if (!request.tryCompleteHeightRequest( + asyncSystem, contentManager, options, loadedTiles, @@ -249,10 +251,35 @@ void Cesium3DTilesSelection::TilesetHeightRequest::failHeightRequests( } bool TilesetHeightRequest::tryCompleteHeightRequest( + const AsyncSystem& asyncSystem, TilesetContentManager& contentManager, const TilesetOptions& options, Tile::LoadedLinkedList& loadedTiles, std::set& tileLoadSet) { + // If this TilesetContentLoader supports direct height queries, use that + // instead of downloading tiles. + if (contentManager.getRootTile() && + contentManager.getRootTile()->getLoader()) { + ITilesetHeightQuery* pQuery = + contentManager.getRootTile()->getLoader()->getHeightQuery(); + if (pQuery) { + std::vector positions; + positions.reserve(this->queries.size()); + for (TilesetHeightQuery& query : this->queries) { + positions.emplace_back(query.inputPosition); + } + + pQuery->queryHeights(asyncSystem, std::move(positions)) + .thenImmediately( + [promise = this->promise](SampleHeightResult&& result) { + promise.resolve(std::move(result)); + }); + + return true; + } + } + + // No direct height query possible, so download and sample tiles. bool tileStillNeedsLoading = false; std::vector warnings; for (TilesetHeightQuery& query : this->queries) { diff --git a/Cesium3DTilesSelection/src/TilesetHeightQuery.h b/Cesium3DTilesSelection/src/TilesetHeightQuery.h index e9cbd0ef0..f8e883f1d 100644 --- a/Cesium3DTilesSelection/src/TilesetHeightQuery.h +++ b/Cesium3DTilesSelection/src/TilesetHeightQuery.h @@ -126,6 +126,7 @@ struct TilesetHeightRequest { * @brief Process a given list of height requests. This is called by the {@link Tileset} * in every call to {@link Tileset::updateView}. * + * @param asyncSystem The async system used to do work in threads. * @param contentManager The content manager. * @param options Options associated with the tileset. * @param loadedTiles The linked list of loaded tiles, used to ensure that @@ -137,6 +138,7 @@ struct TilesetHeightRequest { * height requests can complete are added to this vector. */ static void processHeightRequests( + const CesiumAsync::AsyncSystem& asyncSystem, TilesetContentManager& contentManager, const TilesetOptions& options, Tile::LoadedLinkedList& loadedTiles, @@ -160,6 +162,7 @@ struct TilesetHeightRequest { * @brief Tries to complete this height request. Returns false if further data * still needs to be loaded and thus the request cannot yet complete. * + * @param asyncSystem The async system used to do work in threads. * @param contentManager The content manager. * @param options Options associated with the tileset. * @param loadedTiles The linked list of loaded tiles, used to ensure that @@ -169,6 +172,7 @@ struct TilesetHeightRequest { * can complete. */ bool tryCompleteHeightRequest( + const CesiumAsync::AsyncSystem& asyncSystem, TilesetContentManager& contentManager, const TilesetOptions& options, Tile::LoadedLinkedList& loadedTiles,