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