From e62cfd762d2e710a3484e36fa83684d0b142769d Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 8 Jan 2025 15:55:52 -0500 Subject: [PATCH 01/28] Remove GLM_FORCE_SIZE_T_LENGTH --- CHANGES.md | 4 ++++ Cesium3DTilesContent/src/I3dmToGltfConverter.cpp | 2 +- CesiumGeometry/src/IntersectionTests.cpp | 2 +- CesiumRasterOverlays/src/RasterOverlayUtilities.cpp | 8 +++++--- cmake/macros/configure_cesium_library.cmake | 1 - 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c4fe0089b..c65288505 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ### v0.44.0 - 2025-02-03 +##### Breaking Changes :mega: + +- cesium-native no longer uses the `GLM_FORCE_SIZE_T_LENGTH` option with the `glm` library + ##### Fixes :wrench: - Fixed a crash in `GltfWriter` that would happen when the `EXT_structural_metadata` `schema` property was null. diff --git a/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp b/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp index 3e64bd4b8..12cb2feb8 100644 --- a/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp +++ b/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp @@ -345,7 +345,7 @@ CesiumAsync::Future convertI3dmContent( decodedInstances.positions.begin(), [&parsedContent](auto&& posQuantized) { glm::vec3 position; - for (unsigned j = 0; j < 3; ++j) { + for (glm::length_t j = 0; j < 3; ++j) { position[j] = static_cast( posQuantized[j] / 65535.0 * (*parsedContent.quantizedVolumeScale)[j] + diff --git a/CesiumGeometry/src/IntersectionTests.cpp b/CesiumGeometry/src/IntersectionTests.cpp index ea7fe47f2..9e1f29a1b 100644 --- a/CesiumGeometry/src/IntersectionTests.cpp +++ b/CesiumGeometry/src/IntersectionTests.cpp @@ -199,7 +199,7 @@ std::optional IntersectionTests::rayAABBParametric( double tmin = greatestMin; double tmax = smallestMax; - for (uint32_t i = 0; i < 3; ++i) { + for (glm::length_t i = 0; i < 3; ++i) { if (glm::abs(dir[i]) < Math::Epsilon6) { continue; } else { diff --git a/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp b/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp index 3590e4ac7..1911ebc8f 100644 --- a/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp +++ b/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp @@ -1360,9 +1360,11 @@ void addSkirt( position -= center; for (uint32_t c = 0; c < 3; ++c) { - output.push_back(static_cast(position[c])); - attribute.minimums[c] = glm::min(attribute.minimums[c], position[c]); - attribute.maximums[c] = glm::max(attribute.maximums[c], position[c]); + output.push_back(static_cast(position[glm::length_t(c)])); + attribute.minimums[c] = + glm::min(attribute.minimums[c], position[glm::length_t(c)]); + attribute.maximums[c] = + glm::max(attribute.maximums[c], position[glm::length_t(c)]); } } else { for (uint32_t c = 0; diff --git a/cmake/macros/configure_cesium_library.cmake b/cmake/macros/configure_cesium_library.cmake index a4ed0b3b3..26a8c57e0 100644 --- a/cmake/macros/configure_cesium_library.cmake +++ b/cmake/macros/configure_cesium_library.cmake @@ -22,7 +22,6 @@ function(configure_cesium_library targetName) PUBLIC GLM_FORCE_XYZW_ONLY # Disable .rgba and .stpq to make it easier to view values from debugger GLM_FORCE_EXPLICIT_CTOR # Disallow implicit conversions between dvec3 <-> dvec4, dvec3 <-> fvec3, etc - GLM_FORCE_SIZE_T_LENGTH # Make vec.length() and vec[idx] use size_t instead of int ) endif() From d2789510e601672b87e498672c82afdb0e65a9bc Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 8 Jan 2025 16:23:56 -0500 Subject: [PATCH 02/28] Fix clang errors --- CesiumGltfReader/test/TestGltfReader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CesiumGltfReader/test/TestGltfReader.cpp b/CesiumGltfReader/test/TestGltfReader.cpp index 40c0b3425..845fbde29 100644 --- a/CesiumGltfReader/test/TestGltfReader.cpp +++ b/CesiumGltfReader/test/TestGltfReader.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -118,7 +119,7 @@ T getRange(const CesiumGltf::AccessorView& accessorView) { T max{std::numeric_limits::lowest()}; for (int32_t i = 0; i < accessorView.size(); ++i) { const T& value = accessorView[i]; - for (uint32_t j = 0; j < static_cast(value.length()); ++j) { + for (glm::length_t j = 0; j < value.length(); ++j) { min[j] = glm::min(min[j], value[j]); max[j] = glm::max(max[j], value[j]); } @@ -162,7 +163,7 @@ VertexAttributeRange getVertexAttributeRange(const Model& model) { template bool epsilonCompare(const T& v1, const T& v2, double epsilon) { - for (uint32_t i = 0; i < static_cast(v1.length()); ++i) { + for (glm::length_t i = 0; i < v1.length(); ++i) { if (!CesiumUtility::Math::equalsEpsilon(v1[i], v2[i], epsilon)) { return false; } From 2dcbb94c9c254a1c601b0640cb7220971d2e36e3 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 9 Jan 2025 16:28:39 -0500 Subject: [PATCH 03/28] Allow specifying request headers in TilesetOptions --- .../include/Cesium3DTilesSelection/TilesetOptions.h | 6 ++++++ Cesium3DTilesSelection/src/Tileset.cpp | 2 +- Cesium3DTilesSelection/src/TilesetContentManager.cpp | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h index bb09588cb..15169e5b8 100644 --- a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h +++ b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h @@ -2,6 +2,7 @@ #include "Library.h" +#include #include #include @@ -328,6 +329,11 @@ struct CESIUM3DTILESSELECTION_API TilesetOptions { * If no ellipsoid is set, Ellipsoid::WGS84 will be used by default. */ CesiumGeospatial::Ellipsoid ellipsoid = CesiumGeospatial::Ellipsoid::WGS84; + + /** + * @brief Headers to attach to requests made for this tileset. + */ + std::vector requestHeaders; }; } // namespace Cesium3DTilesSelection diff --git a/Cesium3DTilesSelection/src/Tileset.cpp b/Cesium3DTilesSelection/src/Tileset.cpp index 5d4f052ca..6498b072e 100644 --- a/Cesium3DTilesSelection/src/Tileset.cpp +++ b/Cesium3DTilesSelection/src/Tileset.cpp @@ -54,7 +54,7 @@ Tileset::Tileset( _loadedTiles, externals, options.ellipsoid}, - std::vector{}, + std::vector(options.requestHeaders), std::move(pCustomLoader), std::move(pRootTile)), } {} diff --git a/Cesium3DTilesSelection/src/TilesetContentManager.cpp b/Cesium3DTilesSelection/src/TilesetContentManager.cpp index 9ec3f7aa4..71fe61c38 100644 --- a/Cesium3DTilesSelection/src/TilesetContentManager.cpp +++ b/Cesium3DTilesSelection/src/TilesetContentManager.cpp @@ -685,7 +685,7 @@ TilesetContentManager::TilesetContentManager( RasterOverlayCollection&& overlayCollection, const std::string& url) : _externals{externals}, - _requestHeaders{}, + _requestHeaders{tilesetOptions.requestHeaders}, _pLoader{}, _pRootTile{}, _userCredit( @@ -837,7 +837,7 @@ TilesetContentManager::TilesetContentManager( const std::string& ionAccessToken, const std::string& ionAssetEndpointUrl) : _externals{externals}, - _requestHeaders{}, + _requestHeaders{tilesetOptions.requestHeaders}, _pLoader{}, _pRootTile{}, _userCredit( From d154416227d1f34a6f4a3562fd3312e269b367f8 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 9 Jan 2025 16:30:52 -0500 Subject: [PATCH 04/28] Format, CHANGES --- CHANGES.md | 6 ++++++ Cesium3DTilesSelection/src/Tileset.cpp | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c4fe0089b..3ecdfc46a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change Log +### ? - ? + +##### Additions :tada: + +- Added `requestHeaders` field to `TilesetOptions` to allow per-tileset request headers to be specified. + ### v0.44.0 - 2025-02-03 ##### Fixes :wrench: diff --git a/Cesium3DTilesSelection/src/Tileset.cpp b/Cesium3DTilesSelection/src/Tileset.cpp index 6498b072e..ff9b62ea7 100644 --- a/Cesium3DTilesSelection/src/Tileset.cpp +++ b/Cesium3DTilesSelection/src/Tileset.cpp @@ -54,7 +54,8 @@ Tileset::Tileset( _loadedTiles, externals, options.ellipsoid}, - std::vector(options.requestHeaders), + std::vector( + options.requestHeaders), std::move(pCustomLoader), std::move(pRootTile)), } {} From 302c7e1d5eab28916644dd365b0c8464e223fd75 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 15 Jan 2025 20:16:40 +1100 Subject: [PATCH 05/28] Add initial raster overlay doc. --- doc/{ => topics}/raster-overlays.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) rename doc/{ => topics}/raster-overlays.md (52%) diff --git a/doc/raster-overlays.md b/doc/topics/raster-overlays.md similarity index 52% rename from doc/raster-overlays.md rename to doc/topics/raster-overlays.md index ccfa18669..5bac49529 100644 --- a/doc/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -1,4 +1,21 @@ -# RasterOverlayTileProvider +# Raster Overlays {#raster-overlays} + +Cesium Native's raster overlays are georeferenced 2D images - perhaps consisting of trillions of pixels or more! - that are draped over the top of a [Tileset](\ref Cesium3DTilesSelection::Tileset). A classic example of a raster overlay is a satellite imagery layer. A `Tileset` can have multiple raster overlays, and they're usually alpha-blended together in a layered fashion. They can also be used for more sophisticated effects, however. For example, a raster overlay could represent a "mask" of where on Earth is land versus water, and that mask used in a custom shader or material to render waves in the water-covered areas. + +Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. The following raster overlay types are currently included in Cesium Native: + +* [BingMapsRasterOverlay](\ref CesiumRasterOverlays::BingMapsRasterOverlay) +* [DebugColorizeTilesRasterOverlay](\ref CesiumRasterOverlays::DebugColorizeTilesRasterOverlay) +* [IonRasterOverlay](\ref CesiumRasterOverlays::IonRasterOverlay) +* [WebMapServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapServiceRasterOverlay) +* [WebMapTileServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapTileServiceRasterOverlay) +* [TileMapServiceRasterOverlay](\ref CesiumRasterOverlays::TileMapServiceRasterOverlay) + +To add a raster overlay to a `Tileset`, construct an instance of the appropriate class and add it to the [RasterOverlayCollection](\ref Cesium3DTilesSelection::RasterOverlayCollection) returned by [Tileset::getOverlays](\ref Cesium3DTilesSelection::Tileset::getOverlays). See the reference documentation for each overlay for details about how to configure that overlay type. + +The rest of this document describes how the raster overlay system is implemented. + +## RasterOverlayTileProvider Loads or creates a `RasterOverlayTile` to cover a given geometry tile. From 88c17a5666a6eabafe5b41b8e890520d4fd12879 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 15 Jan 2025 21:15:38 +1100 Subject: [PATCH 06/28] Doc creating a raster overlay. --- .../RasterOverlayTileProvider.h | 4 ++-- doc/topics/raster-overlays.md | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CesiumRasterOverlays/include/CesiumRasterOverlays/RasterOverlayTileProvider.h b/CesiumRasterOverlays/include/CesiumRasterOverlays/RasterOverlayTileProvider.h index 202b6b9cc..86b9b1084 100644 --- a/CesiumRasterOverlays/include/CesiumRasterOverlays/RasterOverlayTileProvider.h +++ b/CesiumRasterOverlays/include/CesiumRasterOverlays/RasterOverlayTileProvider.h @@ -28,8 +28,8 @@ struct CESIUMRASTEROVERLAYS_API LoadedRasterOverlayImage { /** * @brief The loaded image. * - * This will be an empty optional if the loading failed. In this case, - * the `errors` vector will contain the corresponding error messages. + * This will be nullptr if the loading failed. In this case, the `errors` + * vector will contain the corresponding error messages. */ CesiumUtility::IntrusivePointer pImage{nullptr}; diff --git a/doc/topics/raster-overlays.md b/doc/topics/raster-overlays.md index 5bac49529..b2b9bca99 100644 --- a/doc/topics/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -2,7 +2,7 @@ Cesium Native's raster overlays are georeferenced 2D images - perhaps consisting of trillions of pixels or more! - that are draped over the top of a [Tileset](\ref Cesium3DTilesSelection::Tileset). A classic example of a raster overlay is a satellite imagery layer. A `Tileset` can have multiple raster overlays, and they're usually alpha-blended together in a layered fashion. They can also be used for more sophisticated effects, however. For example, a raster overlay could represent a "mask" of where on Earth is land versus water, and that mask used in a custom shader or material to render waves in the water-covered areas. -Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. The following raster overlay types are currently included in Cesium Native: +The following raster overlay types are currently included in Cesium Native: * [BingMapsRasterOverlay](\ref CesiumRasterOverlays::BingMapsRasterOverlay) * [DebugColorizeTilesRasterOverlay](\ref CesiumRasterOverlays::DebugColorizeTilesRasterOverlay) @@ -13,10 +13,19 @@ Raster overlays are implemented by deriving from the [RasterOverlay](\ref Cesium To add a raster overlay to a `Tileset`, construct an instance of the appropriate class and add it to the [RasterOverlayCollection](\ref Cesium3DTilesSelection::RasterOverlayCollection) returned by [Tileset::getOverlays](\ref Cesium3DTilesSelection::Tileset::getOverlays). See the reference documentation for each overlay for details about how to configure that overlay type. -The rest of this document describes how the raster overlay system is implemented. +## Implementing a new RasterOverlay {#implementing-a-raster-overlay} + +Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. `RasterOverlay` has just a single pure-virtual method that must be implemented: [createTileProvider](\ref CesiumRasterOverlays::RasterOverlay::createTileProvider). This method [asynchronously](#async-system) produces an instance of a class derived from [RasterOverlayTileProvider](\ref CesiumRasterOverlays::RasterOverlayTileProvider). + +A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection) and a rectangle that it covers, expressed in that projection. + +Deriving a class from `RasterOverlayTileProvider`, in turn, requires implementing one more pure-virtual method: [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage). This class is passed an instance of [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) and is expected to asynchronously produce a [LoadedRasterOverlayImage](\ref CesiumRasterOverlays::LoadedRasterOverlayImage), containing the actual image data plus details... ## RasterOverlayTileProvider + +The job of a `RasterOverlayTileProvider` is to create `RasterOverlayTile` instances on demand to cover each geometry tile. + Loads or creates a `RasterOverlayTile` to cover a given geometry tile. The rest of the 3D Tiles engine calls `getTile`, giving it the exact rectangle that the returned tile must cover. The tile provider has a `Projection`, and the provided rectangle is expressed in that projection. From de9a48d60d9b4baed7747582544e22829597b387 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 15 Jan 2025 22:49:50 +1100 Subject: [PATCH 07/28] More raster overlay implementation docs. --- .../test/ExamplesRasterOverlays.cpp | 67 +++++++++++++++++++ doc/topics/raster-overlays.md | 23 ++++++- 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp diff --git a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp new file mode 100644 index 000000000..3fc926e37 --- /dev/null +++ b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp @@ -0,0 +1,67 @@ +#include +#include + +#include + +using namespace CesiumRasterOverlays; + +namespace { + +class MyRasterOverlay : public RasterOverlay { +public: + virtual CesiumAsync::Future 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 override; +}; + +//! [use-url-template] +CesiumAsync::Future +MyRasterOverlay::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 { + // Create a new raster overlay with a URL template. + CesiumGeometry::Rectangle coverageRectangle = CesiumGeospatial:: + WebMercatorProjection::computeMaximumProjectedRectangle(); + + UrlTemplateRasterOverlayOptions options{ + .credit = "Copyright (c) Some Amazing Source", + .projection = CesiumGeospatial::WebMercatorProjection(), + .tilingScheme = + CesiumGeometry::QuadtreeTilingScheme(coverageRectangle, 1, 1), + .minimumLevel = 0, + .maximumLevel = 15, + .tileWidth = 256, + .tileHeight = 256, + .coverageRectangle = coverageRectangle, + }; + + CesiumUtility::IntrusivePointer pUrlTemplate = + new UrlTemplateRasterOverlay( + this->getName(), + "https://example.com/{z}/{x}/{y}.png", + {}, + options); + + // Get that raster overlay's tile provider. + return pUrlTemplate->createTileProvider( + asyncSystem, + pAssetAccessor, + pCreditSystem, + pPrepareRendererResources, + pLogger, + this); +} +//! [use-url-template] + +} // namespace diff --git a/doc/topics/raster-overlays.md b/doc/topics/raster-overlays.md index b2b9bca99..26d54e72e 100644 --- a/doc/topics/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -10,6 +10,7 @@ The following raster overlay types are currently included in Cesium Native: * [WebMapServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapServiceRasterOverlay) * [WebMapTileServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapTileServiceRasterOverlay) * [TileMapServiceRasterOverlay](\ref CesiumRasterOverlays::TileMapServiceRasterOverlay) +* [UrlTemplateRasterOverlay](\ref CesiumRasterOverlays::UrlTemplateRasterOverlay) To add a raster overlay to a `Tileset`, construct an instance of the appropriate class and add it to the [RasterOverlayCollection](\ref Cesium3DTilesSelection::RasterOverlayCollection) returned by [Tileset::getOverlays](\ref Cesium3DTilesSelection::Tileset::getOverlays). See the reference documentation for each overlay for details about how to configure that overlay type. @@ -17,12 +18,28 @@ To add a raster overlay to a `Tileset`, construct an instance of the appropriate Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. `RasterOverlay` has just a single pure-virtual method that must be implemented: [createTileProvider](\ref CesiumRasterOverlays::RasterOverlay::createTileProvider). This method [asynchronously](#async-system) produces an instance of a class derived from [RasterOverlayTileProvider](\ref CesiumRasterOverlays::RasterOverlayTileProvider). -A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection) and a rectangle that it covers, expressed in that projection. +A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection) and a rectangle that the raster overlay covers, expressed in the coordinates of that map projection. -Deriving a class from `RasterOverlayTileProvider`, in turn, requires implementing one more pure-virtual method: [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage). This class is passed an instance of [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) and is expected to asynchronously produce a [LoadedRasterOverlayImage](\ref CesiumRasterOverlays::LoadedRasterOverlayImage), containing the actual image data plus details... +While it's possible to derive a class from `RasterOverlayTileProvider` directly and implement the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method, there are two shortcuts available that often save a lot of implementation effort. -## RasterOverlayTileProvider +In the very common scenario where a raster overlay source is organized into a quadtree of tiles, and each tile can be downloaded from a web URL, we can implement `createTileProvider` to construct an instance of [UrlTemplateRasterOverlay](\ref CesiumRasterOverlays::UrlTemplateRasterOverlay) with the appropriate templatized URL and then call its `createTileProvider`: + +\snippet{trimleft} ExamplesRasterOverlays.cpp use-url-template + +If we need a little more control, or if the raster overlay images are not downloaded from web URLs, then we can derive a new class from [QuadtreeRasterOverlayTileProvider](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider) and create and return an instance of it from `createTileProvider`. Deriving from `QuadtreeRasterOverlayTileProvider` requires implementing the [loadQuadtreeTileImage](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider::loadQuadtreeTileImage) method, which is given a quadtree tile ID (level, x, and y) and must asynchronously return the image for that quadtree tile. `QuadtreeRasterOverlayTileProvider` will automatically figure out an appropriate quadtree level to use for ther raster overlay tile attached to a given geometry tile, and it will make multiple calls to `loadQuadtreeTileImage` as necessary to get all of the quadtree images that cover it. In the common case that multiple geometry tiles overlap a single raster overlay quadtree tile, a small cache ensures that raster overlay tiles are not requested more than is necessary. + +If our raster overlay source is not arranged in a quadtree, however, we're left with the final option, which is deriving from `RasterOverlayTileProvider` directly. This requires implementing the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method. When Cesium Native calls this method, it passes a [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) which captures the requirements for the raster overlay tile that covers this geometry tile: + +* [getRectangle](\ref CesiumRasterOverlays::RasterOverlayTile::getRectangle): Describes the minimum rectangle that the provided image must cover, expressed in the provider's [getProjection](\ref CesiumRasterOverlays::RasterOverlayTileProvider::getProjection). The returned image is allowed to be bigger than this, but the extra pixels will be wasted. +* [getTargetScreenPixels](\ref CesiumRasterOverlays::RasterOverlayTile::getTargetScreenPixels): The number of pixels on the screen that the rectangle is expected to map to, just before the geometry tile switches to a higher level-of-detail. This is used to control how detailed the image will be. +In a typical implementation, the target screen pixels is divided by the raster overlay's configured [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) to determine the target number of pixels in the raster overlay image. Then, that number of pixels is rounded up in order to cover the rectangle without resampling and without partial pixels. + +TODO: add a diagram of this + +Old stuff starts here... + +## RasterOverlayTileProvider The job of a `RasterOverlayTileProvider` is to create `RasterOverlayTile` instances on demand to cover each geometry tile. From 72782b25415c2a385dc6e25b609ffb7562abce88 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 15 Jan 2025 13:51:00 -0500 Subject: [PATCH 08/28] Add documentation section to style guide --- doc/topics/style-guide.md | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/doc/topics/style-guide.md b/doc/topics/style-guide.md index 274461c54..9f228bc8c 100644 --- a/doc/topics/style-guide.md +++ b/doc/topics/style-guide.md @@ -147,6 +147,56 @@ Not covered by C++ Core Guidelines. * Test files should be prefixed with `Test`, e.g. `TestModel` instead of `ModelTests`. +## Documentation + +Not covered by C++ Core Guidelines. + +Our documentation is generated by Doxygen before being published [online](https://cesium.com/learn/cesium-native/ref-doc). Therefore, any public API should be documented with Doxygen-compatible comments that use of the following tags (in the order listed): + +- `@brief`: Summarize the purpose of the class, function, etc. +- `@details`: Use for lengthier explanations, after `@brief`. +- `@tparam`: Describe template parameters. +- `@param`: Denote and describe function parameters. +- `@returns`: Describe the return value of a non-`void` function. +- `@exception`: Describe any exceptions that a function throws. + +Additionally, make sure to: + +- Put comments **above** the thing being documented (instead of inline). +- Use the `/** ... */` comment style (instead of `///`). +- Use `\ref` when referencing other classes, functions, etc. in the Cesium Native API. +- Use proper capitalization, grammar, and spelling. +- Use back apostrophes (`) to encapsulate references to types and variable names. +- Use triple back apostrophes (```) to encapsulate any snippets of math or code. + +You can optionally use `@snippet` to include examples of how functions are used in other parts of the code (usually test cases). First, surround the target code with comments containing a descriptive name: + +```cpp +// In TestPlane.cpp... + +TEST_CASE("Plane constructor from normal and distance") { + //! [constructor-normal-distance] + // The plane x=0 + Plane plane(glm::dvec3(1.0, 0.0, 0.0), 0.0); + //! [constructor-normal-distance] +} +``` + +Then reference the file and the name of the snippet: + +```cpp + /** + * @brief Constructs a new plane from a normal and a distance from the origin. + * + * Example: + * @snippet TestPlane.cpp constructor-normal-distance + */ + Plane(const glm::dvec3& normal, double distance); +``` + + +> Although private classes and functions aren't required to have the same level of documentation, it never hurts to add any, especially if they have non-obvious assumptions, scope, or consequences. + ## 🗂️ Other Not covered by C++ Core Guidelines. From 6476e0d2e0fbbf675e02812c594506d5ccf19f9b Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 15 Jan 2025 13:54:29 -0500 Subject: [PATCH 09/28] Pick a fitting emoji :) --- doc/topics/style-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/topics/style-guide.md b/doc/topics/style-guide.md index 9f228bc8c..011575ed3 100644 --- a/doc/topics/style-guide.md +++ b/doc/topics/style-guide.md @@ -147,7 +147,7 @@ Not covered by C++ Core Guidelines. * Test files should be prefixed with `Test`, e.g. `TestModel` instead of `ModelTests`. -## Documentation +## ✏️ Documentation Not covered by C++ Core Guidelines. From 25649cb2dfe1c2e663ed28a9736e70ca8439d6f4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 15 Jan 2025 14:58:38 -0500 Subject: [PATCH 10/28] Review feedback --- doc/topics/style-guide.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/doc/topics/style-guide.md b/doc/topics/style-guide.md index 011575ed3..2363fde29 100644 --- a/doc/topics/style-guide.md +++ b/doc/topics/style-guide.md @@ -151,20 +151,21 @@ Not covered by C++ Core Guidelines. Not covered by C++ Core Guidelines. -Our documentation is generated by Doxygen before being published [online](https://cesium.com/learn/cesium-native/ref-doc). Therefore, any public API should be documented with Doxygen-compatible comments that use of the following tags (in the order listed): +Our documentation is generated by Doxygen before being published [online](https://cesium.com/learn/cesium-native/ref-doc). Therefore, any public API should be documented with Doxygen-compatible comments that make use of the following tags (in the listed order): - `@brief`: Summarize the purpose of the class, function, etc. -- `@details`: Use for lengthier explanations, after `@brief`. +- `@remarks`: Use for any side comments, e.g., how invalid inputs or special cases are handled. +- `@warning`: Convey any warnings about the use of the class, function, etc., e.g., invalid values that make it unsafe. - `@tparam`: Describe template parameters. - `@param`: Denote and describe function parameters. - `@returns`: Describe the return value of a non-`void` function. -- `@exception`: Describe any exceptions that a function throws. +- `@throws`: Describe any exceptions that a function throws. Additionally, make sure to: - Put comments **above** the thing being documented (instead of inline). - Use the `/** ... */` comment style (instead of `///`). -- Use `\ref` when referencing other classes, functions, etc. in the Cesium Native API. +- Use `@ref` when referencing other classes, functions, etc. in the Cesium Native API. - Use proper capitalization, grammar, and spelling. - Use back apostrophes (`) to encapsulate references to types and variable names. - Use triple back apostrophes (```) to encapsulate any snippets of math or code. @@ -185,15 +186,26 @@ TEST_CASE("Plane constructor from normal and distance") { Then reference the file and the name of the snippet: ```cpp - /** - * @brief Constructs a new plane from a normal and a distance from the origin. - * - * Example: - * @snippet TestPlane.cpp constructor-normal-distance - */ - Plane(const glm::dvec3& normal, double distance); +/** + * @brief Constructs a new plane from a normal and a distance from the origin. + * + * Example: + * @snippet TestPlane.cpp constructor-normal-distance + */ +Plane(const glm::dvec3& normal, double distance); ``` +If you find that comments are duplicated across multiple classes, functions, etc., then: + +- Keep the comment on the most sensible instance, e.g., a base class or a pure virtual function. +- Use `@copydoc` for the others. + +For `@copydoc`, keep the comment to one line instead of adding the usual linebreak after `/**`. + +```cpp +/** @copydoc Foo */ +struct Bar { ... } +``` > Although private classes and functions aren't required to have the same level of documentation, it never hurts to add any, especially if they have non-obvious assumptions, scope, or consequences. From 3ab61bc01893649909628f3c5b82f061fad369e4 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 10:56:02 +1100 Subject: [PATCH 11/28] Add raster overlay image, tweak text. --- doc/img/raster-overlay-mapping.svg | 461 +++++++++++++++++++++++++++++ doc/topics/raster-overlays.md | 14 +- 2 files changed, 467 insertions(+), 8 deletions(-) create mode 100644 doc/img/raster-overlay-mapping.svg diff --git a/doc/img/raster-overlay-mapping.svg b/doc/img/raster-overlay-mapping.svg new file mode 100644 index 000000000..67540f38b --- /dev/null +++ b/doc/img/raster-overlay-mapping.svg @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pixels in overlay source + RasterOverlayTile rectangle + Geometry tile + Output image rectangle + + + + + + + diff --git a/doc/topics/raster-overlays.md b/doc/topics/raster-overlays.md index 26d54e72e..752321161 100644 --- a/doc/topics/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -18,7 +18,7 @@ To add a raster overlay to a `Tileset`, construct an instance of the appropriate Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. `RasterOverlay` has just a single pure-virtual method that must be implemented: [createTileProvider](\ref CesiumRasterOverlays::RasterOverlay::createTileProvider). This method [asynchronously](#async-system) produces an instance of a class derived from [RasterOverlayTileProvider](\ref CesiumRasterOverlays::RasterOverlayTileProvider). -A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection) and a rectangle that the raster overlay covers, expressed in the coordinates of that map projection. +A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection), which is used to select or generate appropriate texture coordinates for this raster overlay, and a rectangle that the raster overlay covers, expressed in the coordinates of that map projection. While it's possible to derive a class from `RasterOverlayTileProvider` directly and implement the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method, there are two shortcuts available that often save a lot of implementation effort. @@ -26,18 +26,16 @@ In the very common scenario where a raster overlay source is organized into a qu \snippet{trimleft} ExamplesRasterOverlays.cpp use-url-template -If we need a little more control, or if the raster overlay images are not downloaded from web URLs, then we can derive a new class from [QuadtreeRasterOverlayTileProvider](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider) and create and return an instance of it from `createTileProvider`. Deriving from `QuadtreeRasterOverlayTileProvider` requires implementing the [loadQuadtreeTileImage](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider::loadQuadtreeTileImage) method, which is given a quadtree tile ID (level, x, and y) and must asynchronously return the image for that quadtree tile. `QuadtreeRasterOverlayTileProvider` will automatically figure out an appropriate quadtree level to use for ther raster overlay tile attached to a given geometry tile, and it will make multiple calls to `loadQuadtreeTileImage` as necessary to get all of the quadtree images that cover it. In the common case that multiple geometry tiles overlap a single raster overlay quadtree tile, a small cache ensures that raster overlay tiles are not requested more than is necessary. +If we need a little more control, or if the raster overlay images are not downloaded from web URLs, then we can derive a new class from [QuadtreeRasterOverlayTileProvider](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider) and create and return an instance of it from `createTileProvider`. This requires implementing the [loadQuadtreeTileImage](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider::loadQuadtreeTileImage) method, which is given a quadtree tile ID (level, x, and y) and must asynchronously return the image for that quadtree tile. `QuadtreeRasterOverlayTileProvider` itself will automatically figure out an appropriate quadtree level to use for ther raster overlay tile attached to a given geometry tile, and it will make multiple calls to `loadQuadtreeTileImage` as necessary to get all of the quadtree images that cover it. In the common case that multiple geometry tiles overlap a single raster overlay quadtree tile, a small cache ensures that raster overlay tiles are not requested more than is necessary. If our raster overlay source is not arranged in a quadtree, however, we're left with the final option, which is deriving from `RasterOverlayTileProvider` directly. This requires implementing the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method. When Cesium Native calls this method, it passes a [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) which captures the requirements for the raster overlay tile that covers this geometry tile: -* [getRectangle](\ref CesiumRasterOverlays::RasterOverlayTile::getRectangle): Describes the minimum rectangle that the provided image must cover, expressed in the provider's [getProjection](\ref CesiumRasterOverlays::RasterOverlayTileProvider::getProjection). The returned image is allowed to be bigger than this, but the extra pixels will be wasted. -* [getTargetScreenPixels](\ref CesiumRasterOverlays::RasterOverlayTile::getTargetScreenPixels): The number of pixels on the screen that the rectangle is expected to map to, just before the geometry tile switches to a higher level-of-detail. This is used to control how detailed the image will be. +* [Rectangle](\ref CesiumRasterOverlays::RasterOverlayTile::getRectangle): Describes the minimum rectangle that the provided image must cover, expressed in the provider's [Projection](\ref CesiumRasterOverlays::RasterOverlayTileProvider::getProjection). The returned image is allowed to be bigger than this, but the extra pixels will be wasted. +* [TargetScreenPixels](\ref CesiumRasterOverlays::RasterOverlayTile::getTargetScreenPixels): The number of pixels on the screen that the rectangle is expected to map to, just before the geometry tile switches to a higher level-of-detail. This is used to control how detailed the image will be. -In a typical implementation, the target screen pixels is divided by the raster overlay's configured [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) to determine the target number of pixels in the raster overlay image. Then, that number of pixels is rounded up in order to cover the rectangle without resampling and without partial pixels. +In a typical implementation, the target screen pixels is divided by the raster overlay's configured [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) to determine the target number of pixels in the raster overlay image. Then, pixels are copied into the output image in order to completely fill the rectangle. The output image rectangle is usually larger than the `RasterOverlayTile` rectangle, and the number of pixels is slightly higher than the target number of pixels in the raster overlay image, because both must be rounded up in order to fully include partial pixels. -TODO: add a diagram of this - -Old stuff starts here... +\image html raster-overlay-mapping.svg ## RasterOverlayTileProvider From 64deffc72481149ee8c0f60c2b0a94fe28908cee Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 11:35:29 +1100 Subject: [PATCH 12/28] Separate topic for creating new raster overlay types. --- .../test/ExamplesRasterOverlays.cpp | 2 +- .../implementing-a-new-raster-overlay-type.md | 42 +++++++++++++++++++ doc/topics/raster-overlays.md | 42 +------------------ 3 files changed, 44 insertions(+), 42 deletions(-) create mode 100644 doc/topics/implementing-a-new-raster-overlay-type.md diff --git a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp index 3fc926e37..34b1daa4d 100644 --- a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp +++ b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp @@ -49,7 +49,7 @@ MyRasterOverlay::createTileProvider( CesiumUtility::IntrusivePointer pUrlTemplate = new UrlTemplateRasterOverlay( this->getName(), - "https://example.com/{z}/{x}/{y}.png", + "https://example.com/level-{z}/column-{x}/row-{y}.png", {}, options); diff --git a/doc/topics/implementing-a-new-raster-overlay-type.md b/doc/topics/implementing-a-new-raster-overlay-type.md new file mode 100644 index 000000000..6dbc5cd57 --- /dev/null +++ b/doc/topics/implementing-a-new-raster-overlay-type.md @@ -0,0 +1,42 @@ +# Implementing a new RasterOverlay Type {#implementing-a-new-raster-overlay-type} + +Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. `RasterOverlay` has just a single pure-virtual method that must be implemented: [createTileProvider](\ref CesiumRasterOverlays::RasterOverlay::createTileProvider). This method [asynchronously](#async-system) produces an instance of a class derived from [RasterOverlayTileProvider](\ref CesiumRasterOverlays::RasterOverlayTileProvider). + +A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection), which is used to select or generate appropriate texture coordinates for this raster overlay, and a rectangle that the raster overlay covers, expressed in the coordinates of that map projection. + +While it's possible to derive a class from `RasterOverlayTileProvider` directly and implement the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method, there are two shortcuts available that often save a lot of implementation effort. + +In the very common scenario where a raster overlay source is organized into a quadtree of tiles, and each tile can be downloaded from a web URL, we can implement `createTileProvider` to construct an instance of [UrlTemplateRasterOverlay](\ref CesiumRasterOverlays::UrlTemplateRasterOverlay) with the appropriate templatized URL and then call its `createTileProvider`: + +\snippet{trimleft} ExamplesRasterOverlays.cpp use-url-template + +If we need a little more control, or if the raster overlay images are not downloaded from web URLs, then we can derive a new class from [QuadtreeRasterOverlayTileProvider](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider) and create and return an instance of it from `createTileProvider`. This requires implementing the [loadQuadtreeTileImage](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider::loadQuadtreeTileImage) method, which is given a quadtree tile ID (level, x, and y) and must asynchronously return the image for that quadtree tile. `QuadtreeRasterOverlayTileProvider` itself will automatically figure out an appropriate quadtree level to use for ther raster overlay tile attached to a given geometry tile, and it will make multiple calls to `loadQuadtreeTileImage` as necessary to get all of the quadtree images that cover it. In the common case that multiple geometry tiles overlap a single raster overlay quadtree tile, a small cache ensures that raster overlay tiles are not requested more than is necessary. + +If our raster overlay source is not arranged in a quadtree, however, we're left with the final option, which is deriving from `RasterOverlayTileProvider` directly. This requires implementing the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method. When Cesium Native calls this method, it passes a [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) which captures the requirements for the raster overlay tile that covers this geometry tile: + +* [Rectangle](\ref CesiumRasterOverlays::RasterOverlayTile::getRectangle): Describes the minimum rectangle that the provided image must cover, expressed in the provider's [Projection](\ref CesiumRasterOverlays::RasterOverlayTileProvider::getProjection). The returned image is allowed to be bigger than this, but the extra pixels will be wasted. +* [TargetScreenPixels](\ref CesiumRasterOverlays::RasterOverlayTile::getTargetScreenPixels): The number of pixels on the screen that the rectangle is expected to map to, just before the geometry tile switches to a higher level-of-detail. This is used to control how detailed the image will be. + +In a typical implementation, the target screen pixels is divided by the raster overlay's configured [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) to determine the target number of pixels in the raster overlay image. Then, pixels are copied into the output image in order to completely fill the rectangle. The output image rectangle is usually larger than the `RasterOverlayTile` rectangle, and the number of pixels is slightly higher than the target number of pixels in the raster overlay image, because both must be rounded up in order to fully include partial pixels. + +\image html raster-overlay-mapping.svg + +## RasterOverlayTileProvider + +The job of a `RasterOverlayTileProvider` is to create `RasterOverlayTile` instances on demand to cover each geometry tile. + +Loads or creates a `RasterOverlayTile` to cover a given geometry tile. + +The rest of the 3D Tiles engine calls `getTile`, giving it the exact rectangle that the returned tile must cover. The tile provider has a `Projection`, and the provided rectangle is expressed in that projection. + +`getTile` returns a `RasterOverlayTile`, but does not immediately start loading it. The 3D Tiles engine calls `RasterOverlayTileProvider::loadTile` to kick off the loading process. `getTile` may return nullptr if the provider has no data within the given rectangle. + +While the returned `RasterOverlayTile` is loading, the 3D Tiles engine will use the geometry from the parent geometry tile. The `RasterOverlayTileProvider` doesn't need to concern itself with this at all. It is handled by `RasterMappedTo3DTile`. + +`RasterOverlayTileProvider` also, in general, does not need to do any caching. The 3D Tiles engine will only call `getTile` once per geometry tile. + +`getTile` internally calls the polymorphic `loadTileImage`. Derived `RasterOverlayTileProvider` classes implement this method to kick off a request, if necessary, then decode the result and provide the decoded pixels as a `LoadedRasterOverlayImage`. All the lifecycle management is handled automatically by `RasterOverlayTileProvider`, so that derived classes only need to implement this one async method. + +# QuadtreeRasterOverlayTileProvider + +Derives from `RasterOveralyTileProvider` and provides an implementation for `RasterOverlayTileProvider::loadTileImage`. This implementation looks a bit like the old `mapRasterTilesToGeometryTile`. It figures out which quadtree tiles fall inside the rectangle passed to `loadTileImage`. Then, it starts an async load of each of these tiles and waits for them _all_ to either finish loading or fail to load. For the ones that fail to load, we try a parent tile, which may require more waiting. Eventually we have tiles that cover the entire rectangle, and we can blit them to the output texture. `loadTileImage` is an async method start to finish, so this is straightforward. It doesn't require any tricky lifetime management. diff --git a/doc/topics/raster-overlays.md b/doc/topics/raster-overlays.md index 752321161..badaaf8db 100644 --- a/doc/topics/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -14,45 +14,5 @@ The following raster overlay types are currently included in Cesium Native: To add a raster overlay to a `Tileset`, construct an instance of the appropriate class and add it to the [RasterOverlayCollection](\ref Cesium3DTilesSelection::RasterOverlayCollection) returned by [Tileset::getOverlays](\ref Cesium3DTilesSelection::Tileset::getOverlays). See the reference documentation for each overlay for details about how to configure that overlay type. -## Implementing a new RasterOverlay {#implementing-a-raster-overlay} +* \subpage implementing-a-new-raster-overlay-type - How to implement a new kind of `RasterOverlay`. -Raster overlays are implemented by deriving from the [RasterOverlay](\ref CesiumRasterOverlays::RasterOverlay) abstract base class, so new ones can be easily added even from outside of Cesium Native. `RasterOverlay` has just a single pure-virtual method that must be implemented: [createTileProvider](\ref CesiumRasterOverlays::RasterOverlay::createTileProvider). This method [asynchronously](#async-system) produces an instance of a class derived from [RasterOverlayTileProvider](\ref CesiumRasterOverlays::RasterOverlayTileProvider). - -A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection), which is used to select or generate appropriate texture coordinates for this raster overlay, and a rectangle that the raster overlay covers, expressed in the coordinates of that map projection. - -While it's possible to derive a class from `RasterOverlayTileProvider` directly and implement the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method, there are two shortcuts available that often save a lot of implementation effort. - -In the very common scenario where a raster overlay source is organized into a quadtree of tiles, and each tile can be downloaded from a web URL, we can implement `createTileProvider` to construct an instance of [UrlTemplateRasterOverlay](\ref CesiumRasterOverlays::UrlTemplateRasterOverlay) with the appropriate templatized URL and then call its `createTileProvider`: - -\snippet{trimleft} ExamplesRasterOverlays.cpp use-url-template - -If we need a little more control, or if the raster overlay images are not downloaded from web URLs, then we can derive a new class from [QuadtreeRasterOverlayTileProvider](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider) and create and return an instance of it from `createTileProvider`. This requires implementing the [loadQuadtreeTileImage](\ref CesiumRasterOverlays::QuadtreeRasterOverlayTileProvider::loadQuadtreeTileImage) method, which is given a quadtree tile ID (level, x, and y) and must asynchronously return the image for that quadtree tile. `QuadtreeRasterOverlayTileProvider` itself will automatically figure out an appropriate quadtree level to use for ther raster overlay tile attached to a given geometry tile, and it will make multiple calls to `loadQuadtreeTileImage` as necessary to get all of the quadtree images that cover it. In the common case that multiple geometry tiles overlap a single raster overlay quadtree tile, a small cache ensures that raster overlay tiles are not requested more than is necessary. - -If our raster overlay source is not arranged in a quadtree, however, we're left with the final option, which is deriving from `RasterOverlayTileProvider` directly. This requires implementing the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method. When Cesium Native calls this method, it passes a [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) which captures the requirements for the raster overlay tile that covers this geometry tile: - -* [Rectangle](\ref CesiumRasterOverlays::RasterOverlayTile::getRectangle): Describes the minimum rectangle that the provided image must cover, expressed in the provider's [Projection](\ref CesiumRasterOverlays::RasterOverlayTileProvider::getProjection). The returned image is allowed to be bigger than this, but the extra pixels will be wasted. -* [TargetScreenPixels](\ref CesiumRasterOverlays::RasterOverlayTile::getTargetScreenPixels): The number of pixels on the screen that the rectangle is expected to map to, just before the geometry tile switches to a higher level-of-detail. This is used to control how detailed the image will be. - -In a typical implementation, the target screen pixels is divided by the raster overlay's configured [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) to determine the target number of pixels in the raster overlay image. Then, pixels are copied into the output image in order to completely fill the rectangle. The output image rectangle is usually larger than the `RasterOverlayTile` rectangle, and the number of pixels is slightly higher than the target number of pixels in the raster overlay image, because both must be rounded up in order to fully include partial pixels. - -\image html raster-overlay-mapping.svg - -## RasterOverlayTileProvider - -The job of a `RasterOverlayTileProvider` is to create `RasterOverlayTile` instances on demand to cover each geometry tile. - -Loads or creates a `RasterOverlayTile` to cover a given geometry tile. - -The rest of the 3D Tiles engine calls `getTile`, giving it the exact rectangle that the returned tile must cover. The tile provider has a `Projection`, and the provided rectangle is expressed in that projection. - -`getTile` returns a `RasterOverlayTile`, but does not immediately start loading it. The 3D Tiles engine calls `RasterOverlayTileProvider::loadTile` to kick off the loading process. `getTile` may return nullptr if the provider has no data within the given rectangle. - -While the returned `RasterOverlayTile` is loading, the 3D Tiles engine will use the geometry from the parent geometry tile. The `RasterOverlayTileProvider` doesn't need to concern itself with this at all. It is handled by `RasterMappedTo3DTile`. - -`RasterOverlayTileProvider` also, in general, does not need to do any caching. The 3D Tiles engine will only call `getTile` once per geometry tile. - -`getTile` internally calls the polymorphic `loadTileImage`. Derived `RasterOverlayTileProvider` classes implement this method to kick off a request, if necessary, then decode the result and provide the decoded pixels as a `LoadedRasterOverlayImage`. All the lifecycle management is handled automatically by `RasterOverlayTileProvider`, so that derived classes only need to implement this one async method. - -# QuadtreeRasterOverlayTileProvider - -Derives from `RasterOveralyTileProvider` and provides an implementation for `RasterOverlayTileProvider::loadTileImage`. This implementation looks a bit like the old `mapRasterTilesToGeometryTile`. It figures out which quadtree tiles fall inside the rectangle passed to `loadTileImage`. Then, it starts an async load of each of these tiles and waits for them _all_ to either finish loading or fail to load. For the ones that fail to load, we try a parent tile, which may require more waiting. Eventually we have tiles that cover the entire rectangle, and we can blit them to the output texture. `loadTileImage` is an async method start to finish, so this is straightforward. It doesn't require any tricky lifetime management. From e0b1991b3277368dffc945cd8ed6ac522974182b Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 12:01:05 +1100 Subject: [PATCH 13/28] Outline for raster overlay implementation doc. --- doc/topics/how-raster-overlays-work.md | 13 ++++++++++++ .../implementing-a-new-raster-overlay-type.md | 20 ------------------- doc/topics/raster-overlays.md | 4 +++- 3 files changed, 16 insertions(+), 21 deletions(-) create mode 100644 doc/topics/how-raster-overlays-work.md diff --git a/doc/topics/how-raster-overlays-work.md b/doc/topics/how-raster-overlays-work.md new file mode 100644 index 000000000..66837d82d --- /dev/null +++ b/doc/topics/how-raster-overlays-work.md @@ -0,0 +1,13 @@ +# How Raster Overlays Work {#how-raster-overlays-work} + +This topic explains how Cesium Native's raster overlay system is implemented. + +## Texture Coordinates {#texture-coordinates} + +When rendered, raster overlay images are applied to geometry tiles just like any other texture: they're sampled in a pixel/fragment shader according to texture coordinates associated with every vertex in the geometry. + +## Determining the raster overlay rectangle + +## Target Screen Pixels + +## Missing Tiles and Using Parent Textures diff --git a/doc/topics/implementing-a-new-raster-overlay-type.md b/doc/topics/implementing-a-new-raster-overlay-type.md index 6dbc5cd57..779b0040a 100644 --- a/doc/topics/implementing-a-new-raster-overlay-type.md +++ b/doc/topics/implementing-a-new-raster-overlay-type.md @@ -20,23 +20,3 @@ If our raster overlay source is not arranged in a quadtree, however, we're left In a typical implementation, the target screen pixels is divided by the raster overlay's configured [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) to determine the target number of pixels in the raster overlay image. Then, pixels are copied into the output image in order to completely fill the rectangle. The output image rectangle is usually larger than the `RasterOverlayTile` rectangle, and the number of pixels is slightly higher than the target number of pixels in the raster overlay image, because both must be rounded up in order to fully include partial pixels. \image html raster-overlay-mapping.svg - -## RasterOverlayTileProvider - -The job of a `RasterOverlayTileProvider` is to create `RasterOverlayTile` instances on demand to cover each geometry tile. - -Loads or creates a `RasterOverlayTile` to cover a given geometry tile. - -The rest of the 3D Tiles engine calls `getTile`, giving it the exact rectangle that the returned tile must cover. The tile provider has a `Projection`, and the provided rectangle is expressed in that projection. - -`getTile` returns a `RasterOverlayTile`, but does not immediately start loading it. The 3D Tiles engine calls `RasterOverlayTileProvider::loadTile` to kick off the loading process. `getTile` may return nullptr if the provider has no data within the given rectangle. - -While the returned `RasterOverlayTile` is loading, the 3D Tiles engine will use the geometry from the parent geometry tile. The `RasterOverlayTileProvider` doesn't need to concern itself with this at all. It is handled by `RasterMappedTo3DTile`. - -`RasterOverlayTileProvider` also, in general, does not need to do any caching. The 3D Tiles engine will only call `getTile` once per geometry tile. - -`getTile` internally calls the polymorphic `loadTileImage`. Derived `RasterOverlayTileProvider` classes implement this method to kick off a request, if necessary, then decode the result and provide the decoded pixels as a `LoadedRasterOverlayImage`. All the lifecycle management is handled automatically by `RasterOverlayTileProvider`, so that derived classes only need to implement this one async method. - -# QuadtreeRasterOverlayTileProvider - -Derives from `RasterOveralyTileProvider` and provides an implementation for `RasterOverlayTileProvider::loadTileImage`. This implementation looks a bit like the old `mapRasterTilesToGeometryTile`. It figures out which quadtree tiles fall inside the rectangle passed to `loadTileImage`. Then, it starts an async load of each of these tiles and waits for them _all_ to either finish loading or fail to load. For the ones that fail to load, we try a parent tile, which may require more waiting. Eventually we have tiles that cover the entire rectangle, and we can blit them to the output texture. `loadTileImage` is an async method start to finish, so this is straightforward. It doesn't require any tricky lifetime management. diff --git a/doc/topics/raster-overlays.md b/doc/topics/raster-overlays.md index badaaf8db..0e78c9d7f 100644 --- a/doc/topics/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -14,5 +14,7 @@ The following raster overlay types are currently included in Cesium Native: To add a raster overlay to a `Tileset`, construct an instance of the appropriate class and add it to the [RasterOverlayCollection](\ref Cesium3DTilesSelection::RasterOverlayCollection) returned by [Tileset::getOverlays](\ref Cesium3DTilesSelection::Tileset::getOverlays). See the reference documentation for each overlay for details about how to configure that overlay type. -* \subpage implementing-a-new-raster-overlay-type - How to implement a new kind of `RasterOverlay`. +For more information about `RasterOverlays`, see the following topics: +* \subpage implementing-a-new-raster-overlay-type - How to implement a new kind of `RasterOverlay`. +* \subpage how-raster-overlays-work - How Cesium Native's Raster Overlay system works under-the-hood. From feef2cd0eb162e631e7ddf6c1ae5281c602afab5 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 17:26:18 +1100 Subject: [PATCH 14/28] Doc how raster overlays work. Other tweaks. --- .../src/TilesetContentManager.cpp | 4 +-- CesiumUtility/src/Assert.cpp | 3 +- doc/topics/how-raster-overlays-work.md | 35 +++++++++++++++++-- .../implementing-a-new-raster-overlay-type.md | 3 ++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/Cesium3DTilesSelection/src/TilesetContentManager.cpp b/Cesium3DTilesSelection/src/TilesetContentManager.cpp index 89663c016..d0d932282 100644 --- a/Cesium3DTilesSelection/src/TilesetContentManager.cpp +++ b/Cesium3DTilesSelection/src/TilesetContentManager.cpp @@ -448,8 +448,8 @@ void calcRasterOverlayDetailsInWorkerThread( const TileContentLoadInfo& tileLoadInfo) { CesiumGltf::Model& model = std::get(result.contentKind); - // we will use the fittest bounding volume to calculate raster overlay details - // below + // we will use the best-fitting bounding volume to calculate raster overlay + // details below const BoundingVolume& contentBoundingVolume = getEffectiveContentBoundingVolume( tileLoadInfo.tileBoundingVolume, diff --git a/CesiumUtility/src/Assert.cpp b/CesiumUtility/src/Assert.cpp index 29c208ad1..18034265e 100644 --- a/CesiumUtility/src/Assert.cpp +++ b/CesiumUtility/src/Assert.cpp @@ -1,10 +1,11 @@ - #if defined CESIUM_FORCE_ASSERTIONS && defined NDEBUG #undef NDEBUG #include #define NDEBUG +#include + namespace CesiumUtility { std::int32_t forceAssertFailure() { assert(0 && "Assertion failed"); diff --git a/doc/topics/how-raster-overlays-work.md b/doc/topics/how-raster-overlays-work.md index 66837d82d..5de144cfd 100644 --- a/doc/topics/how-raster-overlays-work.md +++ b/doc/topics/how-raster-overlays-work.md @@ -2,12 +2,41 @@ This topic explains how Cesium Native's raster overlay system is implemented. +> [!note] +> In the explanation below, we distinguish between a "geometry tile", which is an instance of [Tile](\ref Cesium3DTilesSelection::Tile) from a 3D Tiles or quantized-mesh-1.0 tileset, and a "raster overlay tile" which is an instance of [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) that represents a raster overlay image applied to a geometry tile. While a `Tile` may have textures, too, a `RasterOverlayTile` never has geometry. + +## Determining the raster overlay rectangle + +In most cases, a `RasterOverlayTile` is mapped to a `Tile` when that geometry tile first transitions out of the _Unloaded_ state and starts its loading process. This happens with a call to the [RastedMappedTo3DTile::mapOverlayToTile](\ref Cesium3DTilesSelection::RasterMappedTo3DTile::mapOverlayToTile) static method. The first job of this method is to determine a bounding rectangle for this geometry tile, expressed in the coordinates and projection of the raster overlay. + +If the renderable content for this tile were already loaded, this process would be simple. We would simply compute the projected coordinates of each vertex in the tile's model, and form a bounding rectangle from the minimum and maximum of these. Unfortunately, waiting until the model vertices are available is inefficient. It requires that we completely download, parse, and decode the tile's model before we can even start the requests for the raster overlay images. Ideally, we would be able to request the tile content and the raster overlay images simultaneously, which would significantly reduce latency. + +To that end, we try to determine an accurate bounding rectangle for the geometry tile from the geometry tile's 3D bounding volume whenever we can. It's extremely important that the bounding rectangle be accurate, though. If we estimate a significantly larger rectangle than the geometry tile actually covers, we'll end up unnecessarily loading more raster overlay data than we actually need, eliminating the efficiency advantage we were hoping to gain. So `mapOverlayToTile` will only map actual raster overlay tiles to unloaded geometry tiles when it is sure it can determine an accurate rectangle. In all other cases, it instead adds a "placeholder" raster overlay tile, which will be turned into a real one later, after the geometry tile is loaded. + +The current implementation can only determine an accurate rectangle for tiles with a [region](https://github.com/CesiumGS/3d-tiles/tree/main/specification#core-region) bounding volume. The reasoning is as follows: + +1. Cesium Native currently only supports raster overlays with a [Geographic](\ref CesiumGeospatial::GeographicProjection) or [Web Mercator](\ref CesiumGeospatial::WebMercatorProjection) projection. +2. Both of these projections are aligned to longitude/latitude bounds. A constant X or Y coordinate in either projection corresponds to a constant longitude or latitude. +3. Therefore, as long as the 3D bounding region is accurate, the 2D bounding rectangle will be as well. + +For all other bounding volumes, while we could attempt to estimate a bounding rectangle from the bounding volume, we would not have high confidence in the estimate. So, instead, we accept the latency and load the geometry tile first. + ## Texture Coordinates {#texture-coordinates} -When rendered, raster overlay images are applied to geometry tiles just like any other texture: they're sampled in a pixel/fragment shader according to texture coordinates associated with every vertex in the geometry. +When rendered, raster overlay images are applied to geometry tiles just like any other texture: they're sampled in a pixel/fragment shader according to texture coordinates associated with every vertex in the geometry. Cesium Native generates one or more sets of overlay texture coordinates for every geometry tile that has raster overlays. -## Determining the raster overlay rectangle +In fact, it generates a set of texture coordinate for each unique projection used by raster overlays. We need texture coordinates per projection because the raster overlay texture sampling also serves to unproject the overlay images from the raster overlay's projected coordinate system to the 3D world coordinates. + +This unprojection is not perfect. Texture coordinates are defined at vertices and are linearly interpolated over triangles. This linear interpolation may be noticeably different from the result we would get if we actually computed the projected coordinates at a given world position within the triangle. A more correct solution would be to evaluate the projection in the shader or material. This would be less performant, however, and most map projections are difficult to evaluate accurately in the single-precision floating point arithmetic that is commonly available on GPUs. Most importantly, unprojecting with texture coordinates and sampling is good enough in all but pathological cases. Geospatial models tend to have vertices that are close enough together to avoid noticeable artifacts caused by inaccurate unprojection in between them. + +Texture coordinates are computed using [RasterOverlayUtilities::createRasterOverlayTextureCoordinates](\ref CesiumRasterOverlays::RasterOverlayUtilities::createRasterOverlayTextureCoordinates), which is called from a worker thread during the geometry tile loading process. ## Target Screen Pixels -## Missing Tiles and Using Parent Textures +The pixel resolution used for the raster overlay texture applied to a given geometry tile is controlled by the overlay tile's "target screen pixels". This is a parameter that Cesium Native passes to the `RasterOverlayTileProvider` when it requests an overlay image. Cesium Native computes this quantity by calling [RasterOverlayUtilities::computeDesiredScreenPixels](\ref CesiumRasterOverlays::RasterOverlayUtilities::computeDesiredScreenPixels). The return value is a 2D vector, with the X and Y components representing the target number of pixels in the projected X and Y directions, respectively. See the reference documentation for that method, as well as the comments in the implementation, for further details. + +We can think of this as the maximum pixel size of the geometry tile on the screen, just before moving a little closer to it would cause a switch to a higher level-of-detail. This is a function of the geometry tile's bounding box, as well as its geometric error and the tileset's maximum screen-space error. For leaf tiles with a geometric error of zero, we compute this quantity as if the tile had a geometric error that is half of its parent's. + +The "Target Screen Pixels" is not usually used directly as the size of the raster overlay texture, however, but it is used to compute it. First, it is divided by the [maximumScreenSpaceError](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumScreenSpaceError) configured on the `RasterOverlay`. Then, it is clamped to the [maximumTextureSize](\ref CesiumRasterOverlays::RasterOverlayOptions::maximumTextureSize). This formulation makes raster overlay detail shown on the screen a function of its own maximum screen-space error property, and largely independent of the maximum screen-space error configured on the `Tileset`. We can cut the geometry detail in half by changing [TilesetOptions::maximumScreenSpaceError](\ref Cesium3DTilesSelection::TilesetOptions::maximumScreenSpaceError) from 16.0 to 32.0, and this will not affect the sharpness of the raster overlays. + +This formulation does, however, mean that changing `TilesetOptions::maximumScreenSpaceError` requires remapping raster overlaps to geometry tiles, which is usually accomplished by reloading the `Tileset` entirely. diff --git a/doc/topics/implementing-a-new-raster-overlay-type.md b/doc/topics/implementing-a-new-raster-overlay-type.md index 779b0040a..995be5750 100644 --- a/doc/topics/implementing-a-new-raster-overlay-type.md +++ b/doc/topics/implementing-a-new-raster-overlay-type.md @@ -4,6 +4,9 @@ Raster overlays are implemented by deriving from the [RasterOverlay](\ref Cesium A `RasterOverlayTileProvider` has a particular [Projection](\ref CesiumGeospatial::Projection), which is used to select or generate appropriate texture coordinates for this raster overlay, and a rectangle that the raster overlay covers, expressed in the coordinates of that map projection. +> [!note] +> In the explanation below, we distinguish between a "geometry tile", which is an instance of [Tile](\ref Cesium3DTilesSelection::Tile) from a 3D Tiles or quantized-mesh-1.0 tileset, and a "raster overlay tile" which is an instance of [RasterOverlayTile](\ref CesiumRasterOverlays::RasterOverlayTile) that represents a raster overlay image applied to a geometry tile. While a `Tile` may have textures, too, a `RasterOverlayTile` never has geometry. + While it's possible to derive a class from `RasterOverlayTileProvider` directly and implement the [loadTileImage](\ref CesiumRasterOverlays::RasterOverlayTileProvider::loadTileImage) method, there are two shortcuts available that often save a lot of implementation effort. In the very common scenario where a raster overlay source is organized into a quadtree of tiles, and each tile can be downloaded from a web URL, we can implement `createTileProvider` to construct an instance of [UrlTemplateRasterOverlay](\ref CesiumRasterOverlays::UrlTemplateRasterOverlay) with the appropriate templatized URL and then call its `createTileProvider`: From 678c2de3a41b4a997876d497750da3b6b8e44d0a Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 17:36:44 +1100 Subject: [PATCH 15/28] Fix clang/gcc error. --- CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp index 34b1daa4d..ada2a002b 100644 --- a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp +++ b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp @@ -60,7 +60,7 @@ MyRasterOverlay::createTileProvider( pCreditSystem, pPrepareRendererResources, pLogger, - this); + pOwner != nullptr ? pOwner : this); } //! [use-url-template] From 53c239060890caf2e4f31742f65395b3223c890e Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 17:54:26 +1100 Subject: [PATCH 16/28] Mark example code [[maybe_unused]] to appease GCC. --- CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp index ada2a002b..a30306162 100644 --- a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp +++ b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp @@ -7,7 +7,7 @@ using namespace CesiumRasterOverlays; namespace { -class MyRasterOverlay : public RasterOverlay { +class [[maybe_unused]] MyRasterOverlay : public RasterOverlay { public: virtual CesiumAsync::Future createTileProvider( const CesiumAsync::AsyncSystem& asyncSystem, From 53826da2bb3ddb1d90b028d041af414b05b65718 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 16 Jan 2025 18:00:42 +1100 Subject: [PATCH 17/28] Use the example raster overlay. --- CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp index a30306162..9c933d065 100644 --- a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp +++ b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp @@ -7,8 +7,10 @@ using namespace CesiumRasterOverlays; namespace { -class [[maybe_unused]] MyRasterOverlay : public RasterOverlay { +class MyRasterOverlay : public RasterOverlay { public: + MyRasterOverlay() : RasterOverlay("name", {}) {} + virtual CesiumAsync::Future createTileProvider( const CesiumAsync::AsyncSystem& asyncSystem, const std::shared_ptr& pAssetAccessor, @@ -65,3 +67,8 @@ MyRasterOverlay::createTileProvider( //! [use-url-template] } // namespace + +TEST_CASE("RasterOverlay examples") { + CesiumUtility::IntrusivePointer pOverlay = + new MyRasterOverlay(); +} \ No newline at end of file From e740e3a7b580452cb02db4df490358143bade7e9 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 16 Jan 2025 14:05:13 -0500 Subject: [PATCH 18/28] Address review comments --- .../include/Cesium3DTilesSelection/TilesetOptions.h | 2 +- Cesium3DTilesSelection/src/Tileset.cpp | 2 -- Cesium3DTilesSelection/src/TilesetContentManager.cpp | 3 +-- Cesium3DTilesSelection/src/TilesetContentManager.h | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h index 15169e5b8..24d289808 100644 --- a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h +++ b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/TilesetOptions.h @@ -331,7 +331,7 @@ struct CESIUM3DTILESSELECTION_API TilesetOptions { CesiumGeospatial::Ellipsoid ellipsoid = CesiumGeospatial::Ellipsoid::WGS84; /** - * @brief Headers to attach to requests made for this tileset. + * @brief HTTP headers to attach to requests made for this tileset. */ std::vector requestHeaders; }; diff --git a/Cesium3DTilesSelection/src/Tileset.cpp b/Cesium3DTilesSelection/src/Tileset.cpp index ff9b62ea7..8f0ae7c50 100644 --- a/Cesium3DTilesSelection/src/Tileset.cpp +++ b/Cesium3DTilesSelection/src/Tileset.cpp @@ -54,8 +54,6 @@ Tileset::Tileset( _loadedTiles, externals, options.ellipsoid}, - std::vector( - options.requestHeaders), std::move(pCustomLoader), std::move(pRootTile)), } {} diff --git a/Cesium3DTilesSelection/src/TilesetContentManager.cpp b/Cesium3DTilesSelection/src/TilesetContentManager.cpp index 71fe61c38..4d60fb48f 100644 --- a/Cesium3DTilesSelection/src/TilesetContentManager.cpp +++ b/Cesium3DTilesSelection/src/TilesetContentManager.cpp @@ -651,11 +651,10 @@ TilesetContentManager::TilesetContentManager( const TilesetExternals& externals, const TilesetOptions& tilesetOptions, RasterOverlayCollection&& overlayCollection, - std::vector&& requestHeaders, std::unique_ptr&& pLoader, std::unique_ptr&& pRootTile) : _externals{externals}, - _requestHeaders{std::move(requestHeaders)}, + _requestHeaders{tilesetOptions.requestHeaders}, _pLoader{std::move(pLoader)}, _pRootTile{std::move(pRootTile)}, _userCredit( diff --git a/Cesium3DTilesSelection/src/TilesetContentManager.h b/Cesium3DTilesSelection/src/TilesetContentManager.h index 0a4af3831..f8c749482 100644 --- a/Cesium3DTilesSelection/src/TilesetContentManager.h +++ b/Cesium3DTilesSelection/src/TilesetContentManager.h @@ -28,7 +28,6 @@ class TilesetContentManager const TilesetExternals& externals, const TilesetOptions& tilesetOptions, RasterOverlayCollection&& overlayCollection, - std::vector&& requestHeaders, std::unique_ptr&& pLoader, std::unique_ptr&& pRootTile); From bd0ebb9bf1fef32ae4d7a441fe035b275ed880f8 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 16 Jan 2025 14:34:21 -0500 Subject: [PATCH 19/28] Use geospatial guide instead of glossary --- .../include/CesiumGeospatial/Ellipsoid.h | 2 ++ .../include/CesiumGeospatial/GlobeAnchor.h | 2 +- .../LocalHorizontalCoordinateSystem.h | 18 +++++++++--------- .../CesiumGltfContent/SkirtMeshMetadata.h | 2 +- doc/CMakeLists.txt | 2 ++ doc/community.tag | 14 ++++++++++++++ doc/topics/developer.md | 3 ++- doc/topics/glossary.md | 9 --------- 8 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 doc/community.tag delete mode 100644 doc/topics/glossary.md diff --git a/CesiumGeospatial/include/CesiumGeospatial/Ellipsoid.h b/CesiumGeospatial/include/CesiumGeospatial/Ellipsoid.h index de0e7ee82..8e9a26d90 100644 --- a/CesiumGeospatial/include/CesiumGeospatial/Ellipsoid.h +++ b/CesiumGeospatial/include/CesiumGeospatial/Ellipsoid.h @@ -33,6 +33,8 @@ namespace CesiumGeospatial { * 1`. This is primarily used by Cesium to represent the shape of planetary * bodies. Rather than constructing this object directly, one of the provided * constants is normally used. + * + * @see \ref what-is-an-ellipsoid */ class CESIUMGEOSPATIAL_API Ellipsoid final { public: diff --git a/CesiumGeospatial/include/CesiumGeospatial/GlobeAnchor.h b/CesiumGeospatial/include/CesiumGeospatial/GlobeAnchor.h index 2b81ed8dd..750bca6a9 100644 --- a/CesiumGeospatial/include/CesiumGeospatial/GlobeAnchor.h +++ b/CesiumGeospatial/include/CesiumGeospatial/GlobeAnchor.h @@ -14,7 +14,7 @@ class LocalHorizontalCoordinateSystem; /** * @brief Anchors an object to the globe by defining a transformation from the * object's coordinate to the globe-fixed coordinate system (usually - * \ref glossary-ecef). + * \ref what-are-ecef-coordinates). * * This class allows the anchored coordinate system to be realized in any * {@link LocalHorizontalCoordinateSystem}. When the object is moved, either by diff --git a/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h b/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h index 91c2b311b..b1a859b44 100644 --- a/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h +++ b/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h @@ -55,7 +55,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { const Ellipsoid& ellipsoid = CesiumGeospatial::Ellipsoid::WGS84); /** - * @brief Create a new coordinate system centered at a \ref glossary-ecef + * @brief Create a new coordinate system centered at a \ref what-are-ecef-coordinates * "Earth-Centered, Earth-Fixed" position. * * @param originEcef The origin of the coordinate system. @@ -80,7 +80,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Create a new coordinate system with a specified transformation to - * the \ref glossary-ecef "Earth-Centered, Earth-Fixed" frame. This is an + * the \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" frame. This is an * advanced constructor and should be avoided in most cases. * * This constructor can be used to save/restore the state of an instance. It @@ -96,7 +96,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Create a new coordinate system with the specified transformations * between the local frame and the - * \ref glossary-ecef "Earth-Centered, Earth-Fixed" frame. This is an advanced + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" frame. This is an advanced * constructor and should be avoided in most cases. * * This constructor can be used to save/restore the state of an instance. It @@ -117,7 +117,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Gets the transformation matrix from the local horizontal coordinate - * system managed by this instance to the \ref glossary-ecef. + * system managed by this instance to the \ref what-are-ecef-coordinates. * * @return The transformation. */ @@ -126,7 +126,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { } /** - * @brief Gets the transformation matrix from \ref glossary-ecef to the + * @brief Gets the transformation matrix from \ref what-are-ecef-coordinates to the * local horizontal coordinate system managed by this instance. * * @return The transformation. @@ -138,7 +138,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Converts a position in the local horizontal coordinate system * managed by this instance to - * \ref glossary-ecef "Earth-Centered, Earth-Fixed (ECEF)". + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)". * * @param localPosition The position in the local coordinate system. * @return The equivalent position in the ECEF coordinate system. @@ -148,7 +148,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Converts a position in the - * \ref glossary-ecef "Earth-Centered, Earth-Fixed (ECEF)" coordinate system + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)" coordinate system * to the local horizontal coordinate system managed by this instance. * * @param ecefPosition The position in the ECEF coordinate system. @@ -159,7 +159,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Converts a direction in the local horizontal coordinate system * managed by this instance to - * \ref glossary-ecef "Earth-Centered, Earth-Fixed (ECEF)". + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)". * * Because the vector is treated as a direction only, the translation portion * of the transformation is ignored. @@ -172,7 +172,7 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Converts a direction in the - * \ref glossary-ecef "Earth-Centered, Earth-Fixed (ECEF)" coordinate system + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)" coordinate system * to the local horizontal coordinate system managed by this instance. * * Because the vector is treated as a direction only, the translation portion diff --git a/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h b/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h index 594be7ddf..2453097ae 100644 --- a/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h +++ b/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h @@ -89,7 +89,7 @@ struct SkirtMeshMetadata { */ uint32_t noSkirtVerticesCount; /** - * @brief The center coordinates of the mesh, in \ref glossary-ecef. + * @brief The center coordinates of the mesh, in \ref what-are-ecef-coordinates. */ glm::dvec3 meshCenter; /** diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 20cb6bdd0..83c92c4f1 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -115,6 +115,8 @@ if(DOXYGEN_FOUND) set(DOXYGEN_VERBATIM_VARS DOXYGEN_ALIASES DOXYGEN_HTML_EXTRA_FILES) list(APPEND DOXYGEN_EXAMPLE_PATH "${CMAKE_CURRENT_LIST_DIR}/diagrams") + list(APPEND DOXYGEN_TAGFILES "${CMAKE_CURRENT_LIST_DIR}/community.tag=https://github.com/CesiumGS/community/blob/main") + cesium_glob_files( CESIUM_DOC_TOPICS ${CMAKE_CURRENT_LIST_DIR}/topics/*.md diff --git a/doc/community.tag b/doc/community.tag new file mode 100644 index 000000000..b0d46f210 --- /dev/null +++ b/doc/community.tag @@ -0,0 +1,14 @@ + + + + + geospatial-guide + Geospatial Guide + GeospatialGuide/README.md + what-are-ecef-coordinates + what-is-an-ellipsoid + + \ No newline at end of file diff --git a/doc/topics/developer.md b/doc/topics/developer.md index 48f23d1d3..ca3b8f72e 100644 --- a/doc/topics/developer.md +++ b/doc/topics/developer.md @@ -3,4 +3,5 @@ * \subpage developer-setup * \subpage multithreading * \subpage style-guide -* \subpage contributing \ No newline at end of file +* \subpage contributing +* \subpage geospatial-guide \ No newline at end of file diff --git a/doc/topics/glossary.md b/doc/topics/glossary.md deleted file mode 100644 index 0154b6e4b..000000000 --- a/doc/topics/glossary.md +++ /dev/null @@ -1,9 +0,0 @@ -# Glossary {#glossary} - -Terminology and jargon used throughout Cesium Native and its documentation is collected here for clarity's sake. - -## Earth-Centered, Earth-Fixed Coordinates (ECEF) {#glossary-ecef} - -Earth-Centered, Earth-Fixed (ECEF) coordinates are, as the name describes, in a 3D Cartesian coordinate system fixed to the Earth with the center at the center of the Earth's ellipsoid. As the Earth spins, the coordinate system spins with it, meaning an ECEF coordinate and its equivalent coordinate in a cartographic coordinate system (like Longitude, Latitude, Height) will remain the same. - -For example, Philadelphia, Pennsylvania is located at -75.1652215° longitude, 39.952839° latitude, at a height of 14.34m. The equivalent ECEF coordinates are (1253556.69, -4732887.41, 4073982.02). \ No newline at end of file From 46cb506eac70ce5f9d9d261f39f7313d34624f82 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 16 Jan 2025 14:38:26 -0500 Subject: [PATCH 20/28] Format --- .../LocalHorizontalCoordinateSystem.h | 26 ++++++++++--------- .../CesiumGltfContent/SkirtMeshMetadata.h | 3 ++- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h b/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h index b1a859b44..705c2c867 100644 --- a/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h +++ b/CesiumGeospatial/include/CesiumGeospatial/LocalHorizontalCoordinateSystem.h @@ -55,8 +55,8 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { const Ellipsoid& ellipsoid = CesiumGeospatial::Ellipsoid::WGS84); /** - * @brief Create a new coordinate system centered at a \ref what-are-ecef-coordinates - * "Earth-Centered, Earth-Fixed" position. + * @brief Create a new coordinate system centered at a \ref + * what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" position. * * @param originEcef The origin of the coordinate system. * @param xAxisDirection The local direction in which the X axis points at the @@ -80,8 +80,8 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Create a new coordinate system with a specified transformation to - * the \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" frame. This is an - * advanced constructor and should be avoided in most cases. + * the \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" frame. + * This is an advanced constructor and should be avoided in most cases. * * This constructor can be used to save/restore the state of an instance. It * can also be used to create unusual coordinate systems that can't be created @@ -96,8 +96,8 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Create a new coordinate system with the specified transformations * between the local frame and the - * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" frame. This is an advanced - * constructor and should be avoided in most cases. + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed" frame. This is + * an advanced constructor and should be avoided in most cases. * * This constructor can be used to save/restore the state of an instance. It * can also be used to create unusual coordinate systems that can't be created @@ -126,8 +126,8 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { } /** - * @brief Gets the transformation matrix from \ref what-are-ecef-coordinates to the - * local horizontal coordinate system managed by this instance. + * @brief Gets the transformation matrix from \ref what-are-ecef-coordinates + * to the local horizontal coordinate system managed by this instance. * * @return The transformation. */ @@ -148,8 +148,9 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Converts a position in the - * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)" coordinate system - * to the local horizontal coordinate system managed by this instance. + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)" + * coordinate system to the local horizontal coordinate system managed by this + * instance. * * @param ecefPosition The position in the ECEF coordinate system. * @return The equivalent position in the local coordinate system. @@ -172,8 +173,9 @@ class CESIUMGEOSPATIAL_API LocalHorizontalCoordinateSystem { /** * @brief Converts a direction in the - * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)" coordinate system - * to the local horizontal coordinate system managed by this instance. + * \ref what-are-ecef-coordinates "Earth-Centered, Earth-Fixed (ECEF)" + * coordinate system to the local horizontal coordinate system managed by this + * instance. * * Because the vector is treated as a direction only, the translation portion * of the transformation is ignored. diff --git a/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h b/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h index 2453097ae..e20fda4e6 100644 --- a/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h +++ b/CesiumGltfContent/include/CesiumGltfContent/SkirtMeshMetadata.h @@ -89,7 +89,8 @@ struct SkirtMeshMetadata { */ uint32_t noSkirtVerticesCount; /** - * @brief The center coordinates of the mesh, in \ref what-are-ecef-coordinates. + * @brief The center coordinates of the mesh, in \ref + * what-are-ecef-coordinates. */ glm::dvec3 meshCenter; /** From 31f16082fc1157e8e86ca4a5b66592184e406ba3 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Tue, 21 Jan 2025 14:50:47 -0500 Subject: [PATCH 21/28] Fix build errors --- .../test/TestTilesetContentManager.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp b/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp index f38c6ba00..524a30fea 100644 --- a/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp +++ b/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp @@ -506,7 +506,6 @@ TEST_CASE("Test tile state machine") { externals, options, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -612,7 +611,6 @@ TEST_CASE("Test tile state machine") { externals, options, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -689,7 +687,6 @@ TEST_CASE("Test tile state machine") { externals, options, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -792,7 +789,6 @@ TEST_CASE("Test tile state machine") { externals, options, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -947,7 +943,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, {}, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -1017,7 +1012,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, options, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -1083,7 +1077,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, {}, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -1134,7 +1127,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, {}, std::move(rasterOverlayCollection), - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -1428,7 +1420,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, {}, std::move(rasterOverlayCollection), - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -1651,7 +1642,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, {}, std::move(rasterOverlayCollection), - {}, std::move(pMockedLoader), std::move(pRootTile)}; @@ -1720,7 +1710,6 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { externals, {}, RasterOverlayCollection{loadedTiles, externals}, - {}, std::move(loaderResult.pLoader), std::move(loaderResult.pRootTile)}; From 7948a1b4224812ce0747f7282649a259f7e1230b Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 21 Jan 2025 16:52:51 -0500 Subject: [PATCH 22/28] Fix clang-tidy errors --- Cesium3DTilesContent/src/I3dmToGltfConverter.cpp | 1 + CesiumGeometry/src/IntersectionTests.cpp | 2 +- CesiumRasterOverlays/src/RasterOverlayUtilities.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp b/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp index a145d6e98..ce0d53415 100644 --- a/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp +++ b/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/CesiumGeometry/src/IntersectionTests.cpp b/CesiumGeometry/src/IntersectionTests.cpp index e7c0f56dd..0acbf6e19 100644 --- a/CesiumGeometry/src/IntersectionTests.cpp +++ b/CesiumGeometry/src/IntersectionTests.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp b/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp index 693c5ec47..b741a97f1 100644 --- a/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp +++ b/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include From 699691492a09af7c0a6a1efb0fb89f3b042ff05a Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 21 Jan 2025 16:53:00 -0500 Subject: [PATCH 23/28] Tweak developer setup guide --- doc/topics/developer-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/topics/developer-setup.md b/doc/topics/developer-setup.md index 919bd6099..442622ea9 100644 --- a/doc/topics/developer-setup.md +++ b/doc/topics/developer-setup.md @@ -159,7 +159,7 @@ cmake -B build -S . 3. Next, we run the clang-tidy target of Cesium Native's cmake build, which will run clang-tidy. clang-tidy produces a lot of not-very-useful output, so we send it to a file instead of the console: ``` -cmake --build build-tidy --target clang-tidy > clang-tidy.log +cmake --build build --target clang-tidy > clang-tidy.log ``` 4. Finally, we use `sed` to extract the errors and warnings from the log: @@ -187,7 +187,7 @@ cmake -B build -S . -DCLANG_TIDY_PATH=$(brew --prefix llvm)/bin/clang-tidy -DCLA 3. Next, we run the clang-tidy target of Cesium Native's cmake build, which will run clang-tidy. clang-tidy produces a lot of not-very-useful output, so we send it to a file instead of the console: ``` -cmake --build build-tidy --target clang-tidy > clang-tidy.log +cmake --build build --target clang-tidy > clang-tidy.log ``` 4. Finally, we use `sed` to extract the errors and warnings from the log: From cf03a20818557ac8c406eaf388b74a10f81c5e87 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 22 Jan 2025 13:43:52 +1100 Subject: [PATCH 24/28] Clean up CHANGES.md. --- CHANGES.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a88cb56ed..588f7f4b8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,5 @@ # Change Log -### ? - ? - -##### Additions :tada: - -- Added `requestHeaders` field to `TilesetOptions` to allow per-tileset request headers to be specified. - ### v0.44.0 - 2025-02-03 ##### Breaking Changes :mega: @@ -18,6 +12,7 @@ - Added `CesiumIonClient::Connection::geocode` method for making geocoding queries against the Cesium ion geocoder API. - Added `UrlTemplateRasterOverlay` for requesting raster tiles from services using a templated URL. - `upsampleGltfForRasterOverlays` is now compatible with meshes using TRIANGLE_STRIP, TRIANGLE_FAN, or non-indexed TRIANGLES primitives. +- Added `requestHeaders` field to `TilesetOptions` to allow per-tileset request headers to be specified. ##### Fixes :wrench: From 4b8e520ef0317d3d9800b623881663fcba550c16 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 22 Jan 2025 18:50:41 +1100 Subject: [PATCH 25/28] Return the highest sample height, not the first one. --- CHANGES.md | 1 + Cesium3DTilesSelection/src/TilesetHeightQuery.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 588f7f4b8..c41e0dbb5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ ##### Fixes :wrench: - Fixed a crash in `GltfWriter` that would happen when the `EXT_structural_metadata` `schema` property was null. +- Fixed a bug that could cause `Tileset::sampleHeightMostDetailed` to return a height that is not the highest one when the sampled tileset contained multiple heights at the given location. ### v0.43.0 - 2025-01-02 diff --git a/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp b/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp index 170eaa6e6..6fa2c60ff 100644 --- a/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp +++ b/Cesium3DTilesSelection/src/TilesetHeightQuery.cpp @@ -133,9 +133,9 @@ void TilesetHeightQuery::intersectVisibleTile( // Set ray info to this hit if closer, or the first hit if (!this->intersection.has_value()) { this->intersection = std::move(gltfIntersectResult.hit); - } else { + } else if (gltfIntersectResult.hit) { double prevDistSq = this->intersection->rayToWorldPointDistanceSq; - double thisDistSq = intersection->rayToWorldPointDistanceSq; + double thisDistSq = gltfIntersectResult.hit->rayToWorldPointDistanceSq; if (thisDistSq < prevDistSq) this->intersection = std::move(gltfIntersectResult.hit); } From 6541b5b4502853d83fa414e07dbfcd0a7c88252a Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 22 Jan 2025 21:27:55 +1100 Subject: [PATCH 26/28] Add a test. --- .../test/TestTilesetHeightQueries.cpp | 31 ++++++++ .../test/data/stacked-cubes/cube.b3dm | Bin 0 -> 1680 bytes .../test/data/stacked-cubes/tileset.json | 71 ++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 Cesium3DTilesSelection/test/data/stacked-cubes/cube.b3dm create mode 100644 Cesium3DTilesSelection/test/data/stacked-cubes/tileset.json diff --git a/Cesium3DTilesSelection/test/TestTilesetHeightQueries.cpp b/Cesium3DTilesSelection/test/TestTilesetHeightQueries.cpp index 6c5bfdce1..0facaa86f 100644 --- a/Cesium3DTilesSelection/test/TestTilesetHeightQueries.cpp +++ b/Cesium3DTilesSelection/test/TestTilesetHeightQueries.cpp @@ -275,4 +275,35 @@ TEST_CASE("Tileset height queries") { 0.0, Math::Epsilon4)); } + + SUBCASE("stacked-cubes") { + // This tileset has two cubes on top of each other, each in a different + // tile, so we can test that the height of the top one is returned. + // The bottom cube has a height of 78.0 meters, the upper cube has a height + // of 83.0 meters. + std::string url = + "file://" + + Uri::nativePathToUriPath(StringHelpers::toStringUtf8( + (testDataPath / "stacked-cubes" / "tileset.json").u8string())); + + Tileset tileset(externals, url); + + Future future = tileset.sampleHeightMostDetailed( + {Cartographic::fromDegrees(10.0, 45.0, 0.0)}); + + while (!future.isReady()) { + tileset.updateView({}); + } + + SampleHeightResult results = future.waitInMainThread(); + CHECK(results.warnings.empty()); + REQUIRE(results.positions.size() == 1); + + CHECK(results.sampleSuccess[0]); + CHECK(Math::equalsEpsilon( + results.positions[0].height, + 83.0, + 0.0, + Math::Epsilon1)); + } } diff --git a/Cesium3DTilesSelection/test/data/stacked-cubes/cube.b3dm b/Cesium3DTilesSelection/test/data/stacked-cubes/cube.b3dm new file mode 100644 index 0000000000000000000000000000000000000000..c86e47cacd21c8e9c5992384f5c47d8fa624b00a GIT binary patch literal 1680 zcmb_cTT|0O6h45WqN1YWYv(*iCQV9h^8%#Bm7&AH;NJs3!Pq}2=kaTu_Gcdy1|XS-;WHRKZG>3-crL74>P+$d@2yX5-p zeNmGS+4k-4Bq(Zh)5@6)1}r*t**CO`Q!T;&<4h-a8DGX9zKmSH%z0v+daY4AxlPTa zoU^g(qHMQ9SzP^a;&`m%_E{e-9!;2rV<&1d zZhM~FI|(PlQ9wN^{5p2b>Y*1#2X>E#k?7*BiY~8Wv1;g5qpIbR$c{-JC{t9xNcoz} zwzj7lGT)73s)UlB=^EWsF54TA?54~N+sC!fU-qf2!K}a0&%XFVFez*Ls+G86&}H3cmiuQuEA4y2G3!g#&viBFX0tz(6|Aw>A&$7 zHfh|1cj@ordM5=m<-vlThbK7KHyPVGu(X|nr|jm9<2H&JQu_b$C++Xf@{l@l` Date: Thu, 23 Jan 2025 13:14:59 -0500 Subject: [PATCH 27/28] Small edits --- doc/topics/developer.md | 1 + doc/topics/raster-overlays.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/topics/developer.md b/doc/topics/developer.md index 17a82a5fc..cd2f4186e 100644 --- a/doc/topics/developer.md +++ b/doc/topics/developer.md @@ -12,3 +12,4 @@ * \subpage multithreading * \subpage selection-algorithm-details * \subpage rendering-3d-tiles +* \subpage raster-overlays \ No newline at end of file diff --git a/doc/topics/raster-overlays.md b/doc/topics/raster-overlays.md index 0e78c9d7f..02de14252 100644 --- a/doc/topics/raster-overlays.md +++ b/doc/topics/raster-overlays.md @@ -7,10 +7,10 @@ The following raster overlay types are currently included in Cesium Native: * [BingMapsRasterOverlay](\ref CesiumRasterOverlays::BingMapsRasterOverlay) * [DebugColorizeTilesRasterOverlay](\ref CesiumRasterOverlays::DebugColorizeTilesRasterOverlay) * [IonRasterOverlay](\ref CesiumRasterOverlays::IonRasterOverlay) -* [WebMapServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapServiceRasterOverlay) -* [WebMapTileServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapTileServiceRasterOverlay) * [TileMapServiceRasterOverlay](\ref CesiumRasterOverlays::TileMapServiceRasterOverlay) * [UrlTemplateRasterOverlay](\ref CesiumRasterOverlays::UrlTemplateRasterOverlay) +* [WebMapServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapServiceRasterOverlay) +* [WebMapTileServiceRasterOverlay](\ref CesiumRasterOverlays::WebMapTileServiceRasterOverlay) To add a raster overlay to a `Tileset`, construct an instance of the appropriate class and add it to the [RasterOverlayCollection](\ref Cesium3DTilesSelection::RasterOverlayCollection) returned by [Tileset::getOverlays](\ref Cesium3DTilesSelection::Tileset::getOverlays). See the reference documentation for each overlay for details about how to configure that overlay type. From 24c84e4cf6b8edfbb9f239a50d20405786216535 Mon Sep 17 00:00:00 2001 From: Ashley Rogers Date: Thu, 23 Jan 2025 13:30:03 -0500 Subject: [PATCH 28/28] Catch2 -> doctest --- CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp index 9c933d065..d38525f50 100644 --- a/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp +++ b/CesiumRasterOverlays/test/ExamplesRasterOverlays.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include using namespace CesiumRasterOverlays;