Beta
Navigation SDK for Android v2

Electronic horizon

Mapbox Electronic Horizon is a feature of the Mapbox Navigation SDK that surfaces map data along the probable path (or paths) of a vehicle within the road network to anticipate conditions beyond the physical "visible" horizon.

The data provided by the electronic horizon enables capabilities like adaptive cruise control, proactive driver alerts for upcoming congestion, speed change and dangerous curves, and available alternative paths. Mapbox Electronic Horizon is designed for Advanced Driver Assistance Systems (ADAS) for in-vehicle deployment, but it can also be used in mobile Android applications.

Active guidance and free drive mode

The Mapbox Navigation SDK allows users to navigate in two different modes: active guidance and free-drive mode. The electronic horizon feature works in both modes.

When navigation is in Active guidance mode the user-selected route and its metadata are used as the path for the electronic horizon.

When navigation is in Free-drive mode the electronic horizon will determine the most probable path from the vehicle's current location.

For both active guidance and free-drive, the electronic horizon and its metadata are exposed via the same interface in the Navigation SDK as described below.

Most probable path (MPP)

Mapbox Electronic Horizon represents the road network ahead of the user as a tree of edges. Each intersection has outbound edges and each edge has a probability of transition to another edge as well as metadata that can be used to implement sophisticated features on top of it.

Based on the device's location and user-selected route (if applicable), Mapbox Electronic Horizon determines the most likely path a user may take and provides a most probable path (MPP). The MPP contains data in a tree-like structure where edges have a level attribute equal to 0 and side-branches have a level attribute equal to 1 or higher based on their position relative to the current edge.

In most cases the electronic horizon will return one MPP, but if there are two or more alternatives at an intersection that have a similar probability (a difference less or equal to 5%) the electronic horizon might return several MPP paths. You can choose the MPP with a slightly higher probability or, if you have additional information about the road conditions, you can suggest which MPP the user should choose.

How to configure the electronic horizon

EHorizonOptions defines the options for the EHorizon.

AttributeDescriptionTypeDefault value
lengthThe minimum length of the MPP in meters. This does not include the trailingLength. The actual MPP length may be bigger.Double in range [1.0, 10000.0]500
expansionThe number of branches to include from the MPP. When set to 0 only the MPP is returned. Higher values will result in deeper nesting.Int in range [0, 2]0
branchLengthWhen expansion is set to anything but 0, this specifies the minimum length in meters branches will be expanded from the MPP.Double in range [1.0, 5000.0]50
minTimeDeltaBetweenUpdatesThe minimum time which should pass between consecutive navigation statuses to update the electronic horizon (seconds). If null the horizon will be updated on each navigation status.Doublenull

These can be specified through the NavigationOptions.

The electronic horizon data

To get the electronic horizon data you can use callbacks and direct calls. With callbacks you get only the most important data, which can be more efficient and save resources. If you need additional data (for example: edge metadata, edge shape, road object metadata) you can make a direct call.

Note

The electronic horizon callbacks are only fired when the trip session is started and external resources, navigation tiles, are downloaded, so callbacks might not fire right away.

The electronic horizon callbacks

Create the EHorizonObserver interface object:

interface EHorizonObserver {

    fun onPositionUpdated(position: EHorizonPosition, distances: Map<String, EHorizonObjectDistanceInfo>)

    fun onRoadObjectEnter(objectEnterExitInfo: EHorizonObjectEnterExitInfo)

    fun onRoadObjectExit(objectEnterExitInfo: EHorizonObjectEnterExitInfo)

    fun onRoadObjectAdded(roadObjectId: String)

    fun onRoadObjectUpdated(roadObjectId: String)

    fun onRoadObjectRemoved(roadObjectId: String)
}

Register the EHorizonObserver object with MapboxNavigation object.

override fun onStart() {
    super.onStart()
    mapView.onStart()
    mapboxNavigation.registerEHorizonObserver(eHorizonObserver)
}
Note

Registering an EHorizonObserver activates the electronic horizon module.

Don't forget to unregister the EHorizonObserver interface.

override fun onStop() {
    super.onStop()
    mapView.onStop()
    mapboxNavigation.unregisterEHorizonObserver(eHorizonObserver)
}
Note

Unregistering all observers deactivates the module.

The electronic horizon position

EHorizonPosition represents the current electronic horizon position

Property nameDescriptionTypeOptional
eHorizonGraphPositionCurrent graph position.EHorizonGraphPositionNo
eHorizonTree of edges.EHorizonNo
eHorizonResultTypeResult type (INITIAL for the first EHorizon and after an EHorizon reset, UPDATE for continuation of the EHorizon)StringNo

The electronic horizon graph position

EHorizonGraphPosition represents the position on the current EHorizon.

Property nameDescriptionTypeOptional
edgeIdCurrent edge id.LongNo
percentAlongThe progress along the current edge [0,1)DoubleNo

The electronic horizon

EHorizon uses map data along the probable path (or paths) of a vehicle within the road graph to surface metadata about the underlying edges of the graph for a certain distance in front of the vehicle. The electronic horizon has a tree structure that can be navigated by traversing the edges and their outgoing connections.

Property nameDescriptionTypeOptional
startThe first edge of the electronic horizon tree.EHorizonEdgeNo

The electronic horizon edge

Property nameDescriptionTypeOptional
idA unique identifier of the directed edge. This identifier may be different for the same actual edge in different dataset versions.LongNo
levelThe nesting level relative to MPP inside eHorizon (0 being the MPP, 1 branches of the MPP, 2 branches of level 1 branches).ByteNo
probabilityThe probability (as a percentage) for this edge to be taken by the driver. The probabilities of all outgoing edges on a single intersection sum up to 1.DoubleNo
outA list of outgoing edges.List<Edge>No

The electronic horizon edge metadata

Property nameDescriptionTypeOptional
headingThe heading (sometimes referred to as bearing) when starting to move along the edge in degrees (0-360).DoubleNo
lengthThe edge's length in meters.DoubleNo
functionRoadClassFunctional road class (as defined by OpenStreetMap). One of the following: MOTORWAY, TRUNK, PRIMARY, SECONDARY, TERTIARY, UNCLASSIFIED, RESIDENTIAL, SERVICE_OTHER.StringNo
speedLimitThe max speed of the edge (speed limit) in meters per second.DoubleYes
speedAverage speed along the edge in meters per second.DoubleNo
rampIf the edge is a ramp.BooleanNo
motorwayIf the edge is a motorway.BooleanNo
bridgeIf the edge is a bridge.BooleanNo
tunnelIf the edge is a tunnel.BooleanNo
tollIf there is a toll on the edge.BooleanNo
namesA list of road names.List<NameInfo>No
laneCountThe number of lanes on the edge (does not change mid-edge).ByteYes
meanElevationThe mean elevation along the edge in meters.DoubleYes
curvatureBinned number denoting the curvature degree of the edge (0-15).ByteNo
countryCodeThe ISO 3166-1 alpha-3 country code.StringYes
stateCodeA state inside a country (ISO 3166-2).StringYes
isRightHandTrafficTrue if in the current place/state a right-hand traffic is used, false if left-hand.BooleanNo

The electronic horizon object enter/exit info

Property nameDescriptionTypeOptional
roadObjectIdRoad object id.StringNo
enterFromStartOrExitFromEndIf the object was entered via its start for EHorizonObserver#onRoadObjectEnter or if the object was exited via its end for EHorizonObserver#onRoadObjectExit.BooleanNo
typeType of road object.StringNo

Direct calls to the electronic horizon

MapboxNavigation object provides two objects:

  • roadObjectsStore: Provides methods to get road objects metadata, and add or remove custom road objects.
  • graphAccessor: Provides methods to get the shape and metadata for an edge (EHorizonEdge).
class RoadObjectsStore {

    fun getRoadObjectsOnTheEdge(edgeId: Long): Map<String, EHorizonObjectEdgeLocation>

    fun getRoadObjectMetadata(roadObjectId: String): EHorizonObjectMetadata? 

    fun getRoadObjectLocation(roadObjectId: String): EHorizonObjectLocation?

    fun getRoadObjectIdsByEdgeIds(edgeIds: List<Long>): List<String> 

    fun addCustomRoadObject(roadObjectId: String, openLRLocation: String, openLRStandard: String) 

    fun removeCustomRoadObject(roadObjectId: String)
}

class GraphAccessor {

    fun getEdgeShape(edgeId: Long): List<Point>?

    fun getEdgeMetadata(edgeId: Long): EHorizonEdgeMetadata?

    fun getPathShape(graphPath: EHorizonGraphPath): List<Point>?

    fun getGraphPositionCoordinate(graphPosition: EHorizonGraphPosition): Point?
}

You can get the shape and metadata of each edge from the MPP using the following code:

override fun onPositionUpdated(
        position: EHorizonPosition,
        distances: Map<String, EHorizonObjectDistanceInfo>
) {
    val mpp = position.eHorizon.mpp()
    mpp.forEach { edge ->
        val edgeShape = mapboxNavigation.graphAccessor.getEdgeShape(edge.id)
        val edgeMetadata = mapboxNavigation.graphAccessor.getEdgeMetadata(edgeId)
    }
}

You can add a custom road object using the following code:

val objectId = "objectId"
val openLRLocation = "CwMisiQpOhZUF/lR/eUTZGMH"
val openLRStandard = OpenLRStandard.TOM_TOM

mapboxNavigation.roadObjectsStore.addCustomRoadObject(objectId, openLRLocation, openLRStandard)

Road object location

EHorizonObjectLocation represents the location of the road object on the road graph.

Property nameDescriptionTypeOptional
pathRepresents the location of the line-like object, will be null for point-like objects.EHorizonGraphPathYes
positionRepresents the location of the point-like object, will be null for line-like objects.EHorizonGraphPositionYes

You can get the position of the object using the following code:

override fun onPositionUpdated(
        position: EHorizonPosition,
        distances: Map<String, EHorizonObjectDistanceInfo>
) {
    distances.forEach { objectId, distanceInfo ->
        mapboxNavigation.roadObjectsStore.getRoadObjectLocation(objectId)?.let { objectLocation ->
            // for line-like objects
            objectLocation.path?.let {
                val path: List<Point>? = mapboxNavigation.graphAccessor.getPathShape(it)
            }
            // for point-like objects
            objectLocation.position?.let {
                val position: Point? = mapboxNavigation.graphAccessor.getGraphPositionCoordinate(it)
            }
        }
    }
}

Graph path

EHorizonGraphPath represents a path on a map graph.

Property nameDescriptionTypeOptional
edgesIds of edges on the road graph.List<Long>No
percentAlongBeginOffset from the start of the edge (0 - 1) pointing to the start of the road object on the very first edge.DoubleNo
percentAlongEndOffset from the start of the edge (0 - 1) pointing to the end of the road object on the very last edge.DoubleNo
lengthLength of the path.DoubleNo

Road object edge location

EHorizonObjectEdgeLocation represents location of the road object on the edge.

Property nameDescriptionTypeOptional
percentAlongBeginOffset from the start of edge (0 - 1) pointing to the beginning of road object on this edge. Will be 0 for all edges in the line-like road object except the very first one in the case of point-like object percentAlongBegin == percentAlongEnd.DoubleNo
percentAlongEndOffset from the start of edge (0 - 1) pointing to the end of road object on this edge. Will be 1 for all edges in the line-like road object except the very first one in the case of point-like object percentAlongBegin == percentAlongEnd.DoubleNo

Road object metadata

EHorizonObjectMetadata represents road object metadata.

Property nameDescriptionTypeOptional
typeType of the road object (INCIDENT, TOLL_COLLECTION_POINT, BORDER_CROSSING, TUNNEL_ENTRANCE, TUNNEL_EXIT, RESTRICTED_AREA_ENTRANCE, RESTRICTED_AREA_EXIT, SERVICE_AREA, BRIDGE_ENTRANCE, BRIDGE_EXIT, CUSTOM).StringNo
objectProviderProvider of the road object (MAPBOX, CUSTOM).StringNo
incidentInfoWill be filled only if type is INCIDENT and objectProvider is MAPBOX.IncidentInfoYes
tunnelInfoWill be filled only if type is TUNNEL_ENTRANCE and objectProvider is MAPBOX.TunnelInfoYes
borderCrossingInfoWill be filled only if type is BORDER_CROSSING and objectProvider is MAPBOX.CountryBorderCrossingInfoYes
tollCollectionTypeWill be filled only if type is TOLL_COLLECTION_POINT and objectProvider is MAPBOX.IntYes
restStopTypeWill be filled only if type is SERVICE_AREA and objectProvider is MAPBOX.IntYes

Use the electronic horizon output

The EHorizon is a tree structure that can be navigated by traversing the edges and their outgoing connections. This can be accomplished by looping over the edges. For common cases, some utilities have been added which are described below.

Get the current Edge

To get the current edge from the EHorizon, an EHorizon#current utility function is provided.

Get the MPP

To collect the entire MPP from the EHorizon, an EHorizon#mpp() utility function is provided that returns an ordered list of edges.

To collect only the edges starting at the current edge (which is important when the trailing length is greater than 0), pass in the current EHorizonPosition EHorizon#mpp(position).