This tutorial shows how you can add a single image to the map using the custom raster API.
The concepts introduced in this article do not limit you to adding a single image. The API also allows you to
-
Create a grid of images
-
Create multiple levels of detail for images
-
Create custom elevation data
These additional topics are not explained explicitly in this article. Refer to the API documentation for
QuadTreeRasterModelBuilder
and
MultilevelTiledRasterModelBuilder
for more
information.
This tutorial assumes that you are using a decoded image . Though with minor changes, you can also use a compressed image, represented by a byte array for example.
Step 1: Create a raster model with a single tile
In the first step, we define the structure of the raster model. The raster model uses a single level, with just 1 tile in it. This is where we add the image.
Note that this snippet mentions the SingleImageDataRetriever
class. Step 2: Create a raster data retriever for the image elaborates on this class.
std::shared_ptr<IRasterModel> createImageModel(std::shared_ptr<Image> image, const Bounds& imageBounds) { auto modelMetadata = ModelMetadata::newBuilder().title("SingleImage").build(); // Create a data retriever that always returns the given image auto widthPx = image->getWidth(); auto heightPx = image->getHeight(); auto dataRetriever = std::make_shared<SingleImageDataRetriever>(std::move(image)); // Create a raster model with a single tile return MultilevelTiledRasterModelBuilder::newBuilder() // .reference(imageBounds.getReference()) .addLevel(widthPx, heightPx, 1, 1, imageBounds) .modelMetadata(modelMetadata) .dataRetriever(dataRetriever) .build(); }
Step 2: Create a raster data retriever for the image
The next step is to create an IMultilevelTiledRasterDataRetriever
implementation that returns the image for the tile defined in Step 1: Create a raster model with a single tile. When the raster visualization
engine requests data for that tile, the IMultilevelTiledRasterDataRetriever
class is called.
These snippets show how this interface is implemented.
// Returns a single Image, no matter which tile is requested class SingleImageDataRetriever final : public IMultilevelTiledRasterDataRetriever { public: explicit SingleImageDataRetriever(std::shared_ptr<Image> image) : _image(std::move(image)) { } void retrieveTileData(const MultilevelTileCoordinate& tileCoordinate, const CancellationToken& cancellationToken, const std::shared_ptr<IMultilevelTiledRasterDataRetrieverCallback>& callback) override { if (cancellationToken.isCanceled()) { callback->onCanceled(tileCoordinate); } else { callback->onImageAvailable(tileCoordinate, _image); } } private: std::shared_ptr<Image> _image; };
Step 3: Add the raster model to the map
The final step is adding the raster model to the map at the location you want:
void addImageToMap(std::shared_ptr<Image> image, const Map& map) { // Define the bounds where the Image should be added on the Map. In this case, // a geodetic (lon-lat) reference is used, and the image is placed somewhere around Paris auto crs = CoordinateReferenceProvider::create("EPSG:4326"); auto locationCenter = Coordinate(2.349014, 48.864716); auto lowerLeft = locationCenter - Coordinate(3.0, 2.0); auto upperRight = locationCenter + Coordinate(3.0, 2.0); auto imageBounds = Bounds(*crs, lowerLeft, upperRight); // Create a raster model based on the Image std::shared_ptr<IRasterModel> rasterModel = createImageModel(std::move(image), imageBounds); // Create a raster layer std::shared_ptr<RasterLayer> rasterLayer = RasterLayer::newBuilder().model(rasterModel).build(); // Add the raster layer to the map map.getLayerList()->add(rasterLayer); }
Figure 1, “The image added to the map” shows the end result: