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: List<RoadObjectDistanceInfo>)

    fun onRoadObjectEnter(objectEnterExitInfo: EHorizonObjectEnterExitInfo)

    fun onRoadObjectExit(objectEnterExitInfo: EHorizonObjectEnterExitInfo)
  
    fun onRoadObjectPassed(objectPassInfo: RoadObjectPassInfo)

    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
isOneWayTrue if current edge is one-way.BooleanNo

Direct calls to the electronic horizon

MapboxNavigation object provides three objects:

  • roadObjectsStore: Provides methods to get the current road object, get upcoming road objects, and add or remove custom road objects.
  • graphAccessor: Provides methods to get the shape and metadata for an edge (EHorizonEdge).
  • roadObjectMatcher: Provides methods to match custom objects to the road graph and get a RoadObject. RoadObjectMatcherObserver should be set to get matching results.
class RoadObjectsStore {

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

    fun getRoadObject(roadObjectId: String): RoadObject? 

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

    fun addCustomRoadObject(roadObject: RoadObject) 

    fun removeCustomRoadObject(roadObjectId: String)

    fun removeAllCustomRoadObjects()
    
    fun getUpcomingRoadObjects(distances: List<RoadObjectDistanceInfo>): List<UpcomingRoadObject>
}

class GraphAccessor {

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

    fun getEdgeMetadata(edgeId: Long): EHorizonEdgeMetadata?

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

    fun getGraphPositionCoordinate(graphPosition: EHorizonGraphPosition): Point?
}

class RoadObjectMatcher {
    
    fun registerRoadObjectMatcherObserver(roadObjectMatcherObserver: RoadObjectMatcherObserver)
    
    fun matchOpenLRObject(roadObjectId: String, openLRLocation: String, openLRStandard: String) 
    
    fun matchPolylineObject(roadObjectId: String, polyline: List<Point>)
    
    fun matchPolygonObject(roadObjectId: String, polygon: List<Point>) 
    
    fun matchGantryObject(roadObjectId: String, gantry: List<Point>) 
    
    fun matchPointObject(roadObjectId: String, point: Point)
    
    fun cancel(roadObjectId: String) 
}

interface RoadObjectMatcherObserver {
    
    fun onRoadObjectMatched(result: Expected<RoadObject, RoadObjectMatcherError>)
}

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

override fun onPositionUpdated(
        position: EHorizonPosition,
        distances: List<RoadObjectDistanceInfo>
) {
    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.roadObjectMatcher.registerRoadObjectMatcherObserver(object : RoadObjectMatcherObserver {
    override fun onRoadObjectMatched(result: Expected<RoadObject, RoadObjectMatcherError>) {
        if (result.isValue) {
            // matching finished, add object to the store
            mapboxNavigation.roadObjectsStore.addCustomRoadObject(result.value!!)
        } else {
            // handle RoadObjectMatcherError
        }
    }
})

mapboxNavigation.roadObjectMatcher.matchOpenLRObject(objectId, openLRLocation, openLRStandard)

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

RoadObjectEdgeLocation 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

RoadObject is an abstract class that serves as a base for all road objects. There are two sources of road objects:

  • active route
  • the electronic horizon

Objects coming from different sources might be duplicated. Duplicates will not have the same IDs.

Property nameDescriptionTypeOptional
idId of the road object. If you receive duplicate objects (for example, 'RoadObjectType.TUNNEL') from the electronic horizon and the active route, the two objects will not have the same IDs.StringNo
objectTypeConstant describing the object type. Available road object types are: TUNNEL, COUNTRY_BORDER_CROSSING, TOLL_COLLECTION, REST_STOP, RESTRICTED_AREA, BRIDGE, INCIDENT, CUSTOM.IntNo
lengthLength of the object, null if the object is point-like.DoubleYes
locationLocation of the road object. Road objects coming from the electronic horizon might have the next RoadObjectLocationType: GANTRY, OPEN_LR_LINE, OPEN_LR_POINT, POINT, POLYGON, POLYLINE. Road objects coming from the active route will have RoadObjectLocationType.ROUTE_ALERT location type only.RoadObjectLocationNo
providerProvider of the road object. Might be MAPBOX or CUSTOM.StringNo

Inheritors of the RoadObject are: CountryBorderCrossing, Bridge, Custom, Incident, RestrictedArea, RestStop, TollCollection, Tunnel.

Road object location information

RoadObjectLocation contains information about the location of the road object of a specific type (for example gantry, polygon, line, or point) on the road graph.

Property nameDescriptionTypeOptional
locationTypeType of the road object location.IntNo
shapeGeometry of the road object.GeometryNo

Inheritors of the RoadObjectLocation are: GantryLocation, OpenLRLineLocation, OpenLRPointLocation, PointLocation, PolygonLocation, PolylineLocation, RouteAlertLocation.

Road object distance information

RoadObjectDistanceInfo contains information about the distance to the road object of a specific type (for example gantry, polygon, line, or point).

Property nameDescriptionTypeOptional
roadObjectIdId of the road object.StringNo
roadObjectTypeType of the road object.IntNo
distanceInfoTypeType of the distance info object.IntNo

Inheritors of the RoadObjectDistanceInfo are: GantryDistanceInfo, LineDistanceInfo, PointDistanceInfo, PolygonDistanceInfo, SubGraphDistanceInfo.

On entering or exiting an object

RoadObjectEnterExitInfo contains information about the object that has been entered or exited.

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

On passing an object

RoadObjectPassInfo contains a unique ID and the type of road object the driver has passed.

Property nameDescriptionTypeOptional
roadObjectIdRoad object id.StringNo
typeType of road object.StringNo

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).