Merge remote-tracking branch 'origin/trouble-with-triplets' into gaussian-splats
This commit is contained in:
commit
9c41f33c83
|
|
@ -5,6 +5,12 @@
|
|||
##### Breaking Changes :mega:
|
||||
|
||||
- Restored vcpkg commit update to `2025.09.17`.
|
||||
- Removed `refreshTileProviderWithNewKey` from `BingMapsRasterOverlay` and `refreshTileProviderWithNewUrlAndHeaders` from `TileMapServiceRasterOverlay`. These were no longer used after the raster overlay refactor in `v0.52.0`.
|
||||
|
||||
##### Additions :tada:
|
||||
|
||||
- Added `AzureMapsRasterOverlay`.
|
||||
- Added `Uri::ensureTrailingSlash`, which is helpful when the `Uri` represents a base URL.
|
||||
|
||||
##### Additions :tada:
|
||||
|
||||
|
|
@ -14,6 +20,7 @@
|
|||
##### Fixes :wrench:
|
||||
|
||||
- Fixed a bug in `GoogleMapTilesRasterOverlay` that tried to parse credits from an erroneous viewport service response.
|
||||
- Fixed a bug with credits not showing on-screen when `showCreditsOnScreen` was enabled on `GoogleMapTilesRasterOverlay`.
|
||||
|
||||
### v0.52.1 - 2025-10-01
|
||||
|
||||
|
|
|
|||
|
|
@ -53,9 +53,16 @@ if (NOT VCPKG_TRIPLET)
|
|||
else()
|
||||
set(VCPKG_TRIPLET "${DETECTED_VCPKG_TRIPLET}")
|
||||
endif()
|
||||
if (NOT CESIUM_USE_EZVCPKG)
|
||||
set(VCPKG_TARGET_TRIPLET "${VCPKG_TRIPLET}")
|
||||
endif()
|
||||
|
||||
# If we're using ezvcpkg, ezvcpkg will update CMAKE_TOOLCHAIN_FILE to point to the vcpkg toolchain.
|
||||
# Which means that when we hit the `project` function call below, cmake will load the vcpkg
|
||||
# toolchain file. If VCPKG_TARGET_TRIPLET isn't set by that time, vcpkg will set it itself, and
|
||||
# maybe not to what we want. So set VCPKG_TARGET_TRIPLET explicit here so that we're sure to get
|
||||
# the right one.
|
||||
#
|
||||
# If we're _not_ using ezvcpkg, then we also must set VCPKG_TARGET_TRIPLET, but for a different reason.
|
||||
# VCPKG_TRIPLET is only an ezvcpkg thing, vcpkg itself only knows about VCPKG_TARGET_TRIPLET.
|
||||
set(VCPKG_TARGET_TRIPLET "${VCPKG_TRIPLET}")
|
||||
endif()
|
||||
|
||||
message(STATUS "VCPKG_TRIPLET ${VCPKG_TRIPLET}")
|
||||
|
|
@ -295,46 +302,42 @@ list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}")
|
|||
# they won't be visible in this scope nor any of the subdirectories for the actual libraries.
|
||||
#
|
||||
# However, for some of the vcpkg built libraries where they don't provide a prope cmake config file, we have to declare
|
||||
# and imporeted library target ourselves. This is the case for modp_b64::modp_b64, picosha2::picosha2 and earcut. In
|
||||
# an imported library target ourselves. This is the case for modp_b64::modp_b64, picosha2::picosha2 and earcut. In
|
||||
# these cases, we *do* have the somewhat ugly and verbose details in the extern/CMakeLists.txt file.
|
||||
#
|
||||
# XXX Above comment should be obsoleted by these first calls to
|
||||
# find_package, which resolve to our own modules that provide
|
||||
# targets. If needed, they can be installed with CMake config files
|
||||
# etc.
|
||||
find_package(zlib-ng REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(modp_b64 REQUIRED)
|
||||
|
||||
find_package(ada CONFIG REQUIRED)
|
||||
find_package(Async++ CONFIG REQUIRED)
|
||||
find_package(blend2d CONFIG REQUIRED)
|
||||
find_package(doctest CONFIG REQUIRED)
|
||||
find_package(draco CONFIG REQUIRED)
|
||||
find_package(expected-lite CONFIG REQUIRED)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
find_package(httplib CONFIG REQUIRED)
|
||||
find_package(Ktx CONFIG REQUIRED)
|
||||
find_package(libmorton CONFIG REQUIRED)
|
||||
find_package(libjpeg-turbo CONFIG REQUIRED)
|
||||
find_package(libmorton CONFIG REQUIRED)
|
||||
find_package(meshoptimizer CONFIG REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(s2 CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
find_package(spz CONFIG REQUIRED)
|
||||
find_package(tinyxml2 CONFIG REQUIRED)
|
||||
find_package(unofficial-sqlite3 CONFIG REQUIRED)
|
||||
find_package(WebP CONFIG REQUIRED)
|
||||
find_package(blend2d CONFIG REQUIRED)
|
||||
find_package(spz CONFIG REQUIRED)
|
||||
find_package(zlib-ng CONFIG REQUIRED)
|
||||
|
||||
# asmjit should not be included with iOS builds as iOS doesn't support JIT compilation.
|
||||
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
find_package(asmjit CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT CESIUM_DISABLE_CURL)
|
||||
find_package(CURL REQUIRED)
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT CESIUM_DISABLE_CURL)
|
||||
find_package(CURL REQUIRED)
|
||||
endif()
|
||||
|
|
@ -388,7 +391,6 @@ if(CESIUM_INSTALL_STATIC_LIBS AND CESIUM_INSTALL_HEADERS)
|
|||
DESTINATION ${CMAKE_INSTALL_DATADIR}/cesium-native/cmake)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cmake/modules/Findzlib-ng.cmake"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cmake/modules/Findmodp_b64.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/cesium-native/cmake)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,225 @@
|
|||
#pragma once
|
||||
|
||||
#include <CesiumAsync/IAssetRequest.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
|
||||
/**
|
||||
* @brief Supported values for @ref AzureMapsSessionParameters::tilesetId. See
|
||||
* the [official
|
||||
* documentation](https://learn.microsoft.com/en-us/rest/api/maps/render/get-map-tile?tabs=HTTP#tilesetid)
|
||||
* for all standard values. Note that some tileset IDs return vector data, which
|
||||
* is currently unsupported.
|
||||
*/
|
||||
struct AzureMapsTilesetId {
|
||||
/**
|
||||
* @brief All layers with Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string baseRoad = "microsoft.base.road";
|
||||
|
||||
/**
|
||||
* @brief All layers with Azure Maps' dark grey style.
|
||||
*/
|
||||
inline static const std::string baseDarkGrey = "microsoft.base.darkgrey";
|
||||
|
||||
/**
|
||||
* @brief Label data in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string baseLabelsRoad = "microsoft.base.labels.road";
|
||||
|
||||
/**
|
||||
* @brief Label data in Azure Maps' dark grey style.
|
||||
*/
|
||||
inline static const std::string baseLabelsDarkGrey =
|
||||
"microsoft.base.labels.darkgrey";
|
||||
|
||||
/**
|
||||
* @brief Road, boundary and label data in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string baseHybridRoad = "microsoft.base.hybrid.road";
|
||||
|
||||
/**
|
||||
* @brief Road, boundary and label data in Azure Maps' dark grey style.
|
||||
*/
|
||||
inline static const std::string baseHybridDarkGrey =
|
||||
"microsoft.base.hybrid.darkgrey";
|
||||
|
||||
/**
|
||||
* @brief A combination of satellite or aerial imagery. Only available in S1
|
||||
* and G2 pricing SKU.
|
||||
*/
|
||||
inline static const std::string imagery = "microsoft.imagery";
|
||||
|
||||
/**
|
||||
* @brief Shaded relief and terra layers.
|
||||
*/
|
||||
inline static const std::string terra = "microsoft.terra.main";
|
||||
|
||||
/**
|
||||
* @brief Weather radar tiles. Latest weather radar images including areas of
|
||||
* rain, snow, ice and mixed conditions. For more information on the Azure
|
||||
* Maps Weather service coverage, see [Azure Maps weather services
|
||||
* coverage](https://learn.microsoft.com/en-us/azure/azure-maps/weather-coverage).
|
||||
* For more information on Radar data, see [Weather services in Azure
|
||||
* Maps](https://learn.microsoft.com/en-us/azure/azure-maps/weather-services-concepts#radar-images).
|
||||
*/
|
||||
inline static const std::string weatherRadar = "microsoft.weather.radar.main";
|
||||
|
||||
/**
|
||||
* @brief Weather infrared tiles. Latest Infrared Satellite images show
|
||||
* clouds by their temperature. For more information on the Azure Maps Weather
|
||||
* service coverage, see [Azure Maps weather services
|
||||
* coverage](https://learn.microsoft.com/en-us/azure/azure-maps/weather-coverage).
|
||||
* For more information on Radar data, see [Weather services in Azure
|
||||
* Maps](https://learn.microsoft.com/en-us/azure/azure-maps/weather-services-concepts#radar-images).
|
||||
*/
|
||||
inline static const std::string weatherInfrared =
|
||||
"microsoft.weather.infrared.main";
|
||||
|
||||
/**
|
||||
* @brief Absolute traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficAbsolute =
|
||||
"microsoft.traffic.absolute.main";
|
||||
|
||||
/**
|
||||
* @brief Relative traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficRelativeMain =
|
||||
"microsoft.traffic.relative.main";
|
||||
|
||||
/**
|
||||
* @brief Relative traffic tiles in Azure Maps' dark style.
|
||||
*/
|
||||
inline static const std::string trafficRelativeDark =
|
||||
"microsoft.traffic.relative.dark";
|
||||
|
||||
/**
|
||||
* @brief Delay traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficDelay = "microsoft.traffic.delay.main";
|
||||
|
||||
/**
|
||||
* @brief Reduced traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficReduced =
|
||||
"microsoft.traffic.reduced.main";
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Session parameters for an Azure Maps overlay.
|
||||
*/
|
||||
struct AzureMapsSessionParameters {
|
||||
/**
|
||||
* @brief The Azure Maps subscription key to use.
|
||||
*/
|
||||
std::string key;
|
||||
|
||||
/**
|
||||
* @brief The version number of Azure Maps API.
|
||||
*/
|
||||
std::string apiVersion{"2024-04-01"};
|
||||
|
||||
/**
|
||||
* @brief A tileset is a collection of raster or vector data broken up into a
|
||||
* uniform grid of square tiles at preset zoom levels. Every tileset has a
|
||||
* tilesetId to use when making requests. The tilesetId for tilesets created
|
||||
* using [Azure Maps Creator](https://aka.ms/amcreator) are generated through
|
||||
* the [Tileset Create
|
||||
* API](https://learn.microsoft.com/en-us/rest/api/maps-creator/tileset).
|
||||
*
|
||||
* The supported ready-to-use tilesets supplied by Azure Maps are listed
|
||||
* [here](https://learn.microsoft.com/en-us/rest/api/maps/render/get-map-tile?view=rest-maps-2025-01-01&tabs=HTTP#tilesetid).
|
||||
*/
|
||||
std::string tilesetId{AzureMapsTilesetId::baseRoad};
|
||||
|
||||
/**
|
||||
* @brief The language in which search results should be returned. Should be
|
||||
* one of the supported [IETF language
|
||||
* tags](https://en.wikipedia.org/wiki/IETF_language_tag), case insensitive.
|
||||
* When data in the specified language is not available for a specific field,
|
||||
* default language is used.
|
||||
*
|
||||
* Refer to [Supported
|
||||
* Languages](https://learn.microsoft.com/en-us/azure/azure-maps/supported-languages)
|
||||
* for details.
|
||||
*/
|
||||
std::string language{"en-US"};
|
||||
|
||||
/**
|
||||
* @brief The view (also called the "user region") of a certain country/region
|
||||
* for which to show the correct maps. Quoting the Azure Maps' documentation:
|
||||
*
|
||||
* "Different countries/regions have different views of such regions, and the
|
||||
* View parameter allows your application to comply with the view required by
|
||||
* the country/region your application will be serving. By default, the View
|
||||
* parameter is set to "Unified" even if you haven't defined it in the
|
||||
* request. It is your responsibility to determine the location of your users,
|
||||
* and then set the View parameter correctly for that location. Alternatively,
|
||||
* you have the option to set 'View=Auto', which will return the map data
|
||||
* based on the IP address of the request. The View parameter in Azure Maps
|
||||
* must be used in compliance with applicable laws, including those regarding
|
||||
* mapping, of the country/region where maps, images and other data and third
|
||||
* party content that you are authorized to access via Azure Maps is made
|
||||
* available. Example: view=IN."
|
||||
*
|
||||
* Refer to [Supported Views](https://aka.ms/AzureMapsLocalizationViews) for
|
||||
* details and to see the available Views.
|
||||
*/
|
||||
std::string view{"US"};
|
||||
|
||||
/**
|
||||
* @brief Whether or not the @ref AzureMapsRasterOverlay should show the
|
||||
* Azure Maps logo.
|
||||
*
|
||||
* Azure requires the logo to be shown, so setting this to false is only
|
||||
* valid when something else is already showing the logo.
|
||||
*/
|
||||
bool showLogo = true;
|
||||
|
||||
/**
|
||||
* @brief The base URL for the Azure Maps API.
|
||||
*/
|
||||
std::string apiBaseUrl{"https://atlas.microsoft.com/"};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A @ref RasterOverlay that retrieves imagery from the Azure Maps API.
|
||||
*/
|
||||
class CESIUMRASTEROVERLAYS_API AzureMapsRasterOverlay final
|
||||
: public RasterOverlay {
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a new instance.
|
||||
*
|
||||
* @param name The user-given name of this overlay layer.
|
||||
* @param sessionParameters The session parameters for this overlay.
|
||||
* @param overlayOptions The @ref RasterOverlayOptions for this instance.
|
||||
*/
|
||||
AzureMapsRasterOverlay(
|
||||
const std::string& name,
|
||||
const AzureMapsSessionParameters& sessionParameters,
|
||||
const RasterOverlayOptions& overlayOptions = {});
|
||||
virtual ~AzureMapsRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const override;
|
||||
|
||||
private:
|
||||
AzureMapsSessionParameters _sessionParameters;
|
||||
};
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <CesiumAsync/IAssetRequest.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
||||
|
|
@ -116,20 +115,6 @@ public:
|
|||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const override;
|
||||
|
||||
/**
|
||||
* @brief Refresh a previously-created tile provider using a new key.
|
||||
*
|
||||
* Calling this method on a tile provider that was not created by this \ref
|
||||
* BingMapsRasterOverlay will lead to undefined behavior.
|
||||
*
|
||||
* @param pProvider The previously-created tile provider.
|
||||
* @param newKey The new key to use.
|
||||
*/
|
||||
CesiumAsync::Future<void> refreshTileProviderWithNewKey(
|
||||
const CesiumUtility::IntrusivePointer<RasterOverlayTileProvider>&
|
||||
pProvider,
|
||||
const std::string& newKey);
|
||||
|
||||
private:
|
||||
static const std::string BING_LOGO_HTML;
|
||||
|
||||
|
|
|
|||
|
|
@ -252,8 +252,8 @@ struct GoogleMapTilesNewSessionParameters {
|
|||
};
|
||||
|
||||
/**
|
||||
* @brief A `RasterOverlay` that retrieves imagery from the [Google Maps Tiles
|
||||
* API](https://developers.google.com/maps/documentation/tile).
|
||||
* @brief A @ref RasterOverlay that retrieves imagery from the [Google Maps
|
||||
* Tiles API](https://developers.google.com/maps/documentation/tile).
|
||||
*/
|
||||
class CESIUMRASTEROVERLAYS_API GoogleMapTilesRasterOverlay
|
||||
: public RasterOverlay {
|
||||
|
|
|
|||
|
|
@ -126,11 +126,10 @@ private:
|
|||
};
|
||||
|
||||
/** @private */
|
||||
struct Bing {
|
||||
std::string key;
|
||||
struct Azure2D {
|
||||
std::string url;
|
||||
std::string mapStyle;
|
||||
std::string culture;
|
||||
std::string tilesetId;
|
||||
std::string key;
|
||||
};
|
||||
|
||||
/** @private */
|
||||
|
|
@ -144,7 +143,21 @@ private:
|
|||
uint32_t tileHeight;
|
||||
};
|
||||
|
||||
std::variant<std::monostate, TileMapService, Bing, Google2D> options{};
|
||||
/** @private */
|
||||
struct Bing {
|
||||
std::string key;
|
||||
std::string url;
|
||||
std::string mapStyle;
|
||||
std::string culture;
|
||||
};
|
||||
|
||||
std::variant<std::monostate, TileMapService, Azure2D, Google2D, Bing>
|
||||
options{};
|
||||
|
||||
void parseAzure2DOptions(const rapidjson::Document& ionResponse);
|
||||
void parseGoogle2DOptions(const rapidjson::Document& ionResponse);
|
||||
void parseBingOptions(const rapidjson::Document& ionResponse);
|
||||
void parseTileMapServiceOptions(const rapidjson::Document& ionResponse);
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, ExternalAssetEndpoint> endpointCache;
|
||||
|
|
|
|||
|
|
@ -115,27 +115,6 @@ public:
|
|||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const override;
|
||||
|
||||
/**
|
||||
* @brief Refresh a previously-created tile provider using a new URL and
|
||||
* request headers. This is primarily useful to refresh an access token after
|
||||
* it expires.
|
||||
*
|
||||
* Calling this method on a tile provider that was not created by this \ref
|
||||
* TileMapServiceRasterOverlay will lead to undefined behavior.
|
||||
*
|
||||
* @param pProvider The previously-created tile provider.
|
||||
* @param newUrl The new URL to use. If `std::nullopt`, the existing URL is
|
||||
* unchanged.
|
||||
* @param newHeaders The new request headers to use. If `std::nullopt`, the
|
||||
* existing headers are unchanged.
|
||||
*/
|
||||
CesiumAsync::Future<void> refreshTileProviderWithNewUrlAndHeaders(
|
||||
const CesiumUtility::IntrusivePointer<RasterOverlayTileProvider>&
|
||||
pProvider,
|
||||
const std::optional<std::string>& newUrl,
|
||||
const std::optional<std::vector<CesiumAsync::IAssetAccessor::THeader>>&
|
||||
newHeaders);
|
||||
|
||||
private:
|
||||
std::string _url;
|
||||
std::vector<CesiumAsync::IAssetAccessor::THeader> _headers;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,632 @@
|
|||
#include <CesiumAsync/Future.h>
|
||||
#include <CesiumAsync/IAssetAccessor.h>
|
||||
#include <CesiumAsync/IAssetResponse.h>
|
||||
#include <CesiumGeometry/QuadtreeTileID.h>
|
||||
#include <CesiumGeometry/Rectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
#include <CesiumJsonReader/JsonObjectJsonHandler.h>
|
||||
#include <CesiumJsonReader/JsonReader.h>
|
||||
#include <CesiumRasterOverlays/AzureMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/CreditReferencer.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/ErrorList.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/JsonHelpers.h>
|
||||
#include <CesiumUtility/JsonValue.h>
|
||||
#include <CesiumUtility/Uri.h>
|
||||
#include <CesiumUtility/joinToString.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace CesiumAsync;
|
||||
using namespace CesiumGeometry;
|
||||
using namespace CesiumGeospatial;
|
||||
using namespace CesiumJsonReader;
|
||||
using namespace CesiumUtility;
|
||||
|
||||
namespace {
|
||||
std::unordered_map<std::string, std::vector<std::byte>> sessionCache;
|
||||
} // namespace
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
const std::string AZURE_MAPS_LOGO_HTML =
|
||||
"<img alt=\"Microsoft Azure\" "
|
||||
"src=\"data:image/"
|
||||
"png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAM0AAAAnCAYAAACsY8yNAAAAAXNSR0IB2cksfwAAAAlwSFlzAA"
|
||||
"ALEwAACxMBAJqcGAAACaFJREFUeJztWweMVUUU3QUUUURBUIqBFZBFUbGgQQFDlCi2KAr2Hl2w"
|
||||
"oRRFxQgaVDYrxIINBCyASrHFFRCU2KMIlgixF4wVdBELosD1HuaO7/757/333vJ1/"
|
||||
"8c5ycnfd+fOvGl35s6dtyUlHh4eHh4eHh4eHh4eHh4e/2/8ckL7mWm4pl/"
|
||||
"7GT+d2q7lmLklZ4x6rmRmGt4wv+"
|
||||
"TYum6vh8dmgw2B0pCNZh0bze5sNJVsCJSSV9Z1ez08NhveaDw8UsIbjYdHSnij2TJBRE2ZBzB7"
|
||||
"MTvVdX22KGzpRsMTphVzMLPDf/"
|
||||
"3uugK39RLmV8yNZPBVXddpi0IhGQ0P7vHMvxRXMJvFtYF1Zjr5hom8DfM7mTjfM1vnq98KFdzG"
|
||||
"E5l/Uia+yVPZw1Uf/46dLB/"
|
||||
"lFh0KzGj6UTb6x+"
|
||||
"RpK4OocaWk7cfcILL1zL3z2XeFBm5fPebr0l7sMmczd2R2ZjZg7sMcz5xci7KR/y2nnyv/"
|
||||
"jXYUPIrAaGZjMuTIMyEkjzWarZnXM99g3oTnfPdfIYHMOeYb6YP3nbRy5jpJW1CLsrsx10p+"
|
||||
"uxAtYzbKXwuKBAVsNHaA4FZ1idBvwvxC9Fa7RvN/"
|
||||
"A7e7BfMH6YNFTloX1T+1MZp7Vf5n5RduYI/8taBIUMBGM40C33xchP4pauW71TUa/"
|
||||
"m3IPJNZwTyN2cDJD5ejB3MM80HmI8xK5uFWV95RIb9wf/"
|
||||
"qKzlXMrVRZcH2GMCcxHybjBp3D3C6i7nsyR4rudCmzd4jetlL3KtGdLO/"
|
||||
"e39E7nzmMuUb64EOpt+Vo1T/LlbxrrjGRsrdn/"
|
||||
"ip5n8O7tQFF5NnLeX8onT4GG4a036adpOTHKDl22AOZN0o/"
|
||||
"7qr0OjCHMu8m45VcziyLa3NOFLDRnM58W/"
|
||||
"7+lFnf0S1lzpH0xWQiRhbWaODPfy2yz0lNYP67GXMq82fKxk/"
|
||||
"MtqL3ocg+Zl6kJs+m8pjbMK+jIOCggXPUIuYhTt37q3ppzHf0Dma+TNkHe2AVGSPdVnR/"
|
||||
"C9FJgthdmTLH5Swyi80KeYZHsFNInssTvHut08dAU6ecVirtHSVfoOSXkvFILHqKDuqqo4gWH5"
|
||||
"EywNQoYKPBSjJcPR/q6JZRMOHRaYmNhswONIcy8RnzRSkTE6G9M6BrKXAZ/"
|
||||
"ymPeZdTzifMJZQ50b8lWd3IBC5+FDkCGLOYj4lsgWpfRzLGa/"
|
||||
"EHmbPZCiXDDlsl+v+m0cwSXdSxlchuUmVUhOTBmKwLoZ3A+"
|
||||
"B3o9DFQG6OpcdrUk8wCZwNEcN3hXt5PwbigLgfGtT0UP/"
|
||||
"ffbUoarh5QNnHVGW13GVtdOmDMvJIpKXlUzOC4RrM7BSs7ttd6Sne8yDGRd6Z0RoMVer3IsRL1"
|
||||
"sGWTcQcGosyQAYXu4TKQuDTcV5WD95yo6gejfkLlnSjyQUo2QunDkHvL3whgLFJ69zCbS1p9yt"
|
||||
"zxYOS7Sb3bMVeK/CUyRm3ZTZX3gpL/"
|
||||
"42JGjElz9S6cZUpFrscm0RmJ9Y6mIBhRTRKYoc03Giwu8Exaow/JuI/"
|
||||
"2bIdFpovK14OCxfahJPXOxvSaNmlZb9qqBmvm1G/"
|
||||
"y+5OlrVOycUynukZTSsGhEx1TLnqNKPDdbxVZGqNZLjIM+"
|
||||
"pExdbIDmnXo5ecH1DvDVttmFKxsG6Q+2m2ZSM45S/IhVG6NETtXYycd/"
|
||||
"VKpyhkk8rwHAihzRznPqcNLqm05vzogs4jYuqFPy1Ta5hrNSCdPhUrrF1KX+ZJWy/"
|
||||
"ur6TWrU3Ils+"
|
||||
"Nfz5SO3ji3pCYlL4vp2AyjERlWELuljxDZafKMVaubyBIZjchsyPQVCpm0Tp3sgGLFaqLk2A0+"
|
||||
"UPXoHJF/iapXdzIBALvSbZA6XEiyk0ies1SeaRHlHq107hVZXo2GzOK0TPLA/"
|
||||
"cMq3UbxFlXmhBzlNCZzdWD7qndEHwO1MRrXddeRPgRZ7nP4iaRtTNIP2ZheQyn5J7PT+"
|
||||
"uqSSprH9UvHVGcakbWkYHK+SuYQ+"
|
||||
"qQ8v8fcRvSSGk250ns0rnvUgOLwuLWS70DGXQPgM7eJyD9Pva8PmRUad0f6QhaLAi4Ou0qewSo"
|
||||
"tKnJ4kNKZLbJ8Gw1cOrtTor5fSj9a6sM3AiVRkcJrVXun5OhjoDZG08XJM5sSIkk/"
|
||||
"ZKPAjUbkQ0WGAcQtt3VdhimdpEbTUelVx3UPRRsNVs8vJA2rcFlE/"
|
||||
"lfU+7oreVcyQYRfVToCBjsxL1ay+yLKPczVofwbzXhKDhh+"
|
||||
"35AysDtZg3mNHFfT6WPANZrWKi2p0Tyi0hBMGhzFJP2QjeIwmnYUrHir5BeTbQ+"
|
||||
"lk9RocGC2h1FM+"
|
||||
"rKYOkUZDe5sXo2ZMA1VfTFxWjjpONTDZXtX1f08ynS9MNHCzj1DlM4lIktqNAtztVn0cR6zrhm"
|
||||
"CLaMjOEOVe49TBiKFb0oaIm/"
|
||||
"7RrxruSqjzEk7QKUlNRp93su4z8oPisBoJG0+"
|
||||
"ZQIumo6mpQkEVCtdBBrcS08cxJvK36FGI2nnqnKwo7RQaTAqHTKfJvJDyPkIlZ+"
|
||||
"vVnowBkQD7eSHsZ3s6MMA7C6HxaOTyHMZTWf1jo9yjYPoX0DBjj43h14zpYdzXzuRY0F4XL0z8"
|
||||
"jzLaQuV3mAnbZJKS2o0fVXapkhhyDsRFcy6X0qG4jEaHI713UdPJz2N0eDSUF9GYqWHK4KV82n"
|
||||
"mL5R9TxNmNLjY1KskJnKVlIOzjJ1M2G06Sx58BQA3bILUeQQFB1PsgDZCOFCVC/"
|
||||
"cPExBnodskvwVC8TYMnMtosMvqeyYckPElROglH5mbf4uLY8btedHDjjtcZOeq9q+R+"
|
||||
"s8IIXbj8ykI9qDvx5H5uuExyryYTGo08CYWq/"
|
||||
"S3pJ8RVELIfyqZYEzo51nxKB6jwQS1W33WSknpvwg4lII7DRf47D3WaCQddyTLIsoBECzoo/"
|
||||
"RHRughkjbcKRufhYR9DWD1MbkaKf1Io5F0HMjd2/GsMSETfNFfh+f8lwrKNPClInO/PI/"
|
||||
"Cprsi5lMRbbxNPScyGtUXb1M00K7yXO2KRmEZDb5XqhJmhXBZdpykZa2OZNwem7e3yBAyvU5k1"
|
||||
"1D2TlEucqyqCA3j/PAQmW+h7MXbVZIfv/"
|
||||
"Xd94oOImmYODiALpaycLEJt6tVyDtvJuNuLiXj1iEMegQ5X3OTcfGwK95OZjXHJMDdyB1kXBD3"
|
||||
"0yIEJ0ZJfQeF1BP9MVTKQh2rKfx7t71VX14R1mZHv6XSHyvvqUpI28/oQ5zn8A0gvta4U/"
|
||||
"qkqdIdot5ZoeS7RNQLruOlUh7GBTvOM9L/"
|
||||
"vaLGMx4FZDQeHsUBbzQeHinhjcbDIyW80Xh4pIQ3Gg8PDw8PDw8PDw8PDw8PDw8PDw8Pj9T4G6"
|
||||
"U/URjRT3IrAAAAAElFTkSuQmCC\"/>";
|
||||
|
||||
namespace {
|
||||
Rectangle createRectangle(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
pOwner->getOptions().ellipsoid);
|
||||
}
|
||||
|
||||
QuadtreeTilingScheme createTilingScheme(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return QuadtreeTilingScheme(createRectangle(pOwner), 1, 1);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class AzureMapsRasterOverlayTileProvider final
|
||||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
AzureMapsRasterOverlayTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const std::string& baseUrl,
|
||||
const std::string& apiVersion,
|
||||
const std::string& tilesetId,
|
||||
const std::string& key,
|
||||
const std::string& tileEndpoint,
|
||||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel,
|
||||
uint32_t imageSize,
|
||||
bool showLogo);
|
||||
|
||||
virtual ~AzureMapsRasterOverlayTileProvider() = default;
|
||||
|
||||
void update(const AzureMapsRasterOverlayTileProvider& newProvider) {
|
||||
this->_baseUrl = newProvider._baseUrl;
|
||||
this->_apiVersion = newProvider._apiVersion;
|
||||
this->_tilesetId = newProvider._tilesetId;
|
||||
this->_key = newProvider._key;
|
||||
this->_tileEndpoint = newProvider._tileEndpoint;
|
||||
}
|
||||
|
||||
CesiumAsync::Future<void> loadCredits();
|
||||
|
||||
virtual void addCredits(
|
||||
CesiumUtility::CreditReferencer& creditReferencer) noexcept override;
|
||||
|
||||
protected:
|
||||
virtual CesiumAsync::Future<LoadedRasterOverlayImage> loadQuadtreeTileImage(
|
||||
const CesiumGeometry::QuadtreeTileID& tileID) const override;
|
||||
|
||||
private:
|
||||
std::string _baseUrl;
|
||||
std::string _apiVersion;
|
||||
std::string _tilesetId;
|
||||
std::string _key;
|
||||
std::string _tileEndpoint;
|
||||
std::optional<Credit> _azureCredit;
|
||||
std::vector<Credit> _credits;
|
||||
bool _showCreditsOnScreen;
|
||||
};
|
||||
|
||||
AzureMapsRasterOverlay::AzureMapsRasterOverlay(
|
||||
const std::string& name,
|
||||
const AzureMapsSessionParameters& sessionParameters,
|
||||
const RasterOverlayOptions& overlayOptions)
|
||||
: RasterOverlay(name, overlayOptions),
|
||||
_sessionParameters(sessionParameters) {
|
||||
Uri baseUrl(this->_sessionParameters.apiBaseUrl);
|
||||
baseUrl.ensureTrailingSlash();
|
||||
this->_sessionParameters.apiBaseUrl = baseUrl.toString();
|
||||
}
|
||||
|
||||
AzureMapsRasterOverlay::~AzureMapsRasterOverlay() = default;
|
||||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
AzureMapsRasterOverlay::createTileProvider(
|
||||
const AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
Uri tilesetUri(this->_sessionParameters.apiBaseUrl, "map/tileset");
|
||||
|
||||
UriQuery tilesetQuery(tilesetUri);
|
||||
tilesetQuery.setValue("api-version", this->_sessionParameters.apiVersion);
|
||||
tilesetQuery.setValue("tilesetId", this->_sessionParameters.tilesetId);
|
||||
tilesetQuery.setValue("subscription-key", this->_sessionParameters.key);
|
||||
tilesetQuery.setValue("language", this->_sessionParameters.language);
|
||||
tilesetQuery.setValue("view", this->_sessionParameters.view);
|
||||
tilesetUri.setQuery(tilesetQuery.toQueryString());
|
||||
|
||||
std::string tilesetUrl = std::string(tilesetUri.toString());
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
auto handleResponse =
|
||||
[pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
sessionParameters = this->_sessionParameters](
|
||||
const std::shared_ptr<IAssetRequest>& pRequest,
|
||||
const std::span<const std::byte>& data) -> CreateTileProviderResult {
|
||||
JsonObjectJsonHandler handler{};
|
||||
ReadJsonResult<JsonValue> response = JsonReader::readJson(data, handler);
|
||||
|
||||
if (!response.value) {
|
||||
ErrorList errorList{};
|
||||
errorList.errors = std::move(response.errors);
|
||||
errorList.warnings = std::move(response.warnings);
|
||||
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = errorList.format("Failed to parse response from Azure "
|
||||
"Maps tileset API service:")});
|
||||
}
|
||||
|
||||
if (!response.value->isObject()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service was not a "
|
||||
"JSON object."});
|
||||
}
|
||||
const JsonValue::Object& responseObject = response.value->getObject();
|
||||
|
||||
uint32_t tileSize = 256u;
|
||||
uint32_t minimumLevel = 0u;
|
||||
uint32_t maximumLevel = 22u;
|
||||
|
||||
// "tileSize" is an optional enum property that is delivered as a string.
|
||||
std::string tileSizeEnum = "256";
|
||||
auto it = responseObject.find("tileSize");
|
||||
if (it != responseObject.end() && it->second.isString()) {
|
||||
tileSizeEnum = it->second.getString();
|
||||
}
|
||||
|
||||
try {
|
||||
tileSize = static_cast<uint32_t>(std::stoul(tileSizeEnum));
|
||||
} catch (std::exception&) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'tileSize' property."});
|
||||
}
|
||||
|
||||
it = responseObject.find("minzoom");
|
||||
if (it != responseObject.end() && it->second.isNumber()) {
|
||||
minimumLevel = it->second.getSafeNumberOrDefault<uint32_t>(0);
|
||||
} else if (it != responseObject.end()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'minzoom' property."});
|
||||
}
|
||||
|
||||
it = responseObject.find("maxzoom");
|
||||
if (it != responseObject.end() && it->second.isNumber()) {
|
||||
maximumLevel = it->second.getSafeNumberOrDefault<uint32_t>(0);
|
||||
} else if (it != responseObject.end()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'maxzoom' property."});
|
||||
}
|
||||
|
||||
std::vector<std::string> tiles;
|
||||
it = responseObject.find("tiles");
|
||||
if (it != responseObject.end()) {
|
||||
tiles = it->second.getArrayOfStrings(std::string());
|
||||
}
|
||||
|
||||
if (tiles.empty()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'tiles' property."});
|
||||
}
|
||||
|
||||
std::string tileEndpoint;
|
||||
for (const std::string& endpoint : tiles) {
|
||||
// Azure Maps documentation: "If multiple endpoints are specified, clients
|
||||
// may use any combination of endpoints. All endpoints MUST return the
|
||||
// same content for the same URL."
|
||||
// This just picks the first non-empty string endpoint.
|
||||
if (!endpoint.empty()) {
|
||||
tileEndpoint = endpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tileEndpoint.empty()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::TileProvider,
|
||||
pRequest,
|
||||
"Azure Maps returned no valid endpoints for the given tilesetId."});
|
||||
}
|
||||
|
||||
std::optional<Credit> topLevelCredit;
|
||||
|
||||
it = responseObject.find("attribution");
|
||||
if (it != responseObject.end() && it->second.isString()) {
|
||||
topLevelCredit = pCreditSystem->createCredit(
|
||||
it->second.getString(),
|
||||
pOwner->getOptions().showCreditsOnScreen);
|
||||
}
|
||||
|
||||
auto* pProvider = new AzureMapsRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
topLevelCredit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
sessionParameters.apiBaseUrl,
|
||||
sessionParameters.apiVersion,
|
||||
sessionParameters.tilesetId,
|
||||
sessionParameters.key,
|
||||
tileEndpoint,
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
tileSize,
|
||||
sessionParameters.showLogo);
|
||||
|
||||
// Start loading credits, but don't wait for the load to finish.
|
||||
pProvider->loadCredits();
|
||||
|
||||
return pProvider;
|
||||
};
|
||||
|
||||
auto cacheResultIt = sessionCache.find(tilesetUrl);
|
||||
if (cacheResultIt != sessionCache.end()) {
|
||||
return asyncSystem.createResolvedFuture(
|
||||
handleResponse(nullptr, std::span<std::byte>(cacheResultIt->second)));
|
||||
}
|
||||
|
||||
return pAssetAccessor->get(asyncSystem, tilesetUrl)
|
||||
.thenInMainThread(
|
||||
[tilesetUrl,
|
||||
handleResponse](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
-> CreateTileProviderResult {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
|
||||
if (!pResponse) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::TileProvider,
|
||||
pRequest,
|
||||
"No response received from Azure Maps imagery tileset "
|
||||
"service."});
|
||||
}
|
||||
|
||||
if (pResponse->statusCode() < 200 ||
|
||||
pResponse->statusCode() >= 300) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = fmt::format(
|
||||
"Azure Maps API tileset request service returned "
|
||||
"HTTP status code {}.",
|
||||
pResponse->statusCode())});
|
||||
}
|
||||
|
||||
CreateTileProviderResult handleResponseResult =
|
||||
handleResponse(pRequest, pResponse->data());
|
||||
|
||||
// If the response successfully created a tile provider, cache it.
|
||||
if (handleResponseResult) {
|
||||
sessionCache[tilesetUrl] = std::vector<std::byte>(
|
||||
pResponse->data().begin(),
|
||||
pResponse->data().end());
|
||||
}
|
||||
|
||||
return handleResponseResult;
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
CesiumAsync::Future<rapidjson::Document> fetchAttributionData(
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const std::string& apiBaseUrl,
|
||||
const std::string& apiVersion,
|
||||
const std::string& tilesetId,
|
||||
const std::string& key,
|
||||
uint32_t zoom,
|
||||
const Rectangle& rectangleDegrees) {
|
||||
std::vector<std::string> bounds(4);
|
||||
bounds[0] = std::to_string(rectangleDegrees.minimumX); // west
|
||||
bounds[1] = std::to_string(rectangleDegrees.minimumY); // south
|
||||
bounds[2] = std::to_string(rectangleDegrees.maximumX); // east
|
||||
bounds[3] = std::to_string(rectangleDegrees.maximumY); // north
|
||||
|
||||
Uri attributionUri(apiBaseUrl, "map/attribution", true);
|
||||
|
||||
UriQuery query(attributionUri);
|
||||
query.setValue("api-version", apiVersion);
|
||||
query.setValue("subscription-key", key);
|
||||
query.setValue("tilesetId", tilesetId);
|
||||
query.setValue("zoom", std::to_string(zoom));
|
||||
query.setValue("bounds", joinToString(bounds, ","));
|
||||
attributionUri.setQuery(query.toQueryString());
|
||||
|
||||
return pAssetAccessor
|
||||
->get(asyncSystem, std::string(attributionUri.toString()))
|
||||
.thenInMainThread(
|
||||
[pLogger](const std::shared_ptr<IAssetRequest>& pRequest)
|
||||
-> rapidjson::Document {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
rapidjson::Document document;
|
||||
|
||||
if (!pResponse) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
pLogger,
|
||||
"No response received from Azure Maps API attribution "
|
||||
"service.");
|
||||
return document;
|
||||
}
|
||||
|
||||
if (pResponse->statusCode() < 200 ||
|
||||
pResponse->statusCode() >= 300) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
pLogger,
|
||||
"Error response {} received from Azure Maps API attribution "
|
||||
"service URL {}.",
|
||||
pResponse->statusCode(),
|
||||
pRequest->url());
|
||||
return document;
|
||||
}
|
||||
|
||||
document.Parse(
|
||||
reinterpret_cast<const char*>(pResponse->data().data()),
|
||||
pResponse->data().size());
|
||||
|
||||
if (document.HasParseError()) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
pLogger,
|
||||
"Error when parsing Azure Maps API attribution service JSON "
|
||||
"from URL {}, error code {} at byte offset {}.",
|
||||
pRequest->url(),
|
||||
document.GetParseError(),
|
||||
document.GetErrorOffset());
|
||||
}
|
||||
|
||||
return document;
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AzureMapsRasterOverlayTileProvider::AzureMapsRasterOverlayTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const std::string& baseUrl,
|
||||
const std::string& apiVersion,
|
||||
const std::string& tilesetId,
|
||||
const std::string& key,
|
||||
const std::string& tileEndpoint,
|
||||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel,
|
||||
uint32_t imageSize,
|
||||
bool showLogo)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
WebMercatorProjection(pOwner->getOptions().ellipsoid),
|
||||
createTilingScheme(pOwner),
|
||||
createRectangle(pOwner),
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
imageSize,
|
||||
imageSize),
|
||||
_baseUrl(baseUrl),
|
||||
_apiVersion(apiVersion),
|
||||
_tilesetId(tilesetId),
|
||||
_key(key),
|
||||
_tileEndpoint(tileEndpoint),
|
||||
_azureCredit(),
|
||||
_credits(),
|
||||
_showCreditsOnScreen(pOwner->getOptions().showCreditsOnScreen) {
|
||||
if (pCreditSystem && showLogo) {
|
||||
this->_azureCredit =
|
||||
pCreditSystem->createCredit(AZURE_MAPS_LOGO_HTML, true);
|
||||
}
|
||||
}
|
||||
|
||||
CesiumAsync::Future<LoadedRasterOverlayImage>
|
||||
AzureMapsRasterOverlayTileProvider::loadQuadtreeTileImage(
|
||||
const CesiumGeometry::QuadtreeTileID& tileID) const {
|
||||
Uri uri(CesiumUtility::Uri::substituteTemplateParameters(
|
||||
this->_tileEndpoint,
|
||||
[this, &tileID](const std::string& key) {
|
||||
if (key == "z") {
|
||||
return std::to_string(tileID.level);
|
||||
}
|
||||
if (key == "x") {
|
||||
return std::to_string(tileID.x);
|
||||
}
|
||||
if (key == "y") {
|
||||
return std::to_string(
|
||||
tileID.computeInvertedY(this->getTilingScheme()));
|
||||
}
|
||||
return key;
|
||||
}));
|
||||
|
||||
UriQuery query(uri);
|
||||
query.setValue("subscription-key", this->_key);
|
||||
uri.setQuery(query.toQueryString());
|
||||
|
||||
std::string url = std::string(uri.toString());
|
||||
|
||||
LoadTileImageFromUrlOptions options;
|
||||
options.allowEmptyImages = true;
|
||||
options.moreDetailAvailable = tileID.level < this->getMaximumLevel();
|
||||
options.rectangle = this->getTilingScheme().tileToRectangle(tileID);
|
||||
|
||||
return this->loadTileImageFromUrl(url, {}, std::move(options));
|
||||
}
|
||||
|
||||
Future<void> AzureMapsRasterOverlayTileProvider::loadCredits() {
|
||||
const uint32_t maximumZoomLevel = this->getMaximumLevel();
|
||||
|
||||
IntrusivePointer thiz = this;
|
||||
|
||||
std::vector<Future<std::vector<std::string>>> creditFutures;
|
||||
creditFutures.reserve(maximumZoomLevel + 1);
|
||||
|
||||
for (size_t i = 0; i <= maximumZoomLevel; ++i) {
|
||||
creditFutures.emplace_back(
|
||||
fetchAttributionData(
|
||||
this->getAssetAccessor(),
|
||||
this->getAsyncSystem(),
|
||||
this->getLogger(),
|
||||
this->_baseUrl,
|
||||
this->_apiVersion,
|
||||
this->_tilesetId,
|
||||
this->_key,
|
||||
uint32_t(i),
|
||||
Rectangle(-180.0, -90.0, 180.0, 90.0))
|
||||
.thenInMainThread([](rapidjson::Document&& document) {
|
||||
if (document.HasParseError() || !document.IsObject()) {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
return JsonHelpers::getStrings(document, "copyrights");
|
||||
}));
|
||||
}
|
||||
|
||||
return this->getAsyncSystem()
|
||||
.all(std::move(creditFutures))
|
||||
.thenInMainThread(
|
||||
[thiz](std::vector<std::vector<std::string>>&& results) {
|
||||
std::set<std::string> uniqueCredits;
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
const std::vector<std::string>& credits = results[i];
|
||||
for (size_t j = 0; j < credits.size(); j++) {
|
||||
if (!credits[j].empty()) {
|
||||
uniqueCredits.insert(credits[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& credit : uniqueCredits) {
|
||||
thiz->_credits.emplace_back(thiz->getCreditSystem()->createCredit(
|
||||
credit,
|
||||
thiz->_showCreditsOnScreen));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AzureMapsRasterOverlayTileProvider::addCredits(
|
||||
CesiumUtility::CreditReferencer& creditReferencer) noexcept {
|
||||
QuadtreeRasterOverlayTileProvider::addCredits(creditReferencer);
|
||||
|
||||
if (this->_azureCredit) {
|
||||
creditReferencer.addCreditReference(*this->_azureCredit);
|
||||
}
|
||||
|
||||
for (const Credit& credit : this->_credits) {
|
||||
creditReferencer.addCreditReference(credit);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#include <CesiumAsync/IAssetAccessor.h>
|
||||
#include <CesiumAsync/IAssetResponse.h>
|
||||
#include <CesiumGeometry/QuadtreeTileID.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumGeometry/Rectangle.h>
|
||||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/pointer.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
|
@ -94,6 +93,19 @@ const std::string BingMapsRasterOverlay::BING_LOGO_HTML =
|
|||
"OXfbBoeDOo8wHpy8lKpvoafRoG6YgXFYKP4GSj63gtwWfhHzl7Skq9JTshAAAAAElFTkSuQmCC"
|
||||
"\" title=\"Bing Imagery\"/></a>";
|
||||
|
||||
namespace {
|
||||
Rectangle createRectangle(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
pOwner->getOptions().ellipsoid);
|
||||
}
|
||||
|
||||
QuadtreeTilingScheme createTilingScheme(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return QuadtreeTilingScheme(createRectangle(pOwner), 2, 2);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class BingMapsTileProvider final : public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
BingMapsTileProvider(
|
||||
|
|
@ -113,8 +125,7 @@ public:
|
|||
uint32_t height,
|
||||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel,
|
||||
const std::string& culture,
|
||||
const CesiumGeospatial::Ellipsoid& ellipsoid)
|
||||
const std::string& culture)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
|
|
@ -123,13 +134,9 @@ public:
|
|||
bingCredit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
WebMercatorProjection(ellipsoid),
|
||||
QuadtreeTilingScheme(
|
||||
WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
ellipsoid),
|
||||
2,
|
||||
2),
|
||||
WebMercatorProjection::computeMaximumProjectedRectangle(ellipsoid),
|
||||
WebMercatorProjection(pOwner->getOptions().ellipsoid),
|
||||
createTilingScheme(pOwner),
|
||||
createRectangle(pOwner),
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
width,
|
||||
|
|
@ -379,8 +386,6 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
const CesiumGeospatial::Ellipsoid& ellipsoid = this->getOptions().ellipsoid;
|
||||
|
||||
auto handleResponse =
|
||||
[pOwner,
|
||||
asyncSystem,
|
||||
|
|
@ -388,7 +393,6 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
ellipsoid,
|
||||
baseUrl = this->_url,
|
||||
culture = this->_culture](
|
||||
const std::shared_ptr<IAssetRequest>& pRequest,
|
||||
|
|
@ -470,8 +474,7 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
height,
|
||||
0,
|
||||
maximumLevel,
|
||||
culture,
|
||||
ellipsoid);
|
||||
culture);
|
||||
};
|
||||
|
||||
auto cacheResultIt = sessionCache.find(metadataUrl);
|
||||
|
|
@ -509,55 +512,4 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> BingMapsRasterOverlay::refreshTileProviderWithNewKey(
|
||||
const IntrusivePointer<RasterOverlayTileProvider>& pProvider,
|
||||
const std::string& newKey) {
|
||||
this->_key = newKey;
|
||||
|
||||
return this
|
||||
->createTileProvider(
|
||||
pProvider->getAsyncSystem(),
|
||||
pProvider->getAssetAccessor(),
|
||||
pProvider->getCreditSystem(),
|
||||
pProvider->getPrepareRendererResources(),
|
||||
pProvider->getLogger(),
|
||||
&pProvider->getOwner())
|
||||
.thenInMainThread([pProvider](CreateTileProviderResult&& result) {
|
||||
if (!result) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Bing Maps raster overlay with a new key: {}.",
|
||||
result.error().message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use static_cast instead of dynamic_cast here to avoid the need for
|
||||
// RTTI, and because we are certain of the type.
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
BingMapsTileProvider* pOldBing =
|
||||
static_cast<BingMapsTileProvider*>(pProvider.get());
|
||||
BingMapsTileProvider* pNewBing =
|
||||
static_cast<BingMapsTileProvider*>(result->get());
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
if (pOldBing->getCoverageRectangle().getLowerLeft() !=
|
||||
pNewBing->getCoverageRectangle().getLowerLeft() ||
|
||||
pOldBing->getCoverageRectangle().getUpperRight() !=
|
||||
pNewBing->getCoverageRectangle().getUpperRight() ||
|
||||
pOldBing->getHeight() != pNewBing->getHeight() ||
|
||||
pOldBing->getWidth() != pNewBing->getWidth() ||
|
||||
pOldBing->getMinimumLevel() != pNewBing->getMinimumLevel() ||
|
||||
pOldBing->getMaximumLevel() != pNewBing->getMaximumLevel() ||
|
||||
pOldBing->getProjection() != pNewBing->getProjection()) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Bing Maps raster overlay with a new key "
|
||||
"because some metadata properties changed unexpectedly upon "
|
||||
"refresh.");
|
||||
return;
|
||||
}
|
||||
|
||||
pOldBing->update(*pNewBing);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ public:
|
|||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
|
|
@ -177,19 +176,12 @@ private:
|
|||
std::string _key;
|
||||
std::optional<Credit> _googleCredit;
|
||||
std::optional<Credit> _credits;
|
||||
bool _showCreditsOnScreen;
|
||||
|
||||
mutable QuadtreeRectangleAvailability _availableTiles;
|
||||
mutable QuadtreeRectangleAvailability _availableAvailability;
|
||||
};
|
||||
|
||||
void ensureTrailingSlash(std::string& url) {
|
||||
Uri uri(url);
|
||||
std::string_view path = uri.getPath();
|
||||
if (path.empty() || path.back() != '/') {
|
||||
uri.setPath(std::string(path) + '/');
|
||||
url = uri.toString();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
|
|
@ -201,7 +193,9 @@ GoogleMapTilesRasterOverlay::GoogleMapTilesRasterOverlay(
|
|||
: RasterOverlay(name, overlayOptions),
|
||||
_newSessionParameters(newSessionParameters),
|
||||
_existingSession(std::nullopt) {
|
||||
ensureTrailingSlash(this->_newSessionParameters->apiBaseUrl);
|
||||
Uri baseUrl(this->_newSessionParameters->apiBaseUrl);
|
||||
baseUrl.ensureTrailingSlash();
|
||||
this->_newSessionParameters->apiBaseUrl = baseUrl.toString();
|
||||
}
|
||||
|
||||
GoogleMapTilesRasterOverlay::GoogleMapTilesRasterOverlay(
|
||||
|
|
@ -211,7 +205,9 @@ GoogleMapTilesRasterOverlay::GoogleMapTilesRasterOverlay(
|
|||
: RasterOverlay(name, overlayOptions),
|
||||
_newSessionParameters(std::nullopt),
|
||||
_existingSession(existingSession) {
|
||||
ensureTrailingSlash(this->_existingSession->apiBaseUrl);
|
||||
Uri baseUrl(this->_existingSession->apiBaseUrl);
|
||||
baseUrl.ensureTrailingSlash();
|
||||
this->_existingSession->apiBaseUrl = baseUrl.toString();
|
||||
}
|
||||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
|
|
@ -242,7 +238,6 @@ GoogleMapTilesRasterOverlay::createTileProvider(
|
|||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
session.apiBaseUrl,
|
||||
|
|
@ -342,13 +337,14 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
{{"Content-Type", "application/json"}},
|
||||
requestPayloadBytes)
|
||||
.thenInMainThread(
|
||||
[this,
|
||||
asyncSystem,
|
||||
[asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pOwner](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
pOwner,
|
||||
newSessionParameters = this->_newSessionParameters](
|
||||
std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
-> Future<CreateTileProviderResult> {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
if (!pResponse) {
|
||||
|
|
@ -453,12 +449,11 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this->_newSessionParameters->apiBaseUrl,
|
||||
newSessionParameters->apiBaseUrl,
|
||||
session,
|
||||
this->_newSessionParameters->key,
|
||||
newSessionParameters->key,
|
||||
maximumZoomLevel,
|
||||
static_cast<uint32_t>(tileWidth),
|
||||
static_cast<uint32_t>(tileHeight),
|
||||
|
|
@ -498,7 +493,6 @@ GoogleMapTilesRasterOverlayTileProvider::
|
|||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
|
|
@ -514,7 +508,7 @@ GoogleMapTilesRasterOverlayTileProvider::
|
|||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
WebMercatorProjection(pOwner->getOptions().ellipsoid),
|
||||
|
|
@ -529,6 +523,7 @@ GoogleMapTilesRasterOverlayTileProvider::
|
|||
_key(key),
|
||||
_googleCredit(),
|
||||
_credits(),
|
||||
_showCreditsOnScreen(pOwner->getOptions().showCreditsOnScreen),
|
||||
_availableTiles(createTilingScheme(pOwner), maximumLevel),
|
||||
_availableAvailability(createTilingScheme(pOwner), maximumLevel) {
|
||||
if (pCreditSystem && showLogo) {
|
||||
|
|
@ -977,7 +972,9 @@ Future<void> GoogleMapTilesRasterOverlayTileProvider::loadCredits() {
|
|||
}
|
||||
|
||||
// Create a single credit from this giant string.
|
||||
thiz->_credits = thiz->getCreditSystem()->createCredit(joined, false);
|
||||
thiz->_credits = thiz->getCreditSystem()->createCredit(
|
||||
joined,
|
||||
thiz->_showCreditsOnScreen);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <CesiumAsync/IAssetResponse.h>
|
||||
#include <CesiumAsync/NetworkAssetDescriptor.h>
|
||||
#include <CesiumAsync/SharedAssetDepot.h>
|
||||
#include <CesiumRasterOverlays/AzureMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/BingMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/GoogleMapTilesRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/IonRasterOverlay.h>
|
||||
|
|
@ -315,6 +316,74 @@ IonRasterOverlay::createTileProvider(
|
|||
return TileProvider::create(externals, descriptor, pOwner);
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseAzure2DOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
const auto optionsIt = ionResponse.FindMember("options");
|
||||
if (optionsIt == ionResponse.MemberEnd() || !optionsIt->value.IsObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ionOptions = optionsIt->value;
|
||||
ExternalAssetEndpoint::Azure2D& azure2D =
|
||||
this->options.emplace<ExternalAssetEndpoint::Azure2D>();
|
||||
azure2D.url = JsonHelpers::getStringOrDefault(ionOptions, "url", "");
|
||||
azure2D.tilesetId =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "tilesetId", "");
|
||||
azure2D.key =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "subscription-key", "");
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseGoogle2DOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
const auto optionsIt = ionResponse.FindMember("options");
|
||||
if (optionsIt == ionResponse.MemberEnd() || !optionsIt->value.IsObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ionOptions = optionsIt->value;
|
||||
ExternalAssetEndpoint::Google2D& google2D =
|
||||
this->options.emplace<ExternalAssetEndpoint::Google2D>();
|
||||
google2D.url =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "url", google2D.url);
|
||||
google2D.key = JsonHelpers::getStringOrDefault(ionOptions, "key", "");
|
||||
google2D.session = JsonHelpers::getStringOrDefault(ionOptions, "session", "");
|
||||
google2D.expiry = JsonHelpers::getStringOrDefault(ionOptions, "expiry", "");
|
||||
google2D.tileWidth =
|
||||
JsonHelpers::getUint32OrDefault(ionOptions, "tileWidth", 256);
|
||||
google2D.tileHeight =
|
||||
JsonHelpers::getUint32OrDefault(ionOptions, "tileHeight", 256);
|
||||
google2D.imageFormat = JsonHelpers::getStringOrDefault(
|
||||
ionOptions,
|
||||
"imageFormat",
|
||||
GoogleMapTilesImageFormat::jpeg);
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseBingOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
const auto optionsIt = ionResponse.FindMember("options");
|
||||
if (optionsIt == ionResponse.MemberEnd() || !optionsIt->value.IsObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ionOptions = optionsIt->value;
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
this->options.emplace<ExternalAssetEndpoint::Bing>();
|
||||
bing.url = JsonHelpers::getStringOrDefault(ionOptions, "url", "");
|
||||
bing.key = JsonHelpers::getStringOrDefault(ionOptions, "key", "");
|
||||
bing.mapStyle =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "mapStyle", "AERIAL");
|
||||
bing.culture = JsonHelpers::getStringOrDefault(ionOptions, "culture", "");
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseTileMapServiceOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
ExternalAssetEndpoint::TileMapService& tileMapService =
|
||||
this->options.emplace<ExternalAssetEndpoint::TileMapService>();
|
||||
tileMapService.url = JsonHelpers::getStringOrDefault(ionResponse, "url", "");
|
||||
tileMapService.accessToken =
|
||||
JsonHelpers::getStringOrDefault(ionResponse, "accessToken", "");
|
||||
}
|
||||
|
||||
/* static */ CesiumUtility::IntrusivePointer<IonRasterOverlay::EndpointDepot>
|
||||
IonRasterOverlay::getEndpointCache() {
|
||||
static CesiumUtility::IntrusivePointer<EndpointDepot> pDepot =
|
||||
|
|
@ -393,36 +462,25 @@ IonRasterOverlay::getEndpointCache() {
|
|||
"externalType",
|
||||
"unknown");
|
||||
|
||||
if (endpoint.externalType == "BING") {
|
||||
const auto optionsIt = response.FindMember("options");
|
||||
if (optionsIt == response.MemberEnd() ||
|
||||
!optionsIt->value.IsObject()) {
|
||||
if (endpoint.externalType == "AZURE_MAPS") {
|
||||
endpoint.parseAzure2DOptions(response);
|
||||
|
||||
if (!std::holds_alternative<ExternalAssetEndpoint::Azure2D>(
|
||||
endpoint.options)) {
|
||||
endpoint.pRequestThatFailed = std::move(pRequest);
|
||||
return ResultPointer<ExternalAssetEndpoint>(
|
||||
new ExternalAssetEndpoint(std::move(endpoint)),
|
||||
ErrorList::error(fmt::format(
|
||||
"Cesium ion Bing Maps raster overlay metadata "
|
||||
"Cesium ion Azure Maps raster overlay metadata "
|
||||
"response does not contain 'options' or it is "
|
||||
"not an object.")));
|
||||
}
|
||||
|
||||
const auto& options = optionsIt->value;
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
endpoint.options.emplace<ExternalAssetEndpoint::Bing>();
|
||||
bing.url =
|
||||
JsonHelpers::getStringOrDefault(options, "url", "");
|
||||
bing.key =
|
||||
JsonHelpers::getStringOrDefault(options, "key", "");
|
||||
bing.mapStyle = JsonHelpers::getStringOrDefault(
|
||||
options,
|
||||
"mapStyle",
|
||||
"AERIAL");
|
||||
bing.culture =
|
||||
JsonHelpers::getStringOrDefault(options, "culture", "");
|
||||
} else if (endpoint.externalType == "GOOGLE_2D_MAPS") {
|
||||
const auto optionsIt = response.FindMember("options");
|
||||
if (optionsIt == response.MemberEnd() ||
|
||||
!optionsIt->value.IsObject()) {
|
||||
endpoint.parseGoogle2DOptions(response);
|
||||
|
||||
if (!std::holds_alternative<
|
||||
ExternalAssetEndpoint::Google2D>(
|
||||
endpoint.options)) {
|
||||
endpoint.pRequestThatFailed = std::move(pRequest);
|
||||
return ResultPointer<ExternalAssetEndpoint>(
|
||||
new ExternalAssetEndpoint(std::move(endpoint)),
|
||||
|
|
@ -431,45 +489,21 @@ IonRasterOverlay::getEndpointCache() {
|
|||
"metadata response does not contain 'options' or "
|
||||
"it is not an object.")));
|
||||
}
|
||||
} else if (endpoint.externalType == "BING") {
|
||||
endpoint.parseBingOptions(response);
|
||||
|
||||
const auto& options = optionsIt->value;
|
||||
ExternalAssetEndpoint::Google2D& google2D =
|
||||
endpoint.options
|
||||
.emplace<ExternalAssetEndpoint::Google2D>();
|
||||
google2D.url = JsonHelpers::getStringOrDefault(
|
||||
options,
|
||||
"url",
|
||||
google2D.url);
|
||||
google2D.key =
|
||||
JsonHelpers::getStringOrDefault(options, "key", "");
|
||||
google2D.session =
|
||||
JsonHelpers::getStringOrDefault(options, "session", "");
|
||||
google2D.expiry =
|
||||
JsonHelpers::getStringOrDefault(options, "expiry", "");
|
||||
google2D.tileWidth = JsonHelpers::getUint32OrDefault(
|
||||
options,
|
||||
"tileWidth",
|
||||
256);
|
||||
google2D.tileHeight = JsonHelpers::getUint32OrDefault(
|
||||
options,
|
||||
"tileHeight",
|
||||
256);
|
||||
google2D.imageFormat = JsonHelpers::getStringOrDefault(
|
||||
options,
|
||||
"imageFormat",
|
||||
GoogleMapTilesImageFormat::jpeg);
|
||||
|
||||
if (!std::holds_alternative<ExternalAssetEndpoint::Bing>(
|
||||
endpoint.options)) {
|
||||
endpoint.pRequestThatFailed = std::move(pRequest);
|
||||
return ResultPointer<ExternalAssetEndpoint>(
|
||||
new ExternalAssetEndpoint(std::move(endpoint)),
|
||||
ErrorList::error(fmt::format(
|
||||
"Cesium ion Bing Maps raster overlay metadata "
|
||||
"response does not contain 'options' or it is "
|
||||
"not an object.")));
|
||||
}
|
||||
} else {
|
||||
ExternalAssetEndpoint::TileMapService& tileMapService =
|
||||
endpoint.options
|
||||
.emplace<ExternalAssetEndpoint::TileMapService>();
|
||||
tileMapService.url =
|
||||
JsonHelpers::getStringOrDefault(response, "url", "");
|
||||
tileMapService.accessToken =
|
||||
JsonHelpers::getStringOrDefault(
|
||||
response,
|
||||
"accessToken",
|
||||
"");
|
||||
endpoint.parseTileMapServiceOptions(response);
|
||||
}
|
||||
|
||||
const auto attributionsIt =
|
||||
|
|
@ -549,17 +583,19 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
}
|
||||
|
||||
IntrusivePointer<RasterOverlay> pOverlay = nullptr;
|
||||
if (pEndpoint->externalType == "BING") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Bing>(
|
||||
if (pEndpoint->externalType == "AZURE_MAPS") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Azure2D>(
|
||||
pEndpoint->options));
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
std::get<ExternalAssetEndpoint::Bing>(pEndpoint->options);
|
||||
pOverlay = new BingMapsRasterOverlay(
|
||||
ExternalAssetEndpoint::Azure2D& azure2D =
|
||||
std::get<ExternalAssetEndpoint::Azure2D>(pEndpoint->options);
|
||||
pOverlay = new AzureMapsRasterOverlay(
|
||||
this->pOwner->getName(),
|
||||
bing.url,
|
||||
bing.key,
|
||||
bing.mapStyle,
|
||||
bing.culture,
|
||||
AzureMapsSessionParameters{
|
||||
.key = azure2D.key,
|
||||
.tilesetId = azure2D.tilesetId,
|
||||
.showLogo = false,
|
||||
.apiBaseUrl = azure2D.url,
|
||||
},
|
||||
this->pOwner->getOptions());
|
||||
} else if (pEndpoint->externalType == "GOOGLE_2D_MAPS") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Google2D>(
|
||||
|
|
@ -579,6 +615,18 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
.apiBaseUrl = google2D.url,
|
||||
},
|
||||
this->pOwner->getOptions());
|
||||
} else if (pEndpoint->externalType == "BING") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Bing>(
|
||||
pEndpoint->options));
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
std::get<ExternalAssetEndpoint::Bing>(pEndpoint->options);
|
||||
pOverlay = new BingMapsRasterOverlay(
|
||||
this->pOwner->getName(),
|
||||
bing.url,
|
||||
bing.key,
|
||||
bing.mapStyle,
|
||||
bing.culture,
|
||||
this->pOwner->getOptions());
|
||||
} else {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::TileMapService>(
|
||||
pEndpoint->options));
|
||||
|
|
@ -629,5 +677,4 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
})
|
||||
.share();
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -37,11 +37,14 @@ RasterOverlayTile::RasterOverlayTile(
|
|||
RasterOverlayTile::~RasterOverlayTile() {
|
||||
this->_pActivatedOverlay->removeTile(this);
|
||||
|
||||
RasterOverlayTileProvider& tileProvider =
|
||||
*this->_pActivatedOverlay->getTileProvider();
|
||||
RasterOverlayTileProvider* pTileProvider =
|
||||
this->_pActivatedOverlay->getTileProvider();
|
||||
|
||||
if (!pTileProvider)
|
||||
return;
|
||||
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources = tileProvider.getPrepareRendererResources();
|
||||
pPrepareRendererResources = pTileProvider->getPrepareRendererResources();
|
||||
|
||||
if (pPrepareRendererResources) {
|
||||
void* pLoadThreadResult =
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include <glm/common.hpp>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
|
@ -520,63 +519,4 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
});
|
||||
}
|
||||
|
||||
Future<void>
|
||||
TileMapServiceRasterOverlay::refreshTileProviderWithNewUrlAndHeaders(
|
||||
const IntrusivePointer<RasterOverlayTileProvider>& pProvider,
|
||||
const std::optional<std::string>& newUrl,
|
||||
const std::optional<std::vector<CesiumAsync::IAssetAccessor::THeader>>&
|
||||
newHeaders) {
|
||||
if (newUrl) {
|
||||
this->_url = *newUrl;
|
||||
}
|
||||
if (newHeaders) {
|
||||
this->_headers = *newHeaders;
|
||||
}
|
||||
|
||||
return this
|
||||
->createTileProvider(
|
||||
pProvider->getAsyncSystem(),
|
||||
pProvider->getAssetAccessor(),
|
||||
pProvider->getCreditSystem(),
|
||||
pProvider->getPrepareRendererResources(),
|
||||
pProvider->getLogger(),
|
||||
&pProvider->getOwner())
|
||||
.thenInMainThread([pProvider](CreateTileProviderResult&& result) {
|
||||
if (!result) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Bing Maps raster overlay with a new key: {}.",
|
||||
result.error().message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use static_cast instead of dynamic_cast here to avoid the need for
|
||||
// RTTI, and because we are certain of the type.
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
TileMapServiceTileProvider* pOld =
|
||||
static_cast<TileMapServiceTileProvider*>(pProvider.get());
|
||||
TileMapServiceTileProvider* pNew =
|
||||
static_cast<TileMapServiceTileProvider*>(result->get());
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
if (pOld->getCoverageRectangle().getLowerLeft() !=
|
||||
pNew->getCoverageRectangle().getLowerLeft() ||
|
||||
pOld->getCoverageRectangle().getUpperRight() !=
|
||||
pNew->getCoverageRectangle().getUpperRight() ||
|
||||
pOld->getHeight() != pNew->getHeight() ||
|
||||
pOld->getWidth() != pNew->getWidth() ||
|
||||
pOld->getMinimumLevel() != pNew->getMinimumLevel() ||
|
||||
pOld->getMaximumLevel() != pNew->getMaximumLevel() ||
|
||||
pOld->getProjection() != pNew->getProjection()) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Tile Map Service raster overlay with a new "
|
||||
"URL and request headers because some metadata properties "
|
||||
"changed unexpectedly upon refresh.");
|
||||
return;
|
||||
}
|
||||
|
||||
pOld->update(*pNew);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ cesium_target_include_directories(
|
|||
target_link_libraries(
|
||||
CesiumUtility
|
||||
PUBLIC
|
||||
zlib-ng::zlib-ng
|
||||
zlib-ng::zlib
|
||||
spdlog::spdlog
|
||||
glm::glm
|
||||
ada::ada
|
||||
|
|
|
|||
|
|
@ -356,6 +356,12 @@ public:
|
|||
static std::string
|
||||
setPath(const std::string& uri, const std::string& newPath);
|
||||
|
||||
/**
|
||||
* @brief Ensures that the Uri's path ends with a slash, modifying itself if
|
||||
* necessary. Useful when the Uri is used as a base URL.
|
||||
*/
|
||||
void ensureTrailingSlash();
|
||||
|
||||
private:
|
||||
std::optional<ada::url_aggregator> _url = std::nullopt;
|
||||
bool _hasScheme = false;
|
||||
|
|
|
|||
|
|
@ -385,4 +385,11 @@ std::string Uri::setPath(const std::string& uri, const std::string& newPath) {
|
|||
return std::string(parsedUri.toString());
|
||||
}
|
||||
|
||||
void Uri::ensureTrailingSlash() {
|
||||
std::string_view path = this->getPath();
|
||||
if (path.empty() || path.back() != '/') {
|
||||
this->setPath(std::string(path) + '/');
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace CesiumUtility
|
||||
|
|
|
|||
|
|
@ -294,4 +294,14 @@ TEST_CASE("Uri::getExtension") {
|
|||
CHECK(Uri("http://example.com/a/b/c/.hidden").getExtension() == "");
|
||||
CHECK(Uri("http://example.com/a/b/c/.").getExtension() == "");
|
||||
CHECK(Uri("http://example.com/a/b/c/..").getExtension() == "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Uri::ensureTrailingSlash") {
|
||||
Uri uri("http://www.example.com");
|
||||
uri.ensureTrailingSlash();
|
||||
CHECK_EQ(uri.toString(), "http://www.example.com/");
|
||||
|
||||
// Ensure nothing changes when a trailing slash is present.
|
||||
uri.ensureTrailingSlash();
|
||||
CHECK_EQ(uri.toString(), "http://www.example.com/");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,25 +4,35 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
|||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(zlib-ng REQUIRED)
|
||||
find_dependency(modp_b64 REQUIRED)
|
||||
|
||||
find_dependency(ada CONFIG REQUIRED)
|
||||
find_dependency(Async++ CONFIG REQUIRED)
|
||||
find_dependency(blend2d CONFIG REQUIRED)
|
||||
find_dependency(doctest CONFIG REQUIRED)
|
||||
find_dependency(draco CONFIG REQUIRED)
|
||||
find_dependency(expected-lite CONFIG REQUIRED)
|
||||
find_dependency(glm CONFIG REQUIRED)
|
||||
find_dependency(meshoptimizer CONFIG REQUIRED)
|
||||
find_dependency(httplib CONFIG REQUIRED)
|
||||
find_dependency(Ktx CONFIG REQUIRED)
|
||||
find_dependency(libmorton CONFIG REQUIRED)
|
||||
find_dependency(libjpeg-turbo CONFIG REQUIRED)
|
||||
find_dependency(libmorton CONFIG REQUIRED)
|
||||
find_dependency(meshoptimizer CONFIG REQUIRED)
|
||||
find_dependency(OpenSSL REQUIRED)
|
||||
find_dependency(s2 CONFIG REQUIRED)
|
||||
find_dependency(spdlog CONFIG REQUIRED)
|
||||
find_dependency(tinyxml2 CONFIG REQUIRED)
|
||||
find_dependency(unofficial-sqlite3 CONFIG REQUIRED)
|
||||
find_dependency(ada CONFIG REQUIRED)
|
||||
find_dependency(WebP CONFIG REQUIRED)
|
||||
find_dependency(zlib-ng CONFIG REQUIRED)
|
||||
|
||||
# asmjit should not be included with iOS builds as iOS doesn't support JIT compilation.
|
||||
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
find_dependency(asmjit CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT CESIUM_DISABLE_CURL)
|
||||
find_dependency(CURL REQUIRED)
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/cesium-nativeTargets.cmake")
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
find_library(zlib-ng_LIBRARIES NAMES zlibstatic-ng z-ng zlib-ng)
|
||||
find_library(zlib-ng_DEBUG_LIBRARIES
|
||||
NAMES
|
||||
"zlibstatic-ngd"
|
||||
"z-ngd"
|
||||
"zlib-ngd"
|
||||
)
|
||||
|
||||
# vcpkg specific locations for debug libraries if they are not already found
|
||||
set(zlibngSavePrefixPath ${CMAKE_PREFIX_PATH})
|
||||
list(FILTER CMAKE_PREFIX_PATH INCLUDE REGEX "/debug")
|
||||
find_library(zlib-ng_DEBUG_LIBRARIES
|
||||
NAMES
|
||||
zlibstatic
|
||||
z-ng
|
||||
zlib-ng
|
||||
)
|
||||
set(CMAKE_PREFIX_PATH ${zlibngSavePrefixPath})
|
||||
|
||||
find_path(zlib-ng_INCLUDE_DIRS NAMES zlib-ng.h)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(zlib-ng
|
||||
FOUND_VAR
|
||||
zlib-ng_FOUND
|
||||
REQUIRED_VARS
|
||||
zlib-ng_LIBRARIES
|
||||
zlib-ng_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
mark_as_advanced(zlib-ng_LIBRARIES zlib-ng_INCLUDE_DIRS)
|
||||
|
||||
if(zlib-ng_FOUND AND NOT TARGET zlib-ng::zlib-ng)
|
||||
add_library(zlib-ng::zlib-ng UNKNOWN IMPORTED)
|
||||
set_target_properties(zlib-ng::zlib-ng PROPERTIES
|
||||
IMPORTED_LOCATION "${zlib-ng_LIBRARIES}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${zlib-ng_INCLUDE_DIRS}"
|
||||
)
|
||||
if(zlib-ng_DEBUG_LIBRARIES)
|
||||
set_target_properties(zlib-ng::zlib-ng PROPERTIES
|
||||
IMPORTED_LOCATION_DEBUG "${zlib-ng_DEBUG_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
Loading…
Reference in New Issue