Some services, such as HERE Maps, require you to display attributions when using their data on the map. LuciadCPillar keeps track of the attributions from all layers that provide attribution data, and exposes an API to retrieve these attributions.

here maps attribution
Figure 1. The Data formats sample displays the current HERE Maps attributions in the bottom right corner of the map. As the user pans the map, the attributions are updated to reflect the newly visible region.

Retrieving the attributions on a map

The attributions on a map are exposed through MapAttributionsMapAttributionsMapAttributions. You can get attributions from all layers, or request the attributions of a specific layer. Layers that aren’t visible aren’t included.

Program: Retrieving attributions from the map.
const MapAttributions& mapAttributions = map->getAttributions();
const std::vector<DataAttribution>& allDataAttributions = mapAttributions.getAllAttributions();
std::optional<DataAttribution> attributionForOneLayer = mapAttributions.getAttribution(layerId);
MapAttributions mapAttributions = map.Attributions;
IList<DataAttribution> allDataAttributions = mapAttributions.AllAttributions;
DataAttribution attributionForOneLayer = mapAttributions.GetAttribution(layerId);
MapAttributions mapAttributions = map.getAttributions();
List<DataAttribution> allDataAttributions = mapAttributions.getAllAttributions();
DataAttribution attributionForOneLayer = mapAttributions.getAttribution(layerId);

To receive events when any of these attributions change, register an IMapObserverIMapObserverIMapObserver on the map and filter on the attributions property:

Program: Observing the map for attribution changes.
map->addObserver(IMapObserver::create([](const MapEvent& event) {
  if (event.getChangedProperty() != Map::propertyAttributions()) {
    return;
  }
  // Do something with the attributions, e.g. format and show on the UI
  std::stringstream ss;
  const MapAttributions& mapAttributions = event.getMap()->getAttributions();
  const auto& attributions = mapAttributions.getAllAttributions();
  for (auto it = attributions.rbegin(); it != attributions.rend(); it++) {
    const auto& attribution = *it;
    for (const auto& attributionString : attribution.getAttributionStrings()) {
      ss << attributionString << "\n";
    }
  }
  std::cout << "New attributions:\n" << ss.str();
}));
class MyMapObserver : IMapObserver
{
    public void OnMapChanged(MapEvent mapEvent)
    {
        if (mapEvent.ChangedProperty != Map.PropertyAttributions)
        {
            return;
        }
        // Do something with the attributions, e.g. format and show on the UI
        string total = "";
        var mapAttributions = mapEvent.Map.Attributions;
        var attributions = mapAttributions.AllAttributions;
        foreach (var attribution in attributions.Reverse())
        {
            foreach (var attributionString in attribution.AttributionStrings)
            {
                total += "\n" + attributionString;
            }
        }
        Console.WriteLine("New attributions:\n" + total);
    }
}

var myMapObserver = new MyMapObserver();
map.AddObserver(myMapObserver);
map.addObserver(mapEvent -> {
    if (!mapEvent.getChangedProperty().equals(Map.PropertyAttributions)) {
        return;
    }
    // Do something with the attributions, e.g. format and show on the UI
    StringBuilder total = new StringBuilder();
    var mapAttributions = mapEvent.getMap().getAttributions();
    var attributions = mapAttributions.getAllAttributions();
    for (int i = attributions.size() - 1; i >= 0; i--) {
        var attribution = attributions.get(i);
        for (var attributionString : attribution.getAttributionStrings()) {
            total.append(attributionString + "\n");
        }
    }
    Log.d("Attributions", "New attributions:\n" + total);
});

Providing attribution data

For a RasterLayerRasterLayerRasterLayer with a multi-level tiled raster model or quad tree raster model, you can provide your own attribution based on the currently displayed tiles using an IMultilevelTiledAttributionProviderIMultilevelTiledAttributionProviderIMultilevelTiledAttributionProvider.

Program: Providing attribution for a QuadTreeRasterModel.
std::shared_ptr<IMultilevelTiledAttributionProvider> myAttributionProvider = IMultilevelTiledAttributionProvider::create(
    [](const std::vector<MultilevelTileInfo>& /*tiles*/, const CancellationToken& /*cancellationToken*/) {
      // Search through the tiles and return the appropriate attribution strings
      std::vector<std::string> strings{"Attribution 1", "Attribution 2"};
      return DataAttribution{strings};
    });

auto model = QuadTreeRasterModelBuilder::newBuilder()
                 .attributionProvider(myAttributionProvider)
                 ...
                 .build();
class MyAttributionProvider : IMultilevelTiledAttributionProvider
{
    public DataAttribution GetAttribution(IList<MultilevelTileInfo> tiles, CancellationToken cancellationToken)
    {
        // Search through the tiles and return the appropriate attribution strings
        List<string> strings = new List<string> { "Attribution 1", "Attribution 2" };
        return new DataAttribution(strings);
    }
}

var myAttributionProvider = new MyAttributionProvider();
var model = QuadTreeRasterModelBuilder.NewBuilder()
                .AttributionProvider(myAttributionProvider)
                ...
                .Build();
IMultilevelTiledAttributionProvider myAttributionProvider = (tiles, cancellationToken) -> {
    // Search through the tiles and return the appropriate attribution strings
    List<String> strings = List.of("Attribution 1", "Attribution 2");
    return new DataAttribution(strings);
};

var model = QuadTreeRasterModelBuilder.newBuilder()
                .attributionProvider(myAttributionProvider)
                ...
                .build();