Optimized Map Integration Module

The HERE Map Content format is designed primarily for map compilation. So accessing HERE Map Content directly is not efficient for the main use cases of the Location Library, routing and path-matching.

For optimized access, HERE provides the Optimized Map for Location Library which is a map format compiled from the HERE Map Content specifically for these main use cases.

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

Note

This chapter demonstrates accessing the Optimized Map for Location Library using the lower-level Component API. Usually, the level of control this API provides is not actually required. The chapter High-Level API shows how to use the simplified Location Library API to access the same information.

Create OptimizedMapVersionedLayers Objects

This section describes how to access the catalogs Optimized Map for Location Library and HERE Map Content in your app.

First, you have to create an instance of the BaseClient interface:

Scala
private val baseClient = BaseClient()

When you are done with manipulating catalogs, terminate the BaseClient as follows:

Scala
Await.result(baseClient.shutdown(), Duration.Inf)

When you are done with manipulating catalogs, you can optionally terminate the BaseClient.

The OptimizedMapVersionedLayers objectth implements OptimizedMapLayers, which allows you to read the data available in an Optimized Map for Location Library catalog through VersionedLayers.

To create an OptimizedMapVersionedLayers object for the Optimized Map for Location Library, use this BaseClient and the appropriate catalog HRN and version:

Scala
val optimizedMap: OptimizedMapVersionedLayers =
  OptimizedMapCatalog
    .from(optimizedMapHRN)
    .usingBaseClient(baseClient)
    .newInstance
    .version(optimizedMapVersion)

For more information on the definition of the HRN and version of the Optimized Map for Location Library, see the section Catalogs HRNs and versions.

Create Layer Objects

The data in the OptimizedMapLayers object is stored in pieces (tiles) in catalog layers. To load data from a particular layer, you can create a layer object by calling the following method:

Scala
val lengthLayer = optimizedMap.length

Each tile is uniquely identified by its TileId. These IDs are related the area that the data inside the tile describes, they follow the heretile partitioning scheme.

Layer objects expose reader methods for reading data by the TileId.

Retrieve Tiles Close to a Given Point

To easily discover which tiles contain the data for a particular area, Location Library provides TileResolvers.

You can get an instance of TileResolver by creating a HereTileResolver and providing it with a HereTileLevel with the zoom level of the layer.

Using a TileResolver you can, for example, look up the tiles that cover a circle of 1000m radius around the Brandenburger Tor as follows:

Scala
import com.here.platform.location.core.geospatial.GeoCoordinate
import com.here.platform.location.inmemory.geospatial.TileId
import com.here.platform.location.integration.herecommons.geospatial.{
  HereTileLevel,
  HereTileResolver
}

val lengthZoomLevel = optimizedMap.versionedLayers
  .versionedHereTileLayer(OptimizedMapLayers.RoadAccessLayerConfiguration.layerId)
  .zoomLevels
  .head
val tileResolver = new HereTileResolver(HereTileLevel(lengthZoomLevel))

val brandenburgerTor = GeoCoordinate(52.516268, 13.377700)
val radiusInMeters = 1000.0

val outputTiles =
  tileResolver.fromCenterAndRadius(brandenburgerTor, radiusInMeters)

val roadAccessLayer = optimizedMap.roadAccess
val readTiles = outputTiles.map(tile => (tile, roadAccessLayer.reader(tile)))

The only tile within 1000 meters of the Brandenburger Tor has the tile ID 1476150. You can search for this tile within the Road Topology & Geometry layer.

Resolve Compatible Version of the Optimized Map for Location Library and the HERE Map Content

If you use both the Optimized Map for Location Library and the HERE Map Content, make sure that the version of the HERE Map Content is compatible with the one of the Optimized Map for Location Library. The following snippet shows how to retrieve the correct HERE Map Content catalog:

Scala
import com.here.platform.data.client.v2.main.scaladsl.DataClient

val dataClient = DataClient()
try {
  val optimizedMap = dataClient
    .catalogBuilder(optimizedMapHRN)
    .build

  println(s"The latest OM4LL version is ${optimizedMap.versionInfo.latestVersion}")

  val om4llVersion = 3305L
  val hmcVersions = optimizedMap.versionInfo.resolveDependencyVersion(
    om4llVersion,
    hereMapContentHRN
  )

  println(
    s"An OM4LL version is $om4llVersion, the compatible HMC versions are ${hmcVersions.mkString(", ")}")
} finally {
  dataClient.shutdown()
}

Properties

Properties are values attached to vertices in the routing graph including the speed limit, accessibility by a particular type of vehicle or even the geometry (road shape). In HERE Map Content, these are called segment attributes.

Vertex Properties

Properties that always have just one value that applies for the whole vertex are represented as PropertyMaps. Vertex properties that are part of Optimized Map for Location Library are discussed in detail below.

Retrieve the Vertex for a Given Topology Segment

As mentioned in the section The Routing Graph, using vertices is more efficient to analyze properties of a given road segment than topology segments. The mapping layer of the Optimized Map for Location Library defines a mapping between vertices in the routing graph and road segments in HERE Map Content. This section demonstrates how to convert a topology segment into a vertex using this layer:

  1. Open https://platform.hereolp.cn/data/hrn:here-cn:data::olp-cn-here:here-map-content-china-2/topology-geometry/inspect.
  2. Click a topology segment.
  3. Expand the start_node_ref object and write down its identifier.
  4. To infer the direction of the segment, click the nodes at the ends of the segment and compare their identifiers with the identifier of the segment start_node_ref.
  5. To convert the topology segment, create a TileLoader for the mapping layer and a TiledReverseHereMapContentReferencePropertyMap. The TiledReverseHereMapContentReferencePropertyMap consumes the partition that the TileLoader produces for a given tile ID. The following code snippet demonstrates how to retrieve the vertex that corresponds to the topology segment here:cm:segment:94480838 in partition 23618402:

    Scala
    import com.here.platform.location.integration.heremapcontent.PartitionId
    import com.here.platform.location.integration.optimizedmap.geospatial.{
      HereMapContentReference,
      SegmentId
    }
    import com.here.platform.location.integration.optimizedmap.graph.{
      MappingTile,
      TiledReverseHereMapContentReferencePropertyMap
    }
    
    val mappingLayer = optimizedMap.mapping
    
    val mappingPartitions: Map[TileId, Option[MappingTile]] =
      outputTiles.map(tileId => (tileId, mappingLayer.reader(tileId))).toMap
    
    val optimizedMapMapping = new TiledReverseHereMapContentReferencePropertyMap(
      mappingPartitions,
      mappingLayer.tileResolver
    )
    
    val srcTopologySegment = HereMapContentReference(PartitionId("23618402"),
                                                     SegmentId("here:cm:segment:94480838"),
                                                     Forward)
    val vertex = optimizedMapMapping(srcTopologySegment)
    
    println(s"The topology segment $srcTopologySegment corresponds to the vertex $vertex")

Retrieve the Topology Segment for a Given Vertex

Several Location Library algorithms, such as proximity search, return vertices instead of topology segments. Vertices have two drawbacks:

Therefore, you may need to convert vertices to a topology segment. The following code snippet demonstrates how to perform this operation by creating a TileLoader for the mapping layer and a TiledHereMapContentReferencePropertyMap. The TiledHereMapContentReferencePropertyMap consumes the partition that the TileLoader produces for a given tile ID. The code snippet uses the vertex retrieved in the code snippet of the previous section.

Scala
import com.here.platform.location.integration.optimizedmap.geospatial.HereMapContentReference
import com.here.platform.location.integration.optimizedmap.graph.{
  MappingTile,
  TiledHereMapContentReferencePropertyMap
}

val mappingLayer = optimizedMap.mapping

val mappingPartitions: Map[TileId, Option[MappingTile]] =
  outputTiles.map(tileId => (tileId, mappingLayer.reader(tileId))).toMap

val hereMapContentMapping = new TiledHereMapContentReferencePropertyMap(mappingPartitions)

val topologySegment = hereMapContentMapping(vertex)
val HereMapContentReference(partitionId, segmentId, direction) = topologySegment

println(s"$vertex corresponds to the segment with identifier $segmentId")
println(s"  in HERE Map Content partition $partitionId")
println(s"  travelling in $direction direction, relative to the segment")

Retrieve the Geometry of a Given Vertex

As mentioned in The Routing Graph, a vertex represents travel in a particular direction along a road segment. The geometry layer in the Optimized Map for Location Library stores the shapes of the road segments. A tile of the layer contains the following:

  • The road shape of each segment that crosses the tile
  • A spatial index for efficient searches within a given area

Creating a property map from geometry layer partitions is enabled by TiledGeometryPropertyMap. The TiledGeometryPropertyMap returns a directed geometry for each vertex: the points of the geometry occur in the travel direction of this vertex.

Scala
import com.here.platform.location.core.graph.PropertyMap
import com.here.platform.location.inmemory.geospatial.{GeometryTile, PackedLineString}

val geometryLayer = optimizedMap.geometry

val geometryTiles: Iterable[(TileId, Option[GeometryTile])] =
  outputTiles.map(tileId => (tileId, geometryLayer.reader(tileId))).toMap
val geometry: PropertyMap[Vertex, PackedLineString] =
  new TiledGeometryPropertyMap(geometryTiles.toMap)

val tileId = outputTiles.head
val segmentIndex = SegmentIndex.fromVertexIndex(VertexIndex(10))

val forwardVertex = Vertex(tileId, segmentIndex.toVertexIndex(Forward))
val backwardVertex = Vertex(tileId, segmentIndex.toVertexIndex(Backward))

assert(geometry(forwardVertex).toIndexedSeq.reverse == geometry(backwardVertex).toIndexedSeq)

The Length Layer

The length layer provides the lengths of vertices in meters. To access the length of a vertex, you first have to create an TiledUndirectedPropertyMap that contains the length data. Then use this TiledUndirectedPropertyMap to access the length of a given vertex.

Scala
val lengthLayer = optimizedMap.length

val lengthPartitions: Iterable[(TileId, Option[UndirectedPropertyTile[Double]])] =
  outputTiles.map(tileId => (tileId, lengthLayer.reader(tileId))).toMap
val lengthProperty: PropertyMap[Vertex, Double] =
  new TiledUndirectedPropertyMap(lengthPartitions.toMap)

val lengthVertex = Vertex(outputTiles.head, VertexIndex(10))

val length = lengthProperty(lengthVertex)
println(s"The $lengthVertex is $length meters long.")

Range-Based Vertex Properties

From the Optimized Map for Location Library

The Optimized Map for Location Library contains some range based property layers that are compiled from HERE Map Content.

One example is the roadaccess layer, which contains information on what type of traffic can access a particular vertex.

Scala
val roadAccessType: RangeBasedPropertyMap[Vertex, RoadAccessType] =
  PropertyMaps(optimizedMap).roadAccess

val vertexHasCarAccessType: Boolean =
  roadAccessType(v, vertexFraction).get.value.intersects(RoadAccess.Automobile)

val isCarOrBusAccessible =
  PropertyMaps(optimizedMap)
    .roadAccess(RoadAccess.Automobile union RoadAccess.Bus)

val vertexIsCarOrBusAccessible: Boolean = isCarOrBusAccessible(v, vertexFraction).get.value

println(s"If $v has the car access type ($vertexHasCarAccessType) it is accessible")
println(s"for cars or buses ($vertexIsCarOrBusAccessible)")

Another example is the freeflowspeed layer, witch contains the speed at which a car is expected to traverse the various portions of a vertex geometry, under normal traffic conditions, expressed in km/h.

Scala
val freeFlowSpeed = PropertyMaps(optimizedMap).freeFlowSpeed
println(s"The free-flow speeds of $v are ${freeFlowSpeed(v)}")

results matching ""

    No results matching ""