diff --git a/CHANGES.md b/CHANGES.md index ed90a6f69..a7a541de2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ### ? - ? ##### Breaking Changes :mega: + - Renamed `CesiumITwinClient::Connection::getAccessToken` to `CesiumITwinClient::Connection::getAuthenticationToken`. - Renamed `CesiumITwinClient::Connection::setAccessToken` to `CesiumITwinClient::Connection::setAuthenticationToken`. @@ -13,6 +14,7 @@ - Added support for the [iTwin Geospatial Features API](https://developer.bentley.com/apis/geospatial-features/overview/). - Added `CesiumITwinClient::Connection::geospatialFeatureCollections` to query for all feature collections within an iTwin. - Added `CesiumITwinClient::Connection::geospatialFeatures` to query features within a feature collection. +- Added `CesiumITwinClient::ITwinGeospatialFeaturesRasterOverlay` for displaying Geospatial Features loaded from iTwin as a raster overlay. ##### Fixes :wrench: diff --git a/CesiumITwinClient/CMakeLists.txt b/CesiumITwinClient/CMakeLists.txt index 76f85801d..da269f780 100644 --- a/CesiumITwinClient/CMakeLists.txt +++ b/CesiumITwinClient/CMakeLists.txt @@ -44,6 +44,7 @@ target_link_libraries(CesiumITwinClient CesiumClientCommon CesiumGeometry CesiumGeospatial + CesiumRasterOverlays CesiumVectorData PRIVATE modp_b64::modp_b64 diff --git a/CesiumITwinClient/include/CesiumITwinClient/ITwinGeospatialFeaturesRasterOverlay.h b/CesiumITwinClient/include/CesiumITwinClient/ITwinGeospatialFeaturesRasterOverlay.h new file mode 100644 index 000000000..c53c8297c --- /dev/null +++ b/CesiumITwinClient/include/CesiumITwinClient/ITwinGeospatialFeaturesRasterOverlay.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace CesiumITwinClient { + +/** + * @brief A raster overlay made from rasterizing a \ref + * CesiumVectorData::GeoJsonDocument. + */ +class CESIUMITWINCLIENT_API ITwinGeospatialFeaturesRasterOverlay final + : public CesiumRasterOverlays::RasterOverlay { + +public: + /** + * @brief Creates a new ITwinGeospatialFeaturesRasterOverlay. + * + * @param name The user-given name of this polygon layer. + * @param iTwinId The ID of the iTwin to obtain the features from. + * @param collectionId The ID of the Geospatial Features Collection to obtain + * the features from. + * @param pConnection The connection to the iTwin API to use. + * @param geoJsonOptions Options to configure the GeoJSON overlay. + * @param overlayOptions Options to use for this RasterOverlay. + */ + ITwinGeospatialFeaturesRasterOverlay( + const std::string& name, + const std::string& iTwinId, + const std::string& collectionId, + const CesiumUtility::IntrusivePointer& pConnection, + const CesiumRasterOverlays::GeoJsonDocumentRasterOverlayOptions& + geoJsonOptions, + const CesiumRasterOverlays::RasterOverlayOptions& overlayOptions = {}); + virtual ~ITwinGeospatialFeaturesRasterOverlay() override; + + virtual CesiumAsync::Future createTileProvider( + const CesiumAsync::AsyncSystem& asyncSystem, + const std::shared_ptr& pAssetAccessor, + const std::shared_ptr& pCreditSystem, + const std::shared_ptr< + CesiumRasterOverlays::IPrepareRasterOverlayRendererResources>& + pPrepareRendererResources, + const std::shared_ptr& pLogger, + CesiumUtility::IntrusivePointer pOwner) + const override; + +private: + std::string _iTwinId; + std::string _collectionId; + CesiumUtility::IntrusivePointer _pConnection; + CesiumRasterOverlays::GeoJsonDocumentRasterOverlayOptions _options; +}; +} // namespace CesiumITwinClient \ No newline at end of file diff --git a/CesiumITwinClient/include/CesiumITwinClient/PagedList.h b/CesiumITwinClient/include/CesiumITwinClient/PagedList.h index dccb20ee9..aed8991a9 100644 --- a/CesiumITwinClient/include/CesiumITwinClient/PagedList.h +++ b/CesiumITwinClient/include/CesiumITwinClient/PagedList.h @@ -152,7 +152,49 @@ template class PagedList { return _operation(connection, *this->_prevUrl); } + /** + * @brief Returns all items in this page as well as all subsequent pages. + * + * This does not return items on previous pages, so call this on the first + * page if you want all results. + * + * @param asyncSystem The `AsyncSystem` to use. + * @param pConnection The `Connection` to use to fetch the next pages of + * results, if any. + */ + CesiumAsync::Future>> allAfter( + const CesiumAsync::AsyncSystem& asyncSystem, + CesiumUtility::IntrusivePointer& pConnection) { + return this->allAfter(asyncSystem, pConnection, std::vector()); + } + private: + CesiumAsync::Future>> allAfter( + const CesiumAsync::AsyncSystem& asyncSystem, + CesiumUtility::IntrusivePointer& pConnection, + std::vector&& results) { + results.insert(results.end(), this->_items.begin(), this->_items.end()); + if (!this->_nextUrl) { + return asyncSystem.createResolvedFuture( + CesiumUtility::Result>(std::move(results))); + } + + return this->_operation(pConnection, *this->_nextUrl) + .thenImmediately( + [asyncSystem, pConnection, results = std::move(results)]( + CesiumUtility::Result>&& result) mutable { + if (!result.value) { + return asyncSystem.createResolvedFuture( + CesiumUtility::Result>(result.errors)); + } + + return result.value->allAfter( + asyncSystem, + pConnection, + std::move(results)); + }); + } + PageOperation _operation; std::vector _items; std::optional _selfUrl = std::nullopt; diff --git a/CesiumITwinClient/src/ITwinGeospatialFeaturesRasterOverlay.cpp b/CesiumITwinClient/src/ITwinGeospatialFeaturesRasterOverlay.cpp new file mode 100644 index 000000000..ec9e9af5e --- /dev/null +++ b/CesiumITwinClient/src/ITwinGeospatialFeaturesRasterOverlay.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace CesiumGeometry; +using namespace CesiumGeospatial; +using namespace CesiumRasterOverlays; +using namespace CesiumUtility; +using namespace CesiumVectorData; + +namespace CesiumITwinClient { + +ITwinGeospatialFeaturesRasterOverlay::ITwinGeospatialFeaturesRasterOverlay( + const std::string& name, + const std::string& iTwinId, + const std::string& collectionId, + const CesiumUtility::IntrusivePointer& pConnection, + const CesiumRasterOverlays::GeoJsonDocumentRasterOverlayOptions& + geoJsonOptions, + const CesiumRasterOverlays::RasterOverlayOptions& overlayOptions) + : RasterOverlay(name, overlayOptions), + _iTwinId(iTwinId), + _collectionId(collectionId), + _pConnection(pConnection), + _options(geoJsonOptions) {} + +ITwinGeospatialFeaturesRasterOverlay::~ITwinGeospatialFeaturesRasterOverlay() = + default; + +CesiumAsync::Future +ITwinGeospatialFeaturesRasterOverlay::createTileProvider( + const CesiumAsync::AsyncSystem& asyncSystem, + const std::shared_ptr& pAssetAccessor, + const std::shared_ptr& pCreditSystem, + const std::shared_ptr& + pPrepareRendererResources, + const std::shared_ptr& pLogger, + CesiumUtility::IntrusivePointer pOwner) const { + + pOwner = pOwner ? pOwner : this; + + return this->_pConnection + ->geospatialFeatures(this->_iTwinId, this->_collectionId) + .thenInWorkerThread( + [asyncSystem, pConnection = this->_pConnection]( + Result>&& result) mutable { + if (!result.value) { + return asyncSystem.createResolvedFuture( + Result>(result.errors)); + } + + return result.value->allAfter(asyncSystem, pConnection); + }) + .thenInWorkerThread( + [asyncSystem, + name = this->getName(), + vectorOptions = this->_options, + options = this->getOptions(), + pAssetAccessor, + pCreditSystem, + pPrepareRendererResources, + pLogger, + pOwner](Result>&& result) + -> CesiumAsync::Future { + if (!result.value) { + return asyncSystem.createResolvedFuture< + RasterOverlay::CreateTileProviderResult>( + nonstd::make_unexpected(RasterOverlayLoadFailureDetails{ + RasterOverlayLoadType::CesiumIon, + nullptr, + fmt::format( + "Errors while loading geospatial features: {}", + CesiumUtility::joinToString( + result.errors.errors, + ", "))})); + } + + std::vector objects; + objects.reserve(result.value->size()); + + for (GeoJsonFeature& feature : *result.value) { + objects.emplace_back(std::move(feature)); + } + + std::shared_ptr pDocument = + std::make_shared( + GeoJsonObject{GeoJsonFeatureCollection{ + std::move(objects), + std::nullopt, + {}, + std::nullopt}}, + std::vector{}); + GeoJsonDocumentRasterOverlay geoJsonOverlay( + name, + std::move(pDocument), + vectorOptions, + options); + + return geoJsonOverlay.createTileProvider( + asyncSystem, + pAssetAccessor, + pCreditSystem, + pPrepareRendererResources, + pLogger, + pOwner); + }); +} + +} // namespace CesiumITwinClient \ No newline at end of file