Implementing a Kanzi Maps backend¶
You can implement your own Kanzi Maps backend.
When implementing a Kanzi Maps backend, you must implement:
A way to register the backend. See Registering a backend.
These main components:
Component
Example name
Inherits from
Backend
MyOwnBackend
MapBackend
Tiling scheme
MyOwnTilingScheme
TilingScheme
Tile fetcher
MyOwnTileFetcher
TileFetcher
Tile source
MyOwnTileSource
TileSource
To make your backend support more functionality, you can implement these optional components:
Component |
Example name |
Inherits from |
---|---|---|
Texture reference |
|
|
Texture tile |
|
|
Router |
|
|
Geocoder |
|
|
Registering a backend¶
Current Kanzi Maps backends expose a function that you can call to register the backend. For MyOwnBackend
this function can look like this:
void registerMyOwnBackend()
{
kanzi::MapBackendFactory::get().registerBackend("myown",
[](MapDomainSharedPtr mapDomain) -> std::shared_ptr<kanzi::MapBackend>
{
return std::make_shared<kanzi::MyOwnBackend>(mapDomain);
});
}
After a call to registerMyOwnBackend
, Kanzi Maps can instantiate the new backend with the name “myown”.
Implementing a backend¶
MyOwnBackend
acts as an orchestrator or manager between the other components. Whenever Kanzi Maps requests from the backend a subcomponent, such as the tile fetcher or the router, the backend must return the same instance of that component on every request.
Implementing a tiling scheme¶
The purpose of a tiling scheme is to:
Divide the world into tiles at different zoom levels.
Map WGS84 coordinates to target projection and the other way around.
These are some of the things to consider when you implement a tiling scheme:
Retiling data.
It is usually good to select the tiling to match the tiling used by the source data. Avoid retiling data on the fly, when possible. If the source data does not follow any tiling, you cannot avoid retiling.
Target projection.
When you implement an xyz tiling scheme, you must choose the target projection. To minimize the amount of CPU time use, match the source data projection as closely as possible, as long as that source data uses a projection that roughly approximates meters. An example of such projection is Web Mercator, for which the map backend library provides conversion routines. See
geom::WebMercator
. Another option is to perform runtime conversion from source projection while creatingVectorTiles
.Encoding tile addresses.
The world divided into tiles at 32 zoom levels fits into 64 bits allocated for the
TileAddress
. For example, if zoom level takes 5 bits, it leaves space for2^(64-5)=2^59
tiles per zoom level. Covering an area of 40000 km by 40000 km with tiles results in 0.003 square meters per tile.The projection used by
MyOwnTilingScheme
is directly used for rendering, that is, the returned coordinates are considered as the world coordinates.
Implementing a tile fetcher¶
Tile fetcher defines:
The available map layers
The geometry and metadata that the features on the layers can contain
When designing the tile fetcher, you need to decide how to:
Map
TileFilter
intoTileSource
.Define the pipeline for fetching a tile from a given
TileSource
with a givenTileAddress
.Map source geometry to that supported by
geom::GeometryCollectionBase
:2D point, 2D or 3D line string, concave or convex 2D or 3D polygon with optional holes, 2D triangles, 3D mesh with normals, texture coordinates, and a texture, or 3D strip geometry.
Map feature-specific information into key-value metadata of the feature.
Map potential raster or texture data into
TextureTile
. See Implementing texturing.
The data source is often a REST API that you access over HTTP or HTTPS. The Kanzi Maps backend library provides a rudimentary HTTPClient API that you can use to implement access to such APIs.
Kanzi Maps does not provide built-in support for authentication and similar concepts. Your backend implementation must handle them internally.
The pipeline defined by a tile fetcher often has these stages:
Fetch data from the server, disk, or in-memory cache.
Handle this stage in the IO context.
Process and package the data into
VectorTile
orTextureTile
instances, and the instances into parts of aTile
.Handle this stage in the COMPUTE context.
Renderers can then append further COMPUTE or MAIN context tasks to produce Kanzi meshes, textures, and nodes.
Make sure that you set these metadata keys that the Kanzi Maps plugin uses:
Key |
Type |
Description |
---|---|---|
|
Boolean |
Whether to disable clipping geometry to tile boundaries. |
|
Boolean |
Whether to extrude geometry when supported. |
|
Number |
Sets the floor level of extruded structures. Make this compatible with the target projection in meters. |
|
Number |
Sets the ceiling level of extruded structures. Make this compatible with the target projection in meters. |
Implementing texturing¶
Texturing relies on these classes:
|
Container for texture or raster data for a given If several tiles share texture data, |
|
Opaque reference to
|
|
Owns |
Kanzi Maps supports the PNG and raw RGBA8888 texture formats. TextureTile
and TextureReference
do not support tile atlases. Each texture must either be its own Kanzi texture, or you need to implement the texture atlas on the fly after retrieving the texture data from the texture tile.
Implementing a router¶
The main purpose of the router is to take a list of waypoints, convert them to a request, and fill in a collection of Route
instances.
The routing data source is often a REST API that you access over HTTP or HTTPS. The Kanzi Maps backend library provides a rudimentary HTTPClient API that you can use to implement access to such APIs.
Kanzi Maps does not provide built-in support for authentication and similar concepts. Your backend implementation must handle them internally.
The data structure of a Route
instance closely follows that used by OSRM responses. If your router is OSRM-based, you can use the OSRM JSON parser which is built-in to the map backend library.
For other routing services, you must convert the route information to a format that a Route
can represent:
Split the data into Legs between Waypoints.
Split the Legs into Steps between Maneuvers.
Encode maneuvers and turn-by-turn instructions into Maneuvers.
You need to provide the Route geometry as a geom::LineString
, if requested, and at the requested quality level. Kanzi Maps uses this geometry to render the route on top of the map, which is why the geometry needs to match the road geometry of the map tiles with high enough accuracy.
Implementing a geocoder¶
The Kanzi Maps API supports only reverse geocoding.
The geocoder must return a pipeline for fetching a collection of GeoFeatures when given WGS84 latitude-longitude coordinates and a map feature type filter.
If the reverse geocoding service supports the type filter, you can use that filter to limit results.
You can use the HTTPClient API provided by the Kanzi Maps backend library to access a REST API through which you get the data.
Sometimes geocoding results are provided in GeoJSON format. The Kanzi Maps backend library comes with a partial GeoJSON parser implementation. This parser directly outputs GeoFeature instances. Order the results by relevance, more specific results first. Make the geocoder return only results that intersect a given coordinate. For example, a place of interest comes before a postal code, and a postal code comes before a country.
The Geocoder needs to be able to provide this information for each feature.
Unique ID.
Type. For example, country, post code, or place of interest.
Human-readable text.
(Optional) Address.
Subtype. For example, a place of interest can be a cafe, restaurant, hotel, and so on.
Center of the feature in WGS84 latitude-longitude coordinates.
Requested center, that is, the WGS84 center of the request.