HERE Maps offers map-rendering services that provide world-wide raster data, such as aerial maps. You can use those as background data in your LuciadCPillar map application.
The HERE Maps data is structured as a quad tree with 21 levels. In short, a quad tree is a multi-leveled tile structure where a tile at a certain level is split up in 2x2 tiles at a more detailed level.
This figure illustrates the tile layout of a quad tree with 4 levels. Each level has the same model bounds. The image on the left shows the root tile at level 0. Each new level has 4 times as many tiles.
Each of the tiles in this quad tree corresponds to an image that you can download using the HERE Maps service.
This article shows how you can do that with the LuciadCPillar API.
Step 1: Create a model with a quad-tree structure
The code snippets show how the HERE Maps model is created. It uses a quad-tree structure with a single root tile and 21 levels. Images have a resolution of 256 x 256 pixels.
Note that this snippet already mentions the HereMapsDataRetriever
class. Step 2: Retrieve the HERE Maps imagery data elaborates on this class.
// The reference for the HERE maps tile structure. auto pseudoMercator = CoordinateReferenceProvider::create("EPSG:3857"); if (!pseudoMercator) { throw luciad::RuntimeException("Cannot create Pseudo Mercator reference 'EPSG:3857'"); } // The extent of the tile structure; which is also the extent of the data. Bounds hereMapsBounds = Bounds(*pseudoMercator, Coordinate{-20037508.34278925, -20037508.34278925}, Coordinate{20037508.34278925, 20037508.34278925}); auto modelMetadata = ModelMetadata::newBuilder().title(toTitle(hereType)).build(); auto hereMapsAttributionProvider = createAttributionProvider(hereType, apiKey); auto hereMapsDataRetriever = std::make_shared<HereMapsDataRetriever>(hereMapInfo, dpi); return QuadTreeRasterModelBuilder::newBuilder() .reference(*pseudoMercator) .levelCount(21) .level0ColumnCount(1) .level0RowCount(1) .tileWidthPixels(256) .tileHeightPixels(256) .bounds(hereMapsBounds) .modelMetadata(modelMetadata) .dataRetriever(hereMapsDataRetriever) .attributionProvider(hereMapsAttributionProvider) .build();
Step 2: Retrieve the HERE Maps imagery data
The next step is to create an IMultilevelTiledRasterDataRetriever
implementation that can return HERE Maps data for each tile. When the raster visualization engine requests data
for a certain tile that’s visible on the map, the IMultilevelTiledRasterDataRetriever
class is called.
The snippets show how this interface is implemented for HERE Maps.
For each tile for which data is requested, it:
-
Constructs a HERE Maps URL.
-
Performs a HTTP GET request to this URL to download the HERE Maps PNG image for the tile.
-
Passes the encoded PNG data to the
IMultilevelTiledRasterDataRetrieverCallback
, which decodes the PNG data, and passes it on to the raster visualization engine. -
Handles cancellation, possible errors, or missing tile data.
These snippets don’t show details for every operation. For the full source code, see the |
class HereMapsDataRetriever : public IMultilevelTiledRasterDataRetriever { public: void retrieveTileData(const MultilevelTileCoordinate& tileCoordinate, const CancellationToken& cancellationToken, const std::shared_ptr<IMultilevelTiledRasterDataRetrieverCallback>& callback) override { // Create a HERE Maps url, based on the (fixed) base URL and the tile coordinate for this tile const std::string tileUrl = getUrl(tileCoordinate); // Perform a HTTP GET request to retrieve the data from the HERE Maps url const HttpRequest httpRequest = HttpRequest::newBuilder().uri(tileUrl).build(); const expected<HttpResponse, ErrorInfo> httpResponse = _httpClient->send(httpRequest, cancellationToken); // Handle cancellation. This happens for example when a layer is removed. In that case, the data is not needed anymore if (cancellationToken.isCanceled()) { callback->onCanceled(tileCoordinate); return; } if (httpResponse.has_value()) { // Read the byte data and add it to a DataEntity std::optional<DataEntity> content = httpResponse->getBody(); if (content.has_value()) { // Pass the data to the onDataAvailable callback, which will decode the HERE Maps PNG data // and pass on the decoded image to the raster painting engine. callback->onDataAvailable(tileCoordinate, content.value()); } else { callback->onDataNotAvailable(tileCoordinate); } } else { // Handle errors const std::string message = httpResponse.get_unexpected().value().getMessage(); callback->onError(tileCoordinate, message); } } };
Step 3: Getting a HERE Maps API key
The next thing you need before connecting to HERE Maps is a HERE API key. On the HERE developer portal, you can create a HERE account and one or more keys.
To create a key for HERE Maps:
-
Go to https://developer.here.com/.
-
Log in with your HERE account, or sign up for a new account.
-
If you sign up for a new account, select a plan that fits your project. The default is the Freemium plan.
Once you have logged on, you see a Projects page that lists all your projects and the corresponding HERE plan. For new accounts with a Freemium plan, the Projects page shows one project called Freemium and the project creation date.
-
-
Select the project from the projects page.
-
On the Project Details page, you can create keys. In the
REST
section, click Generate App.
The portal generates an APP ID. -
Click Create API key.
The portal generates a key. Click the Copy button to copy/paste it in your code.
Note that more terms may apply for deployment. For more information about HERE licensing, see the HERE Terms and Conditions.
Step 4: Add the HERE Maps model to the map
The final step is adding the HERE Maps model to the map:
const auto map = _mapObject->getMap(); // Create a model for HereMaps using the API Key auto hereMapsModel = HereMapsModelFactory::createHereModel(hereType, map->getDpi(), hereMapsApiKey.toStdString()); // Create a layer for the model using the layer builder auto hereMapsLayer = RasterLayer::newBuilder().model(hereMapsModel).build(); // Add the layer to the map map->getLayerList()->add(hereMapsLayer);
The tutorial Introduction to styling raster data explains the styling options you have on the raster layer.
Getting the HERE Maps attributions
LuciadCPillar exposes the attributions on a map through |