Retrieving horizon data
The Navigation SDK for iOS is only available upon request. Contact us to get started.
Virtual Horizon acts as a digital assistant, extending the driver’s location context beyond their immediate view. It can be used by UI components to improve the driving experience, for example, by informing the driver of what is ahead. This information includes details about upcoming traffic events, vehicle restrictions, and more.
While navigating, you can use Virtual Horizon to retrieve detailed information about the horizon ahead of the vehicle, along the possible trajectories of the vehicle across the road network. The HorizonEngine
delivers this information as a combination of a HorizonPosition
and a HorizonSnapshot
.
The SDK provides horizon data for various elements, including:
StreetElement
- Information about a street, such as name.SpeedLimitElement
- Information about speed limits.GeneralRoadPropertiesElement
- Information about the road ahead, such as number of lanes, functional road class and driving side.CountryInformationElement
- Information about the country ahead, including country code, speed limit unit and regional speed limits.VehicleRestrictionElement
- Information about vehicle-specific restrictions ahead, such as maximum height allowed and restricted vehicle types.DangerousGoodsRestrictionElement
- Information about dangerous good restrictions ahead, including ADR tunnel restrictions and hazardous load restrictions.
This guide focuses on demonstrating how to utilize the HorizonEngine
for extracting specific speed-related data, including the current speed limit, the distance to the next speed limit, and the value of the upcoming speed limit. These insights allow you to create navigation applications that not only guide users accurately but also enhance their road experience by keeping them well-informed.
For more in-depth information, refer to the HorizonEngine
API reference.
Configuring the horizon engine
Incorporating horizon data into your navigation application requires the following steps:
- Start navigation with or without a route, using the
OnlineTomTomNavigationFactory
to obtain aTomTomNavigation
object. TheHorizonEngine
is automatically created during initialization of theTomTomNavigation
object. - Define your horizon data preferences by specifying
HorizonOptions
, which the SDK uses to configure theHorizonEngine
. - Add a
NavigationHorizonObserver
to receive data based on your chosenHorizonOptions
.
Specifying horizon options
First, define the set of HorizonOptions
. To indicate that you are interested in SpeedLimitElement
horizon elements, specify HorizonElementType
in the list of element types of interest.
1let mainPathSearchOptions = try MainPathSearchOptions(2 searchTime: Measurement.tt.minutes(10),3 searchDistancePolicy: ExplicitDistancePolicy(4 searchDistance: PathSearchDistance(5 maxHorizonLength: Measurement.tt.kilometers(10)6 )7 )8)9let subPathSearchOptions = try SubPathSearchOptions(10 searchTime: Measurement.tt.minutes(5),11 searchDistance: PathSearchDistance(12 maxHorizonLength: Measurement.tt.kilometers(1)13 )14)15let elementTypes = [16 HorizonElementType.pathGeometryType,17 HorizonElementType.speedLimitsType,18 HorizonElementType.streetType,19]20return try HorizonOptions(21 id: UUID(),22 elementTypes: elementTypes,23 mainPathSearchOptions: mainPathSearchOptions,24 subPathSearchOptions: [subPathSearchOptions],25 numberOfPaths: 426)
Observing horizon updates
Declare a custom observer for horizon updates:
1class SpeedElementHorizonObserver: NavigationHorizonObserver {2 private var snapshot: HorizonSnapshot?3 private var position: HorizonPosition?45 var updateBlock: ((HorizonSnapshot, HorizonPosition) -> ())?67 func didUpdateSnapshot(options: HorizonOptions, snapshot: HorizonSnapshot) {8 self.snapshot = snapshot9 }1011 func didUpdatePosition(options: HorizonOptions, position: HorizonPosition) {12 self.position = position1314 if let snapshot {15 updateBlock?(snapshot, position)16 }17 }1819 func didResetHorizon(options: HorizonOptions) {20 // do nothing21 }22}
Starting navigation
Then, start navigation with a route as described in the Starting navigation guide.
But, instead of adding an observer for route progress updates, make sure you add a NavigationHorizonObserver
to listen to horizon updates for the horizon options you defined.
1let navigationConfiguration = OnlineTomTomNavigationFactory.Configuration(2 navigationTileStore: try NavigationTileStore(config: NavigationTileStoreConfiguration(apiKey: "YOUR_TOMTOM_API_KEY")),3 locationProvider: locationProvider,4 routePlanner: routePlanner5)67let tomTomNavigation = try OnlineTomTomNavigationFactory.create(configuration: navigationConfiguration)89let navigationHorizonObserver = SpeedElementHorizonObserver()1011try? tomTomNavigation.addHorizonObserver(navigationHorizonObserver, options: options)1213let routePlan = RoutePlan(route: route, routePlanningOptions: routePlanningOptions)14let navigationOptions = NavigationOptions(activeRoutePlan: routePlan)1516try? tomTomNavigation.start()
Retrieving horizon data
With navigation started, you can listen to horizon updates and retrieve horizon data.
1navigationHorizonObserver.updateBlock = { snapshot, position in2 self.displayCurrentSpeedLimit(snapshot: snapshot, position: position)3 self.displayNextSpeedLimit(snapshot: snapshot, position: position)4}
Once you have retrieved the data, you can use it to extract the value of the current speed limit.
1guard let elements = snapshot.mainPath()?.getElements(type: .speedLimitsType),2 let element = elements.first(where: { element in3 element.startOffset < position.offset &&4 element.endOffset >= position.offset5 }),6 let speedLimitElement = element as? SpeedLimitElement else { return }78switch speedLimitElement.speedLimit {9case let .limited(speed: speed):10 print("Speed limit value: \(speed)")11case .unlimited:12 print("Unlimited speed")13@unknown default:14 print("Unsupported speed limit type")15}
You can also extract the distance to the next speed limit and the value of the next speed limit.
1guard let elements = snapshot.mainPath()?.getElements(type: .speedLimitsType),2 let element = elements.first(where: { element in3 element.startOffset >= position.offset4 }),5 let speedLimitElement = element as? SpeedLimitElement else { return }67print("Distance to the next speed limit : \(snapshot.distance(to: element, from: position))")89switch speedLimitElement.speedLimit {10case let .limited(speed: speed):11 print("Next speed limit value: \(speed)")12case .unlimited:13 print("Next, unlimited speed")14@unknown default:15 print("Next, unsupported speed limit type")16}
Next steps
Now that you know how to retrieve horizon data, here are the recommendations on what to explore next: