diff --git a/src/vsgCs/CMakeLists.txt b/src/vsgCs/CMakeLists.txt
index c896b73..b305e5b 100644
--- a/src/vsgCs/CMakeLists.txt
+++ b/src/vsgCs/CMakeLists.txt
@@ -9,6 +9,10 @@ set(LIB_PUBLIC_HEADERS
${PROJECT_BINARY_DIR}/include/vsgCs/Config.h
CRS.h
CsDebugColorizeTilesOverlay.h
+ CsWebMapServiceRasterOverlay.h
+ CsWebMapTileServiceRasterOverlay.h
+ CsTileMapServiceRasterOverlay.h
+ CsUrlTemplateRasterOverlay.h
CsOverlay.h
CesiumGltfBuilder.h
CppAllocator.h
@@ -35,6 +39,10 @@ set(LIB_PUBLIC_HEADERS
set(SOURCES
CRS.cpp
CsDebugColorizeTilesOverlay.cpp
+ CsWebMapServiceRasterOverlay.cpp
+ CsWebMapTileServiceRasterOverlay.cpp
+ CsTileMapServiceRasterOverlay.cpp
+ CsUrlTemplateRasterOverlay.cpp
CsOverlay.cpp
CesiumGltfBuilder.cpp
CompilableImage.cpp
diff --git a/src/vsgCs/CsTileMapServiceRasterOverlay.cpp b/src/vsgCs/CsTileMapServiceRasterOverlay.cpp
new file mode 100644
index 0000000..880d661
--- /dev/null
+++ b/src/vsgCs/CsTileMapServiceRasterOverlay.cpp
@@ -0,0 +1,93 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#include "CsTileMapServiceRasterOverlay.h"
+
+#include "jsonUtils.h"
+#include
+#include
+
+using namespace vsgCs;
+
+CesiumRasterOverlays::RasterOverlay* CsTileMapServiceRasterOverlay::createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options)
+{
+ if (url.empty())
+ {
+ // Don't create an overlay with an empty URL.
+ return nullptr;
+ }
+
+ CesiumRasterOverlays::TileMapServiceRasterOverlayOptions tmsOptions;
+ if (maximumLevel > minimumLevel && bSpecifyZoomLevels)
+ {
+ tmsOptions.minimumLevel = minimumLevel;
+ tmsOptions.maximumLevel = maximumLevel;
+ }
+
+ std::vector headers;
+
+ for (const auto& [Key, Value] : requestHeaders)
+ {
+ headers.push_back(CesiumAsync::IAssetAccessor::THeader{
+ Key,
+ Value });
+ }
+
+ return new CesiumRasterOverlays::TileMapServiceRasterOverlay(
+ MaterialLayerKey,
+ url,
+ headers,
+ tmsOptions,
+ options);
+}
+
+namespace vsgCs
+{
+ vsg::ref_ptr buildCsTileMapServiceRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object)
+ {
+ auto overlay = create_or(object);
+ factory->build(json, "CsOverlay", overlay);
+ overlay->MaterialLayerKey = CesiumUtility::JsonHelpers::getStringOrDefault(json, "materialKey",
+ "Overlay0");
+ overlay->url = CesiumUtility::JsonHelpers::getStringOrDefault(json, "url", "");
+ overlay->minimumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "minimumLevel", overlay->minimumLevel);
+ overlay->maximumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "maximumLevel", overlay->maximumLevel);
+ const auto requestHeaders = json.FindMember("requestHeaders");
+ if (requestHeaders != json.MemberEnd() && requestHeaders->value.IsObject())
+ {
+ auto obj = requestHeaders->value.GetObject();
+ for (auto itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr)
+ {
+ overlay->requestHeaders.insert(std::make_pair(itr->name.GetString(), itr->value.GetString()));
+ }
+ }
+
+ return overlay;
+ }
+
+ // XXX See jsonUtils for registration.
+}
diff --git a/src/vsgCs/CsTileMapServiceRasterOverlay.h b/src/vsgCs/CsTileMapServiceRasterOverlay.h
new file mode 100644
index 0000000..f84a6fa
--- /dev/null
+++ b/src/vsgCs/CsTileMapServiceRasterOverlay.h
@@ -0,0 +1,71 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#pragma once
+
+#include "CsOverlay.h"
+
+namespace vsgCs
+{
+ class VSGCS_EXPORT CsTileMapServiceRasterOverlay : public vsg::Inherit
+ {
+ public:
+ CsTileMapServiceRasterOverlay(
+ std::string in_url = std::string())
+ : url(std::move(in_url))
+ {
+ }
+
+ /**
+ * The base URL of the Tile Map Service (TMS).
+ */
+ std::string url;
+
+ /**
+ * True to directly specify minum and maximum zoom levels available from the
+ * server, or false to automatically determine the minimum and maximum zoom
+ * levels from the server's tilemapresource.xml file.
+ */
+ bool bSpecifyZoomLevels = false;
+
+ /**
+ * Minimum zoom level.
+ */
+ int32_t minimumLevel = 0;
+
+ /**
+ * Maximum zoom level.
+ */
+ int32_t maximumLevel = 10;
+
+ /**
+ * HTTP headers to be attached to each request made for this raster overlay.
+ */
+ std::map requestHeaders;
+
+ CesiumRasterOverlays::RasterOverlay* createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options) override;
+ };
+}
diff --git a/src/vsgCs/CsUrlTemplateRasterOverlay.cpp b/src/vsgCs/CsUrlTemplateRasterOverlay.cpp
new file mode 100644
index 0000000..9052ab1
--- /dev/null
+++ b/src/vsgCs/CsUrlTemplateRasterOverlay.cpp
@@ -0,0 +1,131 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#include "CsUrlTemplateRasterOverlay.h"
+
+#include "jsonUtils.h"
+#include
+#include
+
+using namespace vsgCs;
+
+CesiumRasterOverlays::RasterOverlay* CsUrlTemplateRasterOverlay::createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options)
+{
+ if (templateUrl.empty())
+ {
+ // Don't create an overlay with an empty base URL.
+ return nullptr;
+ }
+
+ CesiumRasterOverlays::UrlTemplateRasterOverlayOptions urlTemplateOptions;
+
+ urlTemplateOptions.minimumLevel = minimumLevel;
+ urlTemplateOptions.maximumLevel = maximumLevel;
+
+ urlTemplateOptions.tileWidth = tileWidth;
+ urlTemplateOptions.tileHeight = tileHeight;
+
+ const CesiumGeospatial::Ellipsoid& ellipsoid = options.ellipsoid;
+
+ if (projection ==
+ ECesiumUrlTemplateRasterOverlayProjection::Geographic)
+ {
+ urlTemplateOptions.projection =
+ CesiumGeospatial::GeographicProjection(ellipsoid);
+ }
+ else
+ {
+ urlTemplateOptions.projection =
+ CesiumGeospatial::WebMercatorProjection(ellipsoid);
+ }
+
+ if (bSpecifyTilingScheme)
+ {
+ CesiumGeospatial::GlobeRectangle globeRectangle =
+ CesiumGeospatial::GlobeRectangle::fromDegrees(
+ rectangleWest,
+ rectangleSouth,
+ rectangleEast,
+ rectangleNorth);
+ CesiumGeometry::Rectangle coverageRectangle =
+ CesiumGeospatial::projectRectangleSimple(
+ *urlTemplateOptions.projection,
+ globeRectangle);
+ urlTemplateOptions.coverageRectangle = coverageRectangle;
+ urlTemplateOptions.tilingScheme = CesiumGeometry::QuadtreeTilingScheme(
+ coverageRectangle,
+ rootTilesX,
+ rootTilesY);
+ }
+
+ std::vector headers;
+
+ for (const auto& [Key, Value] : requestHeaders)
+ {
+ headers.push_back(CesiumAsync::IAssetAccessor::THeader{
+ Key,
+ Value });
+ }
+
+ return new CesiumRasterOverlays::UrlTemplateRasterOverlay(
+ MaterialLayerKey,
+ templateUrl,
+ headers,
+ urlTemplateOptions,
+ options);
+}
+
+namespace vsgCs
+{
+ vsg::ref_ptr buildCsUrlTemplateRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object)
+ {
+ auto overlay = create_or(object);
+ factory->build(json, "CsOverlay", overlay);
+ overlay->MaterialLayerKey = CesiumUtility::JsonHelpers::getStringOrDefault(json, "materialKey",
+ "Overlay0");
+ overlay->templateUrl = CesiumUtility::JsonHelpers::getStringOrDefault(json, "url", "");
+ std::string projection = CesiumUtility::JsonHelpers::getStringOrDefault(json, "projection", "");
+ overlay->projection = projection == "geographic" ? ECesiumUrlTemplateRasterOverlayProjection::Geographic : ECesiumUrlTemplateRasterOverlayProjection::WebMercator;
+ overlay->tileWidth = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "tileWidth", overlay->tileWidth);
+ overlay->tileHeight = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "tileHeight", overlay->tileHeight);
+ overlay->minimumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "minimumLevel", overlay->minimumLevel);
+ overlay->maximumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "maximumLevel", overlay->maximumLevel);
+ const auto requestHeaders = json.FindMember("requestHeaders");
+ if (requestHeaders != json.MemberEnd() && requestHeaders->value.IsObject())
+ {
+ auto obj = requestHeaders->value.GetObject();
+ for (auto itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr)
+ {
+ overlay->requestHeaders.insert(std::make_pair(itr->name.GetString(), itr->value.GetString()));
+ }
+ }
+
+ return overlay;
+ }
+
+ // XXX See jsonUtils for registration.
+}
diff --git a/src/vsgCs/CsUrlTemplateRasterOverlay.h b/src/vsgCs/CsUrlTemplateRasterOverlay.h
new file mode 100644
index 0000000..e702466
--- /dev/null
+++ b/src/vsgCs/CsUrlTemplateRasterOverlay.h
@@ -0,0 +1,186 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#pragma once
+
+#include "CsOverlay.h"
+
+namespace vsgCs
+{
+ /**
+ * Specifies the type of projection used for projecting a URL template
+ * raster overlay.
+ */
+ enum class ECesiumUrlTemplateRasterOverlayProjection : uint8_t {
+ /**
+ * The raster overlay is projected using Web Mercator.
+ */
+ WebMercator,
+
+ /**
+ * The raster overlay is projected using a geographic projection.
+ */
+ Geographic
+ };
+
+ class VSGCS_EXPORT CsUrlTemplateRasterOverlay : public vsg::Inherit
+ {
+ public:
+ CsUrlTemplateRasterOverlay(
+ std::string in_url = std::string())
+ : templateUrl(std::move(in_url))
+ {
+ }
+
+ /**
+ * @brief The URL containing template parameters that will be substituted when
+ * loading tiles.
+ *
+ * The following template parameters are supported in `url`:
+ * - `{x}` - The tile X coordinate in the tiling scheme, where 0 is the
+ * westernmost tile.
+ * - `{y}` - The tile Y coordinate in the tiling scheme, where 0 is the
+ * nothernmost tile.
+ * - `{z}` - The level of the tile in the tiling scheme, where 0 is the root
+ * of the quadtree pyramid.
+ * - `{reverseX}` - The tile X coordinate in the tiling scheme, where 0 is the
+ * easternmost tile.
+ * - `{reverseY}` - The tile Y coordinate in the tiling scheme, where 0 is the
+ * southernmost tile.
+ * - `{reverseZ}` - The tile Z coordinate in the tiling scheme, where 0 is
+ * equivalent to `urlTemplateOptions.maximumLevel`.
+ * - `{westDegrees}` - The western edge of the tile in geodetic degrees.
+ * - `{southDegrees}` - The southern edge of the tile in geodetic degrees.
+ * - `{eastDegrees}` - The eastern edge of the tile in geodetic degrees.
+ * - `{northDegrees}` - The northern edge of the tile in geodetic degrees.
+ * - `{minimumX}` - The minimum X coordinate of the tile's projected
+ * coordinates.
+ * - `{minimumY}` - The minimum Y coordinate of the tile's projected
+ * coordinates.
+ * - `{maximumX}` - The maximum X coordinate of the tile's projected
+ * coordinates.
+ * - `{maximumY}` - The maximum Y coordinate of the tile's projected
+ * coordinates.
+ * - `{width}` - The width of each tile in pixels.
+ * - `{height}` - The height of each tile in pixels.
+ */
+ std::string templateUrl;
+
+ /**
+ * The type of projection used to project the imagery onto the globe.
+ * For instance, EPSG:4326 uses geographic projection and EPSG:3857 uses Web
+ * Mercator.
+ */
+ ECesiumUrlTemplateRasterOverlayProjection projection =
+ ECesiumUrlTemplateRasterOverlayProjection::WebMercator;
+
+ /**
+ * Set this to true to specify the quadtree tiling scheme according to the
+ * specified root tile numbers and projected bounding rectangle. If false, the
+ * tiling scheme will be deduced from the projection.
+ */
+ bool bSpecifyTilingScheme = false;
+
+ /**
+ * If specified, this determines the number of tiles at the
+ * root of the quadtree tiling scheme in the X direction.
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ int32_t rootTilesX = 1;
+
+ /**
+ * If specified, this determines the number of tiles at the
+ * root of the quadtree tiling scheme in the Y direction.
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ int32_t rootTilesY = 1;
+
+ /**
+ * The west boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in longitude degrees in the range [-180, 180].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleWest = -180;
+
+ /**
+ * The south boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in latitude degrees in the range [-90, 90].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleSouth = -90;
+
+ /**
+ * The east boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in longitude degrees in the range [-180, 180].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleEast = 180;
+
+ /**
+ * The north boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in latitude degrees in the range [-90, 90].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleNorth = 90;
+
+ /**
+ * Minimum zoom level.
+ *
+ * Take care when specifying this that the number of tiles at the minimum
+ * level is small, such as four or less. A larger number is likely to result
+ * in rendering problems.
+ */
+ int32_t minimumLevel = 0;
+
+ /**
+ * Maximum zoom level.
+ */
+ int32_t maximumLevel = 25;
+
+ /**
+ * The pixel width of the image tiles.
+ */
+ int32_t tileWidth = 256;
+
+ /**
+ * The pixel height of the image tiles.
+ */
+ int32_t tileHeight = 256;
+
+ /**
+ * HTTP headers to be attached to each request made for this raster overlay.
+ */
+ std::map requestHeaders;
+
+ CesiumRasterOverlays::RasterOverlay* createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options) override;
+ };
+}
diff --git a/src/vsgCs/CsWebMapServiceRasterOverlay.cpp b/src/vsgCs/CsWebMapServiceRasterOverlay.cpp
new file mode 100644
index 0000000..edc6079
--- /dev/null
+++ b/src/vsgCs/CsWebMapServiceRasterOverlay.cpp
@@ -0,0 +1,99 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#include "CsWebMapServiceRasterOverlay.h"
+
+#include "jsonUtils.h"
+#include
+#include
+
+using namespace vsgCs;
+
+CesiumRasterOverlays::RasterOverlay* CsWebMapServiceRasterOverlay::createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options)
+{
+ if (baseUrl.empty())
+ {
+ // Don't create an overlay with an empty base URL.
+ return nullptr;
+ }
+
+ CesiumRasterOverlays::WebMapServiceRasterOverlayOptions wmsOptions;
+ if (maximumLevel > minimumLevel)
+ {
+ wmsOptions.minimumLevel = minimumLevel;
+ wmsOptions.maximumLevel = maximumLevel;
+ }
+ wmsOptions.layers = layers;
+ wmsOptions.tileWidth = tileWidth;
+ wmsOptions.tileHeight = tileHeight;
+
+ std::vector headers;
+
+ for (const auto& [Key, Value] : requestHeaders)
+ {
+ headers.push_back(CesiumAsync::IAssetAccessor::THeader{
+ Key,
+ Value });
+ }
+
+ return new CesiumRasterOverlays::WebMapServiceRasterOverlay(
+ MaterialLayerKey,
+ baseUrl,
+ headers,
+ wmsOptions,
+ options);
+}
+
+namespace vsgCs
+{
+ vsg::ref_ptr buildCsWebMapServiceRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object)
+ {
+ auto overlay = create_or(object);
+ factory->build(json, "CsOverlay", overlay);
+ overlay->MaterialLayerKey = CesiumUtility::JsonHelpers::getStringOrDefault(json, "materialKey",
+ "Overlay0");
+ overlay->baseUrl = CesiumUtility::JsonHelpers::getStringOrDefault(json, "baseUrl", "");
+ overlay->layers = CesiumUtility::JsonHelpers::getStringOrDefault(json, "layers", "");
+ overlay->tileWidth = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "tileWidth", overlay->tileWidth);
+ overlay->tileHeight = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "tileHeight", overlay->tileHeight);
+ overlay->minimumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "minimumLevel", overlay->minimumLevel);
+ overlay->maximumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "maximumLevel", overlay->maximumLevel);
+ const auto requestHeaders = json.FindMember("requestHeaders");
+ if (requestHeaders != json.MemberEnd() && requestHeaders->value.IsObject())
+ {
+ auto obj = requestHeaders->value.GetObject();
+ for (auto itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr)
+ {
+ overlay->requestHeaders.insert(std::make_pair(itr->name.GetString(), itr->value.GetString()));
+ }
+ }
+
+ return overlay;
+ }
+
+ // XXX See jsonUtils for registration.
+}
diff --git a/src/vsgCs/CsWebMapServiceRasterOverlay.h b/src/vsgCs/CsWebMapServiceRasterOverlay.h
new file mode 100644
index 0000000..88a5799
--- /dev/null
+++ b/src/vsgCs/CsWebMapServiceRasterOverlay.h
@@ -0,0 +1,85 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#pragma once
+
+#include "CsOverlay.h"
+
+namespace vsgCs
+{
+ class VSGCS_EXPORT CsWebMapServiceRasterOverlay : public vsg::Inherit
+ {
+ public:
+ CsWebMapServiceRasterOverlay(
+ std::string in_baseUrl = std::string())
+ : baseUrl(std::move(in_baseUrl))
+ {
+ }
+
+ /**
+ * The base url of the Web Map Service (WMS).
+ * e.g.
+ * https://services.ga.gov.au/gis/services/NM_Culture_and_Infrastructure/MapServer/WMSServer
+ */
+ std::string baseUrl;
+
+ /**
+ * Comma-separated layer names to request from the server.
+ */
+ std::string layers;
+
+ /**
+ * Image width
+ */
+ int32_t tileWidth = 256;
+
+ /**
+ * Image height
+ */
+ int32_t tileHeight = 256;
+
+ /**
+ * Minimum zoom level.
+ *
+ * Take care when specifying this that the number of tiles at the minimum
+ * level is small, such as four or less. A larger number is likely to
+ * result in rendering problems.
+ */
+ int32_t minimumLevel = 0;
+
+ /**
+ * Maximum zoom level.
+ */
+ int32_t maximumLevel = 14;
+
+ /**
+ * HTTP headers to be attached to each request made for this raster overlay.
+ */
+ std::map requestHeaders;
+
+ CesiumRasterOverlays::RasterOverlay* createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options) override;
+ };
+}
diff --git a/src/vsgCs/CsWebMapTileServiceRasterOverlay.cpp b/src/vsgCs/CsWebMapTileServiceRasterOverlay.cpp
new file mode 100644
index 0000000..74656e8
--- /dev/null
+++ b/src/vsgCs/CsWebMapTileServiceRasterOverlay.cpp
@@ -0,0 +1,180 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#include "CsWebMapTileServiceRasterOverlay.h"
+
+#include "jsonUtils.h"
+#include
+#include
+
+using namespace vsgCs;
+
+CesiumRasterOverlays::RasterOverlay* CsWebMapTileServiceRasterOverlay::createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options)
+{
+ if (baseUrl.empty())
+ {
+ // Don't create an overlay with an empty base URL.
+ return nullptr;
+ }
+
+ CesiumRasterOverlays::WebMapTileServiceRasterOverlayOptions wmtsOptions;
+ if (!style.empty())
+ {
+ wmtsOptions.style = style;
+ }
+ if (!layer.empty())
+ {
+ wmtsOptions.layer = layer;
+ }
+ if (!format.empty())
+ {
+ wmtsOptions.format = format;
+ }
+ if (!tileMatrixSetID.empty())
+ {
+ wmtsOptions.tileMatrixSetID = tileMatrixSetID;
+ }
+
+ if (bSpecifyZoomLevels && maximumLevel > minimumLevel)
+ {
+ wmtsOptions.minimumLevel = minimumLevel;
+ wmtsOptions.maximumLevel = maximumLevel;
+ }
+
+ wmtsOptions.tileWidth = tileWidth;
+ wmtsOptions.tileHeight = tileHeight;
+
+ const CesiumGeospatial::Ellipsoid& ellipsoid = options.ellipsoid;
+
+ if (projection ==
+ ECesiumWebMapTileServiceRasterOverlayProjection::Geographic)
+ {
+ wmtsOptions.projection = CesiumGeospatial::GeographicProjection(ellipsoid);
+ }
+ else
+ {
+ wmtsOptions.projection = CesiumGeospatial::WebMercatorProjection(ellipsoid);
+ }
+
+ if (bSpecifyTilingScheme)
+ {
+ CesiumGeospatial::GlobeRectangle globeRectangle =
+ CesiumGeospatial::GlobeRectangle::fromDegrees(
+ rectangleWest,
+ rectangleSouth,
+ rectangleEast,
+ rectangleNorth);
+ CesiumGeometry::Rectangle coverageRectangle =
+ CesiumGeospatial::projectRectangleSimple(
+ *wmtsOptions.projection,
+ globeRectangle);
+ wmtsOptions.coverageRectangle = coverageRectangle;
+ wmtsOptions.tilingScheme = CesiumGeometry::QuadtreeTilingScheme(
+ coverageRectangle,
+ rootTilesX,
+ rootTilesY);
+ }
+
+ if (bSpecifyTileMatrixSetLabels)
+ {
+ if (!tileMatrixSetLabels.empty())
+ {
+ std::vector labels;
+ for (const auto& label : tileMatrixSetLabels)
+ {
+ labels.emplace_back(label);
+ }
+ wmtsOptions.tileMatrixLabels = labels;
+ }
+ }
+ else
+ {
+ if (!tileMatrixSetLabelPrefix.empty())
+ {
+ std::vector labels;
+ for (size_t level = 0; level <= 25; ++level)
+ {
+ std::string label(tileMatrixSetLabelPrefix);
+ label.append(std::to_string(level));
+ labels.emplace_back(label);
+ }
+ wmtsOptions.tileMatrixLabels = labels;
+ }
+ }
+
+ std::vector headers;
+
+ for (const auto& [Key, Value] : requestHeaders)
+ {
+ headers.push_back(CesiumAsync::IAssetAccessor::THeader{
+ Key,
+ Value });
+ }
+
+ return new CesiumRasterOverlays::WebMapTileServiceRasterOverlay(
+ MaterialLayerKey,
+ baseUrl,
+ headers,
+ wmtsOptions,
+ options);
+}
+
+namespace vsgCs
+{
+ vsg::ref_ptr buildCsWebMapTileServiceRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object)
+ {
+ auto overlay = create_or(object);
+ factory->build(json, "CsOverlay", overlay);
+ overlay->MaterialLayerKey = CesiumUtility::JsonHelpers::getStringOrDefault(json, "materialKey",
+ "Overlay0");
+ overlay->baseUrl = CesiumUtility::JsonHelpers::getStringOrDefault(json, "baseUrl", "");
+ overlay->layer = CesiumUtility::JsonHelpers::getStringOrDefault(json, "layer", "");
+ overlay->style = CesiumUtility::JsonHelpers::getStringOrDefault(json, "style", "");
+ overlay->format = CesiumUtility::JsonHelpers::getStringOrDefault(json, "format", overlay->format);
+ overlay->tileMatrixSetID = CesiumUtility::JsonHelpers::getStringOrDefault(json, "tileMatrixSetID", "");
+ overlay->tileMatrixSetLabelPrefix = CesiumUtility::JsonHelpers::getStringOrDefault(json, "tileMatrixSetLabelPrefix", "");
+ std::string projection = CesiumUtility::JsonHelpers::getStringOrDefault(json, "projection", "");
+ overlay->projection = projection == "geographic" ? ECesiumWebMapTileServiceRasterOverlayProjection::Geographic : ECesiumWebMapTileServiceRasterOverlayProjection::WebMercator;
+ overlay->tileWidth = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "tileWidth", overlay->tileWidth);
+ overlay->tileHeight = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "tileHeight", overlay->tileHeight);
+ overlay->minimumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "minimumLevel", overlay->minimumLevel);
+ overlay->maximumLevel = CesiumUtility::JsonHelpers::getInt32OrDefault(json, "maximumLevel", overlay->maximumLevel);
+ const auto requestHeaders = json.FindMember("requestHeaders");
+ if (requestHeaders != json.MemberEnd() && requestHeaders->value.IsObject())
+ {
+ auto obj = requestHeaders->value.GetObject();
+ for (auto itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr)
+ {
+ overlay->requestHeaders.insert(std::make_pair(itr->name.GetString(), itr->value.GetString()));
+ }
+ }
+
+ return overlay;
+ }
+
+ // XXX See jsonUtils for registration.
+}
diff --git a/src/vsgCs/CsWebMapTileServiceRasterOverlay.h b/src/vsgCs/CsWebMapTileServiceRasterOverlay.h
new file mode 100644
index 0000000..9f3f418
--- /dev/null
+++ b/src/vsgCs/CsWebMapTileServiceRasterOverlay.h
@@ -0,0 +1,210 @@
+/*
+
+Copyright(c) 2023 Timothy Moore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+#pragma once
+
+#include "CsOverlay.h"
+
+namespace vsgCs
+{
+ /**
+ * Specifies the type of projection used for projecting a Web Map Tile Service
+ * raster overlay.
+ */
+ enum class ECesiumWebMapTileServiceRasterOverlayProjection : uint8_t {
+ /**
+ * The raster overlay is projected using Web Mercator.
+ */
+ WebMercator,
+
+ /**
+ * The raster overlay is projected using a geographic projection.
+ */
+ Geographic
+ };
+
+ class VSGCS_EXPORT CsWebMapTileServiceRasterOverlay : public vsg::Inherit
+ {
+ public:
+ CsWebMapTileServiceRasterOverlay(
+ std::string in_baseUrl = std::string())
+ : baseUrl(std::move(in_baseUrl))
+ {
+ }
+
+ /**
+ * The base URL of the Web Map Tile Service (WMTS).
+ * This URL should not include query parameters. For example:
+ * https://tile.openstreetmap.org/{TileMatrix}/{TileCol}/{TileRow}.png
+ */
+ std::string baseUrl;
+
+ /**
+ * The layer name for WMTS requests.
+ */
+ std::string layer;
+
+ /**
+ * The style name for WMTS requests.
+ */
+ std::string style;
+
+ /**
+ * The MIME type for images to retrieve from the server.
+ */
+ std::string format = "image/jpeg";
+
+ /**
+ * The tile matrix set identifier for WMTS requests.
+ */
+ std::string tileMatrixSetID;
+
+ /**
+ * The prefix to use for the tile matrix set labels. For instance, setting
+ * "EPSG:4326:" as prefix generates label list ["EPSG:4326:0", "EPSG:4326:1",
+ * "EPSG:4326:2", ...]
+ * Only applicable when "Specify Tile Matrix Set Labels" is false.
+ */
+ std::string tileMatrixSetLabelPrefix;
+
+ /**
+ * Set this to true to specify tile matrix set labels manually. If false, the
+ * labels will be constructed from the specified levels and prefix (if one is
+ * specified).
+ */
+ bool bSpecifyTileMatrixSetLabels = false;
+
+ /**
+ * The manually specified tile matrix set labels.
+ *
+ * Only applicable when "Specify Tile Matrix Set Labels" is true.
+ */
+ std::vector tileMatrixSetLabels;
+
+ /**
+ * The type of projection used to project the WMTS imagery onto the globe.
+ * For instance, EPSG:4326 uses geographic projection and EPSG:3857 uses Web
+ * Mercator.
+ */
+ ECesiumWebMapTileServiceRasterOverlayProjection projection =
+ ECesiumWebMapTileServiceRasterOverlayProjection::WebMercator;
+
+ /**
+ * Set this to true to specify the quadtree tiling scheme according to the
+ * specified root tile numbers and projected bounding rectangle. If false, the
+ * tiling scheme will be deduced from the projection.
+ */
+ bool bSpecifyTilingScheme = false;
+
+ /**
+ * The number of tiles corresponding to TileCol, also known as
+ * TileMatrixWidth. If specified, this determines the number of tiles at the
+ * root of the quadtree tiling scheme in the X direction.
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ int32_t rootTilesX = 1;
+
+ /**
+ * The number of tiles corresponding to TileRow, also known as
+ * TileMatrixHeight. If specified, this determines the number of tiles at the
+ * root of the quadtree tiling scheme in the Y direction.
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ int32_t rootTilesY = 1;
+
+ /**
+ * The west boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in longitude degrees in the range [-180, 180].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleWest = -180;
+
+ /**
+ * The south boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in latitude degrees in the range [-90, 90].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleSouth = -90;
+
+ /**
+ * The east boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in longitude degrees in the range [-180, 180].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleEast = 180;
+
+ /**
+ * The north boundary of the bounding rectangle used for the quadtree tiling
+ * scheme. Specified in latitude degrees in the range [-90, 90].
+ *
+ * Only applicable if "Specify Tiling Scheme" is set to true.
+ */
+ double rectangleNorth = 90;
+
+ /**
+ * Set this to true to directly specify the minimum and maximum zoom levels
+ * available from the server. If false, the minimum and maximum zoom levels
+ * will be retrieved from the server's tilemapresource.xml file.
+ */
+ bool bSpecifyZoomLevels = false;
+
+ /**
+ * Minimum zoom level.
+ *
+ * Take care when specifying this that the number of tiles at the minimum
+ * level is small, such as four or less. A larger number is likely to result
+ * in rendering problems.
+ */
+ int32_t minimumLevel = 0;
+
+ /**
+ * Maximum zoom level.
+ */
+ int32_t maximumLevel = 25;
+
+ /**
+ * The pixel width of the image tiles.
+ */
+ int32_t tileWidth = 256;
+
+ /**
+ * The pixel height of the image tiles.
+ */
+ int32_t tileHeight = 256;
+
+ /**
+ * HTTP headers to be attached to each request made for this raster overlay.
+ */
+ std::map requestHeaders;
+
+ CesiumRasterOverlays::RasterOverlay* createOverlay(
+ const CesiumRasterOverlays::RasterOverlayOptions& options) override;
+ };
+}
diff --git a/src/vsgCs/jsonUtils.cpp b/src/vsgCs/jsonUtils.cpp
index c96faf5..d46a300 100644
--- a/src/vsgCs/jsonUtils.cpp
+++ b/src/vsgCs/jsonUtils.cpp
@@ -83,6 +83,27 @@ namespace vsgCs
JSONObjectFactory*,
const vsg::ref_ptr& object);
JSONObjectFactory::Registrar r("DebugColorizeTilesRasterOverlay", buildCsDebugColorizeTilesOverlay);
+
+ vsg::ref_ptr buildCsWebMapTileServiceRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object);
+ JSONObjectFactory::Registrar rWebMapTileServiceRasterOverlay("WebMapTileServiceRasterOverlay", buildCsWebMapTileServiceRasterOverlay);
+
+ vsg::ref_ptr buildCsWebMapServiceRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object);
+ JSONObjectFactory::Registrar rWebMapServiceRasterOverlay("WebMapServiceRasterOverlay", buildCsWebMapServiceRasterOverlay);
+
+ vsg::ref_ptr buildCsTileMapServiceRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object);
+ JSONObjectFactory::Registrar rTileMapServiceRasterOverlay("TileMapServiceRasterOverlay", buildCsTileMapServiceRasterOverlay);
+
+ vsg::ref_ptr buildCsUrlTemplateRasterOverlay(const rapidjson::Value& json,
+ JSONObjectFactory* factory,
+ const vsg::ref_ptr& object);
+ JSONObjectFactory::Registrar rUrlTemplateRasterOverlay("UrlTemplateRasterOverlay", buildCsUrlTemplateRasterOverlay);
+
vsg::ref_ptr buildStyling(const rapidjson::Value& json,
JSONObjectFactory*,
const vsg::ref_ptr&);
diff --git a/tests/overlay-tms.json b/tests/overlay-tms.json
new file mode 100644
index 0000000..35b6465
--- /dev/null
+++ b/tests/overlay-tms.json
@@ -0,0 +1,15 @@
+{
+ "Type": "World",
+ "tilesets": [
+ {
+ "Type": "Tileset",
+ "ionAssetID": 1,
+ "overlays": [
+ {
+ "Type": "TileMapServiceRasterOverlay",
+ "url": "https://readymap.org/readymap/tiles/1.0.0/7/tilemapresource.xml"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/overlay-urlTemplate.json b/tests/overlay-urlTemplate.json
new file mode 100644
index 0000000..baf26aa
--- /dev/null
+++ b/tests/overlay-urlTemplate.json
@@ -0,0 +1,15 @@
+{
+ "Type": "World",
+ "tilesets": [
+ {
+ "Type": "Tileset",
+ "ionAssetID": 1,
+ "overlays": [
+ {
+ "Type": "UrlTemplateRasterOverlay",
+ "url": "http://a.tile.opencyclemap.org/cycle/{z}/{x}/{reverseY}.png"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/overlay-wms.json b/tests/overlay-wms.json
new file mode 100644
index 0000000..4a40cc5
--- /dev/null
+++ b/tests/overlay-wms.json
@@ -0,0 +1,16 @@
+{
+ "Type": "World",
+ "tilesets": [
+ {
+ "Type": "Tileset",
+ "ionAssetID": 1,
+ "overlays": [
+ {
+ "Type": "WebMapServiceRasterOverlay",
+ "baseUrl": "https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WmsServer?",
+ "layers": "0"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/overlay-wmts.json b/tests/overlay-wmts.json
new file mode 100644
index 0000000..25f3c1f
--- /dev/null
+++ b/tests/overlay-wmts.json
@@ -0,0 +1,19 @@
+{
+ "Type": "World",
+ "tilesets": [
+ {
+ "Type": "Tileset",
+ "ionAssetID": 1,
+ "overlays": [
+ {
+ "Type": "WebMapTileServiceRasterOverlay",
+ "baseUrl": "https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/WMTS?",
+ "layer": "USGSTopo",
+ "style": "default",
+ "format": "image/png",
+ "tileMatrixSetID": "default028mm"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file