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.

Program: Create a raster model with a single tile
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.

Program: Create a data retriever using the image
// 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:

Program: Add the raster model to the map
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);
}
image on map
Figure 1. The image added to the map