GuidesChangelogData Inspector Library API Reference
Guides

Location Library high-level API

Location Library high-level API

The high-level API v2 of the Location Library provides a way to instantiate various kinds of path matchers and a number of factory methods to help you directly implement your algorithms using the following interfaces:

  • ProximitySearch To find topology segments (vertices) from coordinates.
    ProximitySearches
  • DirectedGraph To navigate the topology with an efficient data structure.
    Graphs
  • PropertyMap To access topology and ADAS attributes.
    PropertyMaps

The API also introduces a new cache mechanism which allows re-using blobs that are shared between different catalog versions. This allows a reduction in memory usage compared to the previous approach. The eviction strategy is defined on a catalog basis, allowing the evictions of the layers that are not used anymore.

Setting things up

Before you start using the API, you should add the location-integration-optimized-map-dcl2 dependency:

libraryDependencies ++= Seq(
  "com.here.platform.location" %% "location-integration-optimized-map-dcl2" % "<version>"
)
<dependencies>
    <dependency>
        <groupId>com.here.platform.location</groupId>
        <artifactId>location-integration-optimized-map-dcl2_${scala.compat.version}</artifactId>
    </dependency>
</dependencies>
dependencies {
    compile group: 'com.here.platform.location', name: 'location-integration-optimized-map-dcl2_2.13', version:'<version>'
}

Open a version of Optimized Map for Location Libraries

To start, you need to create an instance of OptimizedMapLayers, which is what the factory of all the algorithms require. You can do this based on a BaseClient instance: ```scala Scala import com.here.platform.data.client.base.scaladsl.BaseClient import com.here.platform.location.integration.optimizedmap.OptimizedMapLayers import com.here.platform.location.integration.optimizedmap.dcl2.OptimizedMapCatalog

val baseClient = BaseClient() val optimizedMap: OptimizedMapLayers = OptimizedMapCatalog.from(optimizedMapHRN).usingBaseClient(baseClient).newInstance.version(42)

```java Java
import com.here.platform.data.client.base.javadsl.BaseClient;
import com.here.platform.data.client.base.javadsl.BaseClientJava;
import com.here.platform.location.integration.optimizedmap.OptimizedMapLayers;
import com.here.platform.location.integration.optimizedmap.dcl2.javadsl.OptimizedMapCatalog;
BaseClient baseClient = BaseClientJava.instance();
OptimizedMapLayers optimizedMap =
    OptimizedMapCatalog.from(optimizedMapHRN)
        .usingBaseClient(baseClient)
        .newInstance()
        .version(42);

Proximity search

In order to associate places in the real world with vertices in the routing graph, ProximitySearch allows you to search for vertices within a certain distance from a point on the map.

You can create a ProximitySearch instance using its factory class ProximitySearches:

import com.here.platform.location.core.geospatial._
import com.here.platform.location.inmemory.graph.Vertex
import com.here.platform.location.integration.optimizedmap.geospatial.ProximitySearches

val proximitySearches: ProximitySearches = ProximitySearches(optimizedMap)
val proximitySearch: ProximitySearch[Vertex] = proximitySearches.vertices
val brandenburgerTor: GeoCoordinate = GeoCoordinate(52.516268, 13.377700)
val projections: Iterable[ElementProjection[Vertex]] =
  proximitySearch.search(center = brandenburgerTor, radiusInMeters = 100)
import com.here.platform.location.core.geospatial.ElementProjection;
import com.here.platform.location.core.geospatial.GeoCoordinate;
import com.here.platform.location.core.geospatial.javadsl.ProximitySearch;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.geospatial.javadsl.ProximitySearches;
ProximitySearches proximitySearches = new ProximitySearches(optimizedMap);
ProximitySearch<GeoCoordinate, Vertex> proximitySearch = proximitySearches.vertices();
GeoCoordinate brandenburgerTor = new GeoCoordinate(52.516268, 13.377700);
Iterable<ElementProjection<Vertex>> projections = proximitySearch.search(brandenburgerTor, 100);

Since the geometries of the vertices are not always rectilinear, in some cases you may want to get one ElementProjection for each segment of the geometry (the segment between consecutive pairs of points).

** Note **

The following image shows the results from the ProximitySearches.vertices. The search only returns the closest point for each vertex: One result per vertex

By using the ProximitySearches.vertexGeometrySegments variant, you have the option to get more than one projection for each vertex: One result for each geometry segment

Bounding box search

BoundingBoxSearch allows you to search for vertices intersecting a bounding box:

import com.here.platform.location.core.geospatial._
import com.here.platform.location.inmemory.graph.Vertex
import com.here.platform.location.integration.optimizedmap.geospatial.BoundingBoxSearches

val boundingBoxSearches: BoundingBoxSearches = BoundingBoxSearches(optimizedMap)
val boundingBoxSearch: BoundingBoxSearch[Vertex] = boundingBoxSearches.vertices
val berlin = BoundingBox(52.52818, 52.504154, 13.416698, 13.384168)
val vertices: Iterator[Vertex] = boundingBoxSearch.intersecting(berlin)
import com.here.platform.location.core.geospatial.BoundingBox;
import com.here.platform.location.core.geospatial.javadsl.BoundingBoxSearch;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.geospatial.javadsl.BoundingBoxSearches;
import java.util.Iterator;
BoundingBoxSearches boundingBoxSearches = new BoundingBoxSearches(optimizedMap);
BoundingBoxSearch<BoundingBox, Vertex> boundingBoxSearch = boundingBoxSearches.vertices();
BoundingBox berlin = new BoundingBox(52.52818, 52.504154, 13.416698, 13.384168);
Iterator<Vertex> vertices = boundingBoxSearch.intersecting(berlin);
Bounding Box Search

See GeoJSON Serialization to learn how to create GeoJSON data.

** Note **

For efficiency reasons the search may return duplicate vertices while iterating. If the searched area is small or memory is not a concern, you may want to convert the Iterator to a Set to remove duplicates.

Graph

You can navigate the road topology and geometry of the HERE Map Content using a graph abstraction. Each vertex of the graph represents a road (topology segment) in a direction, and each edge a physical connection between roads as explained in the Routing Graph section.

To create a DirectedGraph instance, you can use its factory class Graphs:

import com.here.platform.location.core.graph.DirectedGraph
import com.here.platform.location.inmemory.graph.{Edge, Vertex}
import com.here.platform.location.integration.optimizedmap.graph.Graphs

val graphs: Graphs = Graphs(optimizedMap)
val graph: DirectedGraph[Vertex, Edge] = graphs.forward
val outEdges: Iterator[Edge] = graph.outEdgeIterator(vertex)
import com.here.platform.location.core.graph.javadsl.DirectedGraph;
import com.here.platform.location.inmemory.graph.Edge;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.Graphs;
Graphs graphs = new Graphs(optimizedMap);
DirectedGraph<Vertex, Edge> graph = graphs.forward();
Iterator<Edge> outEdges = graph.getOutEdgeIterator(vertex);

** Note **

There are always two vertices associated with a road topology segment, one for each physical direction of travel. PropertyMaps can be used to gather attributes to make decisions, for example PropertyMaps.roadAccess described below can be used to derive information about the direction of travel for various modes of transport.

Path matcher

To resolve sequences of recorded geographical coordinates to paths on the road topology graph, you can use a path matcher. The path matcher will return information about the position on the road that most likely corresponds to each input point, and the most likely connection (transition) between points.

Path matching

** Note **

Dense and sparse traces of probe data

The sequence of recorded geographical coordinates is called trace or probe trace. The path matchers distinguish between dense and sparse traces. Dense traces are characterized by distances between consecutive probes that are short compared to lengths of the road segments in the map. Typically, probes collected every 1 to 5 seconds are considered dense.

You can create a PathMatcher instance using its factory class PathMatchers:

import com.here.platform.location.core.geospatial.GeoCoordinate
import com.here.platform.location.core.mapmatching.{MatchedPath, PathMatcher}
import com.here.platform.location.inmemory.graph.Vertex
import com.here.platform.location.integration.optimizedmap.mapmatching.PathMatchers

val pathMatchers = PathMatchers(optimizedMap)
val pathMatcher: PathMatcher[GeoCoordinate, Vertex, Seq[Vertex]] =
  pathMatchers.carPathMatcherWithTransitions
val matchedPath: MatchedPath[Vertex, Seq[Vertex]] = pathMatcher.matchPath(Seq(coordinates))
import com.here.platform.location.core.geospatial.javadsl.GeoCoordinateHolder;
import com.here.platform.location.core.mapmatching.javadsl.MatchedPath;
import com.here.platform.location.core.mapmatching.javadsl.PathMatcher;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.mapmatching.javadsl.PathMatchers;
PathMatchers pathMatchers = new PathMatchers(optimizedMap);
PathMatcher<GeoCoordinateHolder, Vertex, List<Vertex>> pathMatcher =
    pathMatchers.carPathMatcherWithTransitions();
MatchedPath<Vertex, List<Vertex>> matchedPath =
    pathMatcher.matchPath(Arrays.asList(coordinates));

In order to create path matchers, you can use various methods:

  • The unrestrictedPathMatcherWithoutTransitions creates a map matcher that produces results independent from any driving restriction, and is suitable for dense GPS traces (at least one point every 5 seconds).

    The unrestrictedPathMatcherWithoutTransitions is the most effective method to match to the most probably driven path for dense probes, and all vehicle types. You will not necessarily be able to follow this path by driving, but you can use the results to derive warnings about driving errors.

    The unrestrictedPathMatcherWithoutTransitions may introduce disconnections when consecutive points are not on directly connected topology segments, as it does not use any routing algorithm to compute the transitions.

    The unrestrictedPathMatcherWithTransitions variant will make a bigger effort to reconnect points with a simple shortest path algorithm.

  • The carPathMatcherWithTransitions takes most car driving restrictions into consideration, and is a path matcher specifically configured for cars and sparse data, but will also work on dense data. For example, this path matcher will only match input points to vertices that are accessible by cars according to the roadAccess property.

    The carPathMatcherWithTransitions works better than the unrestrictedPathMatcherWithTransitions for sparse data because it will route between points using a shortest path algorithm that takes into consideration road access and turn restrictions. In some situations, when consecutive points are too far apart (more than about 30 kilometers of on-road distance), they could be considered unreachable and one of them could be matched to Unknown.

    The carPathMatcherWithoutTransition variant is similar but is only suitable for dense data, where the distances between consecutive probes are short compared to vertex lengths in the map.

Starting from the Data SDK for Java & Scala 2.62 and Optimized Map for Location Libraries 5750 you can create the carPathMatcherWithoutTransitions or the carPathMatcherWithTransitions excluding under construction roads by using routingRoadAccess layer:

import com.here.platform.location.core.geospatial.GeoCoordinate
import com.here.platform.location.core.mapmatching.MatchedPath
import com.here.platform.location.inmemory.graph.Vertex
import com.here.platform.location.integration.optimizedmap.mapmatching.{
  CarPathMatcherLayers,
  PathMatchers
}

val layers = new CarPathMatcherLayers(optimizedMap.geometry,
                                      optimizedMap.length,
                                      optimizedMap.routingGraph,
                                      optimizedMap.restrictedManoeuvre,
                                      optimizedMap.routingRoadAccess)
val pathMatcher = PathMatchers.carPathMatcherWithTransitions[GeoCoordinate](layers)
val matchedPath: MatchedPath[Vertex, Seq[Vertex]] = pathMatcher.matchPath(Seq(coordinates))
import com.here.platform.location.core.geospatial.javadsl.GeoCoordinateHolder;
import com.here.platform.location.core.mapmatching.javadsl.MatchedPath;
import com.here.platform.location.core.mapmatching.javadsl.PathMatcher;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.mapmatching.CarPathMatcherLayers;
import com.here.platform.location.integration.optimizedmap.mapmatching.javadsl.PathMatchers;
import org.junit.Test;
CarPathMatcherLayers layers =
    new CarPathMatcherLayers(
        optimizedMap.geometry(),
        optimizedMap.length(),
        optimizedMap.routingGraph(),
        optimizedMap.restrictedManoeuvre(),
        optimizedMap.routingRoadAccess());
PathMatcher<GeoCoordinateHolder, Vertex, List<Vertex>> pathMatcher =
    PathMatchers.carPathMatcherWithTransitions(layers);
MatchedPath<Vertex, List<Vertex>> matchedPath =
    pathMatcher.matchPath(Arrays.asList(coordinates));

** Note **

For more details about the path matcher output, see the API Guide.

  • For advanced scenarios, you can construct an HMMPathMatcher directly, to specify desired path matcher dependencies.

Property maps

** Note: Migration to Topology Attributes **

The Road Attributes, Navigation Attributes, and Advanced Navigation Attributes layers are deprecated and will be removed in favor of the Topology Attributes layer.

If your application currently uses roadAttributes, navigationAttributes, or advancedNavigationAttributes PropertyMaps, you need to replace them with topologyAttributes PropertyMaps.

For details and migration examples, see the Migration to Topology Attributes page.

The Location Library provides property maps that allow you to access many map features.

To create a PropertyMap instance, you can use its factory class PropertyMaps and with that you can retrieve, for example, the length of a vertex:

import com.here.platform.location.core.graph._
import com.here.platform.location.inmemory.graph.Vertex
import com.here.platform.location.integration.optimizedmap.graph.PropertyMaps

val propertyMaps = PropertyMaps(optimizedMap)
val length: PropertyMap[Vertex, Double] = propertyMaps.length
val lengthOfAVertex: Double = length(vertex)
import com.here.platform.location.core.graph.javadsl.PropertyMap;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.PropertyMaps;
PropertyMaps propertyMaps = new PropertyMaps(optimizedMap);
PropertyMap<Vertex, Double> length = propertyMaps.length();
Double lengthOfAVertex = length.get(vertex);

On top of getting the length of a vertex, you can also:

import com.here.platform.location.core.graph.{PointBasedProperty, RangeBasedProperty}
import com.here.platform.location.integration.optimizedmap.advancednavigationattributes._
import com.here.platform.location.integration.optimizedmap.commonattributes.SpeedLimit
import com.here.platform.location.integration.optimizedmap.graph.PropertyMaps
import com.here.platform.location.integration.optimizedmap.navigationattributes._
import com.here.platform.location.integration.optimizedmap.roadattributes._

val topologyAttributes = PropertyMaps(optimizedMap).topologyAttributes

val functionalClasses: Seq[RangeBasedProperty[FunctionalClass]] =
  topologyAttributes.functionalClass(vertex)
val overpassUnderpasses: Seq[RangeBasedProperty[OverpassUnderpass]] =
  topologyAttributes.overpassUnderpass(vertex)
val officialCountryCodes: Seq[RangeBasedProperty[OfficialCountryCode]] =
  topologyAttributes.officialCountryCode(vertex)
val physicalAttributes: Seq[RangeBasedProperty[PhysicalAttribute]] =
  topologyAttributes.physicalAttribute(vertex)
val roadClasses: Seq[RangeBasedProperty[RoadClass]] = topologyAttributes.roadClass(vertex)
val specialTrafficAreaCategories: Seq[RangeBasedProperty[SpecialTrafficAreaCategory]] =
  topologyAttributes.specialTrafficAreaCategory(vertex)
val userDefinedCountryCodes: Seq[RangeBasedProperty[UserDefinedCountryCode]] =
  topologyAttributes.userDefinedCountryCode(vertex)
val tmcCodes: Seq[RangeBasedProperty[Set[TrafficMessageChannelCode]]] =
  topologyAttributes.trafficMessageChannelCodes(vertex)
val roadUsages: Seq[RangeBasedProperty[RoadUsage]] =
  topologyAttributes.roadUsage(vertex)
val intersectionInternalCategories: Seq[RangeBasedProperty[IntersectionInternalCategory]] =
  topologyAttributes.intersectionInternalCategory(vertex)
val laneCategories: Seq[RangeBasedProperty[LaneCategory]] =
  topologyAttributes.laneCategory(vertex)
val throughLaneCounts: Seq[RangeBasedProperty[Int]] =
  topologyAttributes.throughLaneCount(vertex)
val physicalLaneCounts: Seq[RangeBasedProperty[Int]] =
  topologyAttributes.physicalLaneCount(vertex)
val localRoads: Seq[RangeBasedProperty[LocalRoad]] =
  topologyAttributes.localRoad(vertex)
val lowMobilities: Seq[RangeBasedProperty[LowMobility]] =
  topologyAttributes.lowMobility(vertex)
val roadDividers: Seq[RangeBasedProperty[RoadDivider]] =
  topologyAttributes.roadDivider(vertex)
val speedCategories: Seq[RangeBasedProperty[SpeedCategory]] =
  topologyAttributes.speedCategory(vertex)
val supplementalGeometries: Seq[RangeBasedProperty[SupplementalGeometry]] =
  topologyAttributes.supplementalGeometry(vertex)
val urban: Seq[RangeBasedProperty[Boolean]] =
  topologyAttributes.urban(vertex)
val travelDirection: Seq[RangeBasedProperty[TravelDirection]] =
  topologyAttributes.travelDirection(vertex)
val specialExplication: Option[SpecialExplication] =
  topologyAttributes.specialExplication(edge)
val throughRoute: Option[ThroughRoute] =
  topologyAttributes.throughRoute(edge)
val railwayCrossings: Seq[PointBasedProperty[RailwayCrossing]] =
  topologyAttributes.railwayCrossing(vertex)
val gradeCategory: Seq[RangeBasedProperty[GradeCategory]] =
  topologyAttributes.gradeCategory(vertex)
val speedLimit: Seq[RangeBasedProperty[SpeedLimit]] =
  topologyAttributes.speedLimit(vertex)
val scenic: Seq[RangeBasedProperty[Scenic]] =
  topologyAttributes.scenic(vertex)
val trafficSignals: Seq[PointBasedProperty[SignLocation]] =
  topologyAttributes.trafficSignal(vertex)
import com.here.platform.location.core.graph.javadsl.*;
import com.here.platform.location.inmemory.graph.Edge;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.advancednavigationattributes.GradeCategory;
import com.here.platform.location.integration.optimizedmap.advancednavigationattributes.RailwayCrossing;
import com.here.platform.location.integration.optimizedmap.advancednavigationattributes.Scenic;
import com.here.platform.location.integration.optimizedmap.advancednavigationattributes.SignLocation;
import com.here.platform.location.integration.optimizedmap.commonattributes.SpeedLimit;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.PropertyMaps;
import com.here.platform.location.integration.optimizedmap.navigationattributes.*;
import com.here.platform.location.integration.optimizedmap.roadattributes.*;
PropertyMaps.TopologyAttributes topologyAttributes =
    new PropertyMaps(optimizedMap).topologyAttributes();

RangeBasedPropertyMap<Vertex, FunctionalClass> functionalClass =
    topologyAttributes.functionalClass();
List<RangeBasedProperty<FunctionalClass>> functionalClasses = functionalClass.get(vertex);

RangeBasedPropertyMap<Vertex, OverpassUnderpass> overpassUnderpass =
    topologyAttributes.overpassUnderpass();
List<RangeBasedProperty<OverpassUnderpass>> overpassUnderpasses = overpassUnderpass.get(vertex);

RangeBasedPropertyMap<Vertex, OfficialCountryCode> officialCountryCode =
    topologyAttributes.officialCountryCode();
List<RangeBasedProperty<OfficialCountryCode>> officialCountryCodes =
    officialCountryCode.get(vertex);

RangeBasedPropertyMap<Vertex, PhysicalAttribute> physicalAttribute =
    topologyAttributes.physicalAttribute();
List<RangeBasedProperty<PhysicalAttribute>> physicalAttributes = physicalAttribute.get(vertex);

RangeBasedPropertyMap<Vertex, RoadClass> roadClass = topologyAttributes.roadClass();
List<RangeBasedProperty<RoadClass>> roadClasses = roadClass.get(vertex);

RangeBasedPropertyMap<Vertex, SpecialTrafficAreaCategory> specialTrafficAreaCategory =
    topologyAttributes.specialTrafficAreaCategory();
List<RangeBasedProperty<SpecialTrafficAreaCategory>> specialTrafficAreaCategories =
    specialTrafficAreaCategory.get(vertex);

List<RangeBasedProperty<UserDefinedCountryCode>> userDefinedCountryCodes =
    topologyAttributes.userDefinedCountryCode().get(vertex);

RangeBasedPropertyMap<Vertex, Set<TrafficMessageChannelCode>> trafficMessageChannelCodes =
    topologyAttributes.trafficMessageChannelCodes();
List<RangeBasedProperty<Set<TrafficMessageChannelCode>>> tmcCodes =
    trafficMessageChannelCodes.get(vertex);

RangeBasedPropertyMap<Vertex, RoadUsage> roadUsage = topologyAttributes.roadUsage();
List<RangeBasedProperty<RoadUsage>> roadUsages = roadUsage.get(vertex);

RangeBasedPropertyMap<Vertex, IntersectionInternalCategory> intersectionInternalCategory =
    topologyAttributes.intersectionInternalCategory();
List<RangeBasedProperty<IntersectionInternalCategory>> intersectionInternalCategories =
    intersectionInternalCategory.get(vertex);

RangeBasedPropertyMap<Vertex, LaneCategory> laneCategory = topologyAttributes.laneCategory();
List<RangeBasedProperty<LaneCategory>> laneCategories = laneCategory.get(vertex);

RangeBasedPropertyMap<Vertex, Integer> throughLaneCount = topologyAttributes.throughLaneCount();
List<RangeBasedProperty<Integer>> throughLaneCounts = throughLaneCount.get(vertex);

RangeBasedPropertyMap<Vertex, Integer> physicalLaneCount =
    topologyAttributes.physicalLaneCount();
List<RangeBasedProperty<Integer>> physicalLaneCounts = physicalLaneCount.get(vertex);

RangeBasedPropertyMap<Vertex, LocalRoad> localRoad = topologyAttributes.localRoad();
List<RangeBasedProperty<LocalRoad>> localRoads = localRoad.get(vertex);

RangeBasedPropertyMap<Vertex, LowMobility> lowMobility = topologyAttributes.lowMobility();
List<RangeBasedProperty<LowMobility>> lowMobilities = lowMobility.get(vertex);

RangeBasedPropertyMap<Vertex, RoadDivider> roadDivider = topologyAttributes.roadDivider();
List<RangeBasedProperty<RoadDivider>> roadDividers = roadDivider.get(vertex);

RangeBasedPropertyMap<Vertex, SpeedCategory> speedCategory = topologyAttributes.speedCategory();
List<RangeBasedProperty<SpeedCategory>> speedCategories = speedCategory.get(vertex);

RangeBasedPropertyMap<Vertex, SupplementalGeometry> supplementalGeometry =
    topologyAttributes.supplementalGeometry();
List<RangeBasedProperty<SupplementalGeometry>> supplementalGeometries =
    supplementalGeometry.get(vertex);

RangeBasedPropertyMap<Vertex, Boolean> urban = topologyAttributes.urban();
List<RangeBasedProperty<Boolean>> urbans = urban.get(vertex);

RangeBasedPropertyMap<Vertex, TravelDirection> travelDirection =
    topologyAttributes.travelDirection();
List<RangeBasedProperty<TravelDirection>> travelDirections = travelDirection.get(vertex);

PropertyMap<Edge, Optional<SpecialExplication>> specialExplication =
    topologyAttributes.specialExplication();
Optional<SpecialExplication> specialExplications = specialExplication.get(edge);

PropertyMap<Edge, Optional<ThroughRoute>> throughRoute = topologyAttributes.throughRoute();
Optional<ThroughRoute> throughRoutes = throughRoute.get(edge);

PointBasedPropertyMap<Vertex, RailwayCrossing> railwayCrossing =
    topologyAttributes.railwayCrossing();
List<PointBasedProperty<RailwayCrossing>> railwayCrossings = railwayCrossing.get(vertex);

RangeBasedPropertyMap<Vertex, GradeCategory> gradeCategory = topologyAttributes.gradeCategory();
List<RangeBasedProperty<GradeCategory>> gradeCategories = gradeCategory.get(vertex);

RangeBasedPropertyMap<Vertex, SpeedLimit> speedLimit = topologyAttributes.speedLimit();
List<RangeBasedProperty<SpeedLimit>> speedLimits = speedLimit.get(vertex);

RangeBasedPropertyMap<Vertex, Scenic> scenic = topologyAttributes.scenic();
List<RangeBasedProperty<Scenic>> scenics = scenic.get(vertex);

PointBasedPropertyMap<Vertex, SignLocation> trafficSignal = topologyAttributes.trafficSignal();
List<PointBasedProperty<SignLocation>> trafficSignals = trafficSignal.get(vertex);
import com.here.platform.location.core.graph.{PointBasedProperty, RangeBasedProperty}
import com.here.platform.location.integration.optimizedmap.adasattributes._
import com.here.platform.location.integration.optimizedmap.graph.PropertyMaps

val adasAttributes = PropertyMaps(optimizedMap).adasAttributes

val builtUpAreaRoad: Seq[RangeBasedProperty[BuiltUpAreaRoad]] =
  adasAttributes.builtUpAreaRoad(vertex)
val linkAccuracy: Seq[RangeBasedProperty[Int]] = adasAttributes.linkAccuracy(vertex)
val slope: Seq[PointBasedProperty[Slope]] = adasAttributes.slope(vertex)
val curvature: Seq[PointBasedProperty[Int]] =
  adasAttributes.curvature(vertex)
val heading: Seq[PointBasedProperty[Int]] =
  adasAttributes.heading(vertex)
val edgeCurvature: Option[Int] =
  adasAttributes.edgeCurvature(edge)
val edgeHeading: Option[Int] =
  adasAttributes.edgeHeading(edge)
val elevation: Seq[PointBasedProperty[Elevation]] =
  adasAttributes.elevation(vertex)
import com.here.platform.location.core.graph.javadsl.*;
import com.here.platform.location.inmemory.graph.Edge;
import com.here.platform.location.inmemory.graph.Vertex;
import com.here.platform.location.integration.optimizedmap.adasattributes.BuiltUpAreaRoad;
import com.here.platform.location.integration.optimizedmap.adasattributes.Elevation;
import com.here.platform.location.integration.optimizedmap.adasattributes.Slope;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.PropertyMaps;
PropertyMaps.AdasAttributes adasAttributes = new PropertyMaps(optimizedMap).adasAttributes();

RangeBasedPropertyMap<Vertex, BuiltUpAreaRoad> builtUpAreaRoad =
    adasAttributes.builtUpAreaRoad();
List<RangeBasedProperty<BuiltUpAreaRoad>> builtUpAreaRoads = builtUpAreaRoad.get(vertex);

RangeBasedPropertyMap<Vertex, Integer> linkAccuracy = adasAttributes.linkAccuracy();
List<RangeBasedProperty<Integer>> linkAccuracies = linkAccuracy.get(vertex);

PointBasedPropertyMap<Vertex, Slope> slope = adasAttributes.slope();
List<PointBasedProperty<Slope>> slopes = slope.get(vertex);

PointBasedPropertyMap<Vertex, Integer> curvature = adasAttributes.curvature();
List<PointBasedProperty<Integer>> curvatures = curvature.get(vertex);

PointBasedPropertyMap<Vertex, Integer> heading = adasAttributes.heading();
List<PointBasedProperty<Integer>> headings = heading.get(vertex);

PropertyMap<Edge, OptionalInt> edgeCurvature = adasAttributes.edgeCurvature();
OptionalInt edgeCurvatures = edgeCurvature.get(edge);

PropertyMap<Edge, OptionalInt> edgeHeading = adasAttributes.edgeHeading();
OptionalInt edgeHeadings = edgeHeading.get(edge);

PointBasedPropertyMap<Vertex, Elevation> elevation = adasAttributes.elevation();
List<PointBasedProperty<Elevation>> elevations = elevation.get(vertex);

Cache configuration

Basic configuration and statistics

OptimizedMapCatalog allows to set the amount of bytes to be used by the blob cache and the number of entries to be used by the metadata cache. When the number of metadata cache entries is not specified, a reasonable default based on blob cache size is used.

Once your cache is loaded with data, it can be inspected to know few important statistics:

import com.here.platform.data.client.base.scaladsl.BaseClient
import com.here.platform.data.client.v2.api.scaladsl.versioned.CachingVersionedLayers
import com.here.platform.location.integration.optimizedmap.dcl2.OptimizedMapCatalog

val baseClient: BaseClient = BaseClient()
val optimizedMap: OptimizedMapCatalog =
  OptimizedMapCatalog
    .from(optimizedMapHRN)
    .usingBaseClient(baseClient)
    .withMaxBlobCacheSizeBytes(100L * 1024 * 1024)
    .withMaxMetadataCacheEntryCount(10000L)
    .newInstance
val versionedLayers: CachingVersionedLayers = optimizedMap.versionedLayers
println(versionedLayers.blobCacheStats)
println(versionedLayers.metadataCacheStats)
import com.here.platform.data.client.base.javadsl.BaseClient;
import com.here.platform.data.client.base.javadsl.BaseClientJava;
import com.here.platform.data.client.v2.api.javadsl.versioned.CachingVersionedLayers;
import com.here.platform.location.integration.optimizedmap.dcl2.javadsl.OptimizedMapCatalog;
BaseClient baseClient = BaseClientJava.instance();
OptimizedMapCatalog optimizedMap =
    OptimizedMapCatalog.from(optimizedMapHRN)
        .usingBaseClient(baseClient)
        .withMaxBlobCacheSizeBytes(100 * 1024 * 1024)
        .withMaxMetadataCacheEntryCount(10000)
        .newInstance();
CachingVersionedLayers versionedLayers = optimizedMap.versionedLayers();
System.out.println(versionedLayers.getBlobCacheStats());
System.out.println(versionedLayers.getMetadataCacheStats());

Retain only required attributes

When accessing attributes, for example via PropertyMaps.roadAttributes, all available attributes in the layer are cached in memory by default. This can lead to suboptimal memory usage, as unnecessary data consumes space within the allocated cache budget.

To reduce memory overhead, specify only the attributes you need. Note that any attributes not specified will be unavailable at runtime.

The following methods in the OptimizedMapCatalog DSL allow you to define which attributes to retain:

  • withTopologyAttributes
  • withAdasAttributes
import com.here.platform.data.client.base.scaladsl.BaseClient
import com.here.platform.location.compilation.heremapcontent.TopologyAttributeDescription
import com.here.platform.location.core.graph.RangeBasedProperty
import com.here.platform.location.integration.optimizedmap.OptimizedMapLayers
import com.here.platform.location.integration.optimizedmap.dcl2.OptimizedMapCatalog
import com.here.platform.location.integration.optimizedmap.graph.PropertyMaps
import com.here.platform.location.integration.optimizedmap.roadattributes._

import scala.util.Try

val baseClient: BaseClient = BaseClient()
val optimizedMap: OptimizedMapLayers =
  OptimizedMapCatalog
    .from(optimizedMapHRN)
    .usingBaseClient(baseClient)
    .withTopologyAttributes(TopologyAttributeDescription.FunctionalClass,
                            TopologyAttributeDescription.PhysicalAttribute)
    .newInstance
    .latest

val topologyAttributes: PropertyMaps.TopologyAttributes =
  PropertyMaps(optimizedMap).topologyAttributes

val functionalClasses: Seq[RangeBasedProperty[FunctionalClass]] =
  topologyAttributes.functionalClass(vertex)

val physicalAttributes: Seq[RangeBasedProperty[PhysicalAttribute]] =
  topologyAttributes.physicalAttribute(vertex)

val officialCountryCodes: Try[Seq[RangeBasedProperty[OfficialCountryCode]]] =
  Try(topologyAttributes.officialCountryCode(vertex))

assert(officialCountryCodes.isFailure)
import com.here.platform.data.client.base.javadsl.BaseClient;
import com.here.platform.data.client.base.javadsl.BaseClientJava;
import com.here.platform.location.compilation.heremapcontent.TopologyAttributeDescription;
import com.here.platform.location.core.graph.javadsl.RangeBasedProperty;
import com.here.platform.location.integration.optimizedmap.OptimizedMapLayers;
import com.here.platform.location.integration.optimizedmap.dcl2.javadsl.OptimizedMapCatalog;
import com.here.platform.location.integration.optimizedmap.graph.javadsl.PropertyMaps;
import com.here.platform.location.integration.optimizedmap.roadattributes.FunctionalClass;
import com.here.platform.location.integration.optimizedmap.roadattributes.OfficialCountryCode;
import com.here.platform.location.integration.optimizedmap.roadattributes.PhysicalAttribute;
import java.util.List;
BaseClient baseClient = BaseClientJava.instance();
OptimizedMapLayers optimizedMap =
    OptimizedMapCatalog.from(optimizedMapHRN)
        .usingBaseClient(baseClient)
        .withTopologyAttributes(
            TopologyAttributeDescription.FunctionalClass(),
            TopologyAttributeDescription.PhysicalAttribute())
        .newInstance()
        .latest();

PropertyMaps.TopologyAttributes topologyAttributes =
    new PropertyMaps(optimizedMap).topologyAttributes();

List<RangeBasedProperty<FunctionalClass>> functionalClass =
    topologyAttributes.functionalClass().get(vertex);

List<RangeBasedProperty<PhysicalAttribute>> physicalAttribute =
    topologyAttributes.physicalAttribute().get(vertex);

try {
  List<RangeBasedProperty<OfficialCountryCode>> officialCountryCodeRangeBasedProperty =
      topologyAttributes.officialCountryCode().get(vertex);
} catch (IllegalArgumentException e) {
}

Re-use an externally created cache

There are cases when you need to re-use an externally created cache for various reasons, for example if you want to pass a pre-filled cache to OptimizedMapLayers:

import com.here.platform.data.client.base.scaladsl.BaseClient
import com.here.platform.data.client.v2.api.scaladsl.versioned.CachingVersionedLayers
import com.here.platform.data.client.v2.caching.caffeine.scaladsl._
import com.here.platform.location.integration.optimizedmap.OptimizedMapLayers
import com.here.platform.location.integration.optimizedmap.dcl2.{
  OptimizedMapCatalog,
  OptimizedMapVersionedLayers
}

val baseClient = BaseClient()
val versionedLayerReadersConfiguration = OptimizedMapCatalog.versionedLayerReadersConfiguration(
  maxBlobCacheSizeBytes = 100 * 1024 * 1024)

val blobCache = BlobCacheBuilder(versionedLayerReadersConfiguration).build
val metadataCache = MetadataCacheBuilder(versionedLayerReadersConfiguration).build

val optimizedMapCatalog = OptimizedMapCatalog
  .from(optimizedMapHRN)
  .usingBaseClient(baseClient)
  .withVersionedLayerReadersCache(versionedLayerReadersConfiguration, blobCache, metadataCache)
  .newInstance

val optimizedMap: OptimizedMapLayers =
  new OptimizedMapVersionedLayers(optimizedMapCatalog.versionedLayers, 42)

val versionedLayers: CachingVersionedLayers = optimizedMapCatalog.versionedLayers
println(versionedLayers.blobCacheStats)
println(versionedLayers.metadataCacheStats)
import com.github.benmanes.caffeine.cache.Cache;
import com.here.platform.data.client.base.javadsl.BaseClient;
import com.here.platform.data.client.base.javadsl.BaseClientJava;
import com.here.platform.data.client.v2.api.javadsl.versioned.CachingVersionedLayers;
import com.here.platform.data.client.v2.caching.caffeine.javadsl.BlobCacheBuilder;
import com.here.platform.data.client.v2.caching.caffeine.javadsl.MetadataCacheBuilder;
import com.here.platform.data.client.v2.caching.javadsl.versioned.VersionedLayerReadersConfiguration;
import com.here.platform.data.client.v2.caching.model.versioned.LayerMetadata;
import com.here.platform.data.client.v2.caching.model.versioned.LayerMetadataKey;
import com.here.platform.data.client.v2.caching.model.versioned.OptionalLayerMetadata;
import com.here.platform.location.integration.optimizedmap.OptimizedMapLayers;
import com.here.platform.location.integration.optimizedmap.dcl2.javadsl.OptimizedMapCatalog;
BaseClient baseClient = BaseClientJava.instance();

VersionedLayerReadersConfiguration versionedLayerReadersConfiguration =
    OptimizedMapCatalog.newVersionedLayerReadersConfigurationBuilder()
        .withMaxBlobCacheSizeBytes(100 * 1024 * 1024)
        .build();

Cache<LayerMetadata, Object> blobCache =
    new BlobCacheBuilder(versionedLayerReadersConfiguration).build();
Cache<LayerMetadataKey, OptionalLayerMetadata> metadataCache =
    new MetadataCacheBuilder(versionedLayerReadersConfiguration).build();

OptimizedMapCatalog optimizedMapCatalog =
    OptimizedMapCatalog.from(optimizedMapHRN)
        .usingBaseClient(baseClient)
        .withVersionedLayerReadersCache(
            versionedLayerReadersConfiguration, blobCache, metadataCache)
        .newInstance();

OptimizedMapLayers optimizedMap = optimizedMapCatalog.version(42);

CachingVersionedLayers versionedLayers = optimizedMapCatalog.versionedLayers();
System.out.println(versionedLayers.getBlobCacheStats());
System.out.println(versionedLayers.getMetadataCacheStats());

Find latest version of a catalog

The CatalogVersionInfo class provides information about the versions of a given catalog. For detailed information, you can refer to the related documentation in java or scala.
The Location Library allows to obtain a CatalogVersionInfo object from an OptimizedMapCatalog, which you can use to retrieve the latest version of a catalog as follows:

import com.here.platform.data.client.base.scaladsl.BaseClient
import com.here.platform.data.client.v2.api.scaladsl.CatalogVersionInfo
import com.here.platform.location.integration.optimizedmap.dcl2.OptimizedMapCatalog

val baseClient = BaseClient()
val optimizedMapCatalog: OptimizedMapCatalog =
  OptimizedMapCatalog.from(optimizedMapHRN).usingBaseClient(baseClient).newInstance
val optimizedMapVersionInfo: CatalogVersionInfo = optimizedMapCatalog.versionInfo
val latestVersion: Option[Long] = optimizedMapVersionInfo.latestVersion
import com.here.platform.data.client.base.javadsl.BaseClient;
import com.here.platform.data.client.base.javadsl.BaseClientJava;
import com.here.platform.data.client.v2.api.javadsl.CatalogVersionInfo;
import com.here.platform.location.integration.optimizedmap.dcl2.javadsl.OptimizedMapCatalog;
BaseClient baseClient = BaseClientJava.instance();
OptimizedMapCatalog optimizedMapCatalog =
    OptimizedMapCatalog.from(optimizedMapHRN).usingBaseClient(baseClient).newInstance();
CatalogVersionInfo optimizedMapVersionInfo = optimizedMapCatalog.versionInfo();
OptionalLong latestVersion = optimizedMapVersionInfo.latestVersion();

For more advanced usages of CatalogVersionInfo, such as resolving compatible catalog versions, see How to resolve catalog versions.