Example of how to use custom decoder

In this section, you can learn how to work with the OCM custom decoder example.

Set a custom decoder function to decode a layer

By default, OCM Access Manager uses the protopack library to decode the requested layer data.

To decode a tile layer with your custom decoder, you need to create a decoder instance and layer data.

Note: For the purposes of this instruction, we use the RoadArrtibute layer as an example.

You can create your own decoder implementation by inheriting from the clientmap::decoder::AbstractSchemaDecoder abstract class, or you can use clientmap::decoder::DefaultSchemaDecoder as a reference and set custom decoder functions to decode the map layers that you need. If you do not set the custom decoder functions for the layers, clientmap::decoder::DefaultSchemaDecoder will use the default protopack decoding to decode all fields of the corresponding protobuf messages.

To set a custom decoder function to decode a layer:

  1. Create a DefaultSchemaDecoder instance and configure it to use the custom decoder for the specific layer.

    Note: The layers for which custom decoders are not set are decoded using the protopack library by default.

     auto decoder
         = std::make_shared< clientmap::decoder::DefaultSchemaDecoder >( );
    
     decoder->SetDecoder( clientmap::rendering::kRoadAttributeLayerName,
                          RoadAttributeLayerDecoder( ) );
    
  2. To access data from the HERE platform, create a Network instance.

     #include <olp/core/client/OlpClientSettingsFactory.h>
     ...
     auto network = olp::client::OlpClientSettingsFactory::
         CreateDefaultNetworkRequestHandler( );
    
  3. To handle requests asynchronously, create a TaskScheduler instance and specify the number of threads that the SDK should use.

    Note: If you do not define the TaskScheduler explicitly or set the number of threads to 1, HERE Data SDK for C++ will handle all requests synchronously.

     #include <olp/core/client/OlpClientSettingsFactory.h>
     ...
     const std::shared_ptr< olp::thread::TaskScheduler > task_scheduler
         = olp::client::OlpClientSettingsFactory::CreateDefaultTaskScheduler( 4u );
    
  4. Create a DataStoreServer instance that uses the DefaultSchemaDecoder, Network, and TaskSchedulerinstances.

    Note: If you do not set schema_decoder or set it to nullptr, the default clientmap::decoder::DefaultSchemaDecoder instance will be used.

     olp::clientmap::datastore::DataStoreServerSettings server_settings;
     server_settings.network_request_handler = network;
     server_settings.task_scheduler = task_scheduler;
     server_settings.schema_decoder = decoder;
    
     const auto server
         = std::make_shared< olp::clientmap::datastore::DataStoreServer >( server_settings );
    
  5. Initialize the DataStoreServer instance and cache.

     server->Init();
    

    If the operation is successful, you get the kNone error.

  6. Create a DataStoreClient instance using a shared pointer to the DataStoreServer instance.

     olp::clientmap::datastore::DataStoreClient client( server, {} );
    
  7. To access data from the OCM catalog, create an AuthenticationCredentials instance using your platform credentials.

    For instructions on how to get platform credentials, see the Get credentials section in the Getting Started Guide.

     boost::optional< olp::authentication::AuthenticationCredentials > credentials
         = olp::authentication::AuthenticationCredentials::ReadFromFile(
             "path-to-credentials-file" );
    
  8. Сreate an AuthenticationSettings instance using the AuthenticationCredentials, Network, and TaskScheduler instances.

     olp::authentication::Settings settings( credentials );
     settings.network_request_handler = network;
     settings.task_scheduler = task_scheduler;
    
     olp::client::AuthenticationSettings authentication_settings;
     authentication_settings.provider
         = olp::authentication::TokenProviderDefault( std::move( settings ) );
    
  9. Create a CatalogSettings instance using the AuthenticationSettings instance.

     olp::clientmap::datastore::CatalogSettings catalog_settings;
     catalog_settings.authentication_settings = authentication_settings;
    
  10. Configure DataStoreClient to get data from a specific version of the OCM catalog.

    If you do not set the version explicitly or set it to boost::none, the catalog version is set internally to the latest version that is available on the HERE platform when the catalog is added.

    Note: You cannot add two versions of the same catalog to the same DataStoreClient instance. To get data from different versions of the same catalog, create a DataStoreClient instance for each catalog version and add different versions of the catalog to different DataStoreClient instances.

    catalog_settings.version = "version_number";
    
  11. Add a catalog to the DataStoreServer instance using the HERE Resource Name (HRN) of the catalog and the CatalogSettings instance.

    const auto add_catalog_server =
        server->AddCatalog( kCatalogHrn, catalog_settings );
    
  12. Check if the AddCatalog operation is successful.

    if ( !add_catalog_server.IsSuccessful( ) )
    {
        OLP_SDK_LOG_WARNING_F( kLogTag, "Failed to add a catalog to server - error=%s",
                               ToString( add_catalog_server.GetError( ) ).c_str( ) );
        return EXIT_SUCCESS;
    }
    

    The operation can be unsuccessful if one of the following is true:

    • The catalog with the requested HRN does not exist.
    • DataStoreClient fails to check if the catalog with the requested HRN exists. Catalog existence is checked only if the catalog version is not set or set to boost::none.
  13. Add the same catalog to the DataStoreClient instance using the HRN of the catalog and the CatalogSettings instance.

    const auto add_catalog_result =
        client.AddCatalog( kCatalogHrn, catalog_settings );
    
  14. Check if the AddCatalog operation is successful.

    if ( !add_catalog_client.IsSuccessful( ) )
    {
        OLP_SDK_LOG_WARNING_F( kLogTag, "Failed to add a catalog to client - error=%s",
                               ToString( add_catalog_client.GetError( ) ).c_str( ) );
        return EXIT_SUCCESS;
    }
    

    The operation can be unsuccessful if one of the following is true:

    • The catalog with the requested HRN does not exist.
    • DataStoreClient fails to check if the catalog with the requested HRN exists. Catalog existence is checked only if the catalog version is not set or set to boost::none.
  15. If the AddCatalog operation is successful, to access data from the added catalog, save its CatalogHandle.

    const auto catalog_handle = add_catalog_result.GetResult( );
    
  16. Request the needed layer of a tile.

    Note: The RoadArrtibute layer is used as an example.

    clientmap::decoder::ClientMapTile tile;
    
    auto callback = [&]( const olp::clientmap::datastore::ClientMapTiles& catalog_tiles ) {
        tile = catalog_tiles[ catalog_handle ];
    };
    
    const auto error = client.Load( olp::clientmap::datastore::TileRequest( )
                                        .WithTileKey( kTileKey )
                                        .WithLayerGroup( clientmap::layergroup::kRendering )
                                        .WithLayer( clientmap::rendering::kRoadAttributeLayerName ),
                                    std::move( callback ) );
    
    if ( error != olp::clientmap::datastore::Error::kNone )
    {
        OLP_SDK_LOG_WARNING_F( kLogTag, "Failed to load the tile %s - error=%s",
                               kTileKey.ToHereTile( ).c_str( ), ToString( error ).c_str( ) );
        return EXIT_SUCCESS;
    }
    
  17. Check if the requested layer is present in the tile.

    if ( !tile.road_attribute_layer )
    {
        OLP_SDK_LOG_WARNING_F( kLogTag, "The RoadAttribute layer is not present in the tile %s",
                               kTileKey.ToHereTile( ).c_str( ) );
        return EXIT_SUCCESS;
    }
    
    if ( tile.road_attribute_layer->roads_size( ) > 0
         && tile.road_attribute_layer->roads( 0 ).attributes_size( ) > 0 )
    {
        const auto physical = tile.road_attribute_layer->roads( 0 ).attributes( 0 ).physical( );
    
        OLP_SDK_LOG_INFO_F( kLogTag,
                            "The physical characteristics for attribute 0 of segment 0 is %" PRIu32,
                            physical );
    }
    
    return EXIT_SUCCESS;
    

You have set a custom decoder function to decode the requested layer (RoadArrtibute).

The layer data that is decoded by the decoder instance is cached in the DataStoreClient memory tile cache, which is an LRU cache for the ClientMapTile instances that store decoded map data.

Read physical characteristic values

You can use AggregatedMessageReader to read the physical characteristic values from the decoded layer data.

To read the physical characteristic values:

  1. Set a custom decoder function to decode the needed layer.

    For instructions, see the related section in this example documentation.

  2. Read the physical values and distribute them across the parent messages.

     bool
     ReadPhysicalCharacteristic( protopack::internal::AggregatedMessageReader& reader,
                                 clientmap::decoder::RoadAttributeLayer& road_attribute_layer )
     { ...
     }
    

Read physical characteristic values of road segments

You can use the RoadAttributeDecoder structure to read physical characteristic values of road segments.

To read the physical characteristic values of the road segments:

  1. Set a custom decoder function to decode the needed layer.

    For instructions, see the related section in this example documentation.

  2. Create the RoadAttributeDecoder structure with the operator of the AbstractSchemaDecoder::LayerDecoderType type.

     struct RoadAttributeDecoder
     {
         bool
         operator( )( const void* data,
                     const int size,
                     clientmap::decoder::LayerConfigurationPtr configuration,
                     clientmap::decoder::ClientMapTile& tile ) const
         {
             // In the custom decoder function, in the `tile` instance,
             // set the layer configuration and decoded layer
             // data for a specific layer.
    
             // Set the layer configuration.
             tile.road_attribute_layer_configuration = std::move( configuration );
    
             // If the layer data is not present, do not set the layer data and
             // return.
             if ( data == nullptr || size <= 0 )
             {
                 return true;
             }
    
             // Decode the layer data. For this example, we only decode
             // the forward physical characteristic values.
             // To save time, the other values are not decoded.
             if ( !tile.arena )
             {
                 tile.arena = std::make_shared< clientmap::decoder::ClientMapTile::ArenaType >( );
             }
    
             auto* const layer
                 = google::protobuf::Arena::Create< clientmap::decoder::RoadAttributeLayer >(
                     tile.arena.get( ) );
    
             auto aggregated_message_reader = protopack::internal::AggregatedMessageReader::FromBuffer(
                 data, size, clientmap::decoder::RoadAttributeLayer::descriptor( ) );
    
             if ( !ReadPhysicalCharacteristic( aggregated_message_reader, *layer ) )
             {
                 return false;
             }
    
             tile.road_attribute_layer
                 = clientmap::decoder::LayerPtr< const clientmap::decoder::RoadAttributeLayer >(
                     tile.arena, layer );
    
             return true;
         }
    

results matching ""

    No results matching ""