# Traffic

You can visualize traffic incidents on the map by enabling the map layer state trafficIncidents with one line of code. The HERE SDK supports also a separate layer to see the current traffic situation by adding a trafficFlow layer.

In addition, you can also indicate the traffic along a Route instance as shown in the Directions section.

## Show Real-Time Traffic Flow and Incidents on the Map

You can easily visualize traffic incidents on the map by enabling the map layer state trafficIncidents. The HERE SDK also supports a separate layer to see the current traffic situation. See the example below for how to show or hide a layer on the map.

After a layer is set, the visible area of the map is automatically updated. So you can freely pan the map in all directions to see the latest traffic incidents.

In many situations, drivers are interested in finding the fastest route based on the current traffic jams in a city - or outside a city. The HERE SDK allows you to show a layer holding all the current traffic jams, visualized by lines in different colors to indicate the severity of the jam - always updated in real-time. This feature requires an online connection and consumes slightly more data. However, the traffic lines are shown as part of the map tiles and are therefore highly performant.

Together - or independently - you can visualize such traffic information on the map with just a few lines of code:

do {
try mapView.mapScene.setLayerState(layer: MapLayerLite.trafficFlow, newState: LayerStateLite.enabled)
try mapView.mapScene.setLayerState(layer: MapLayerLite.trafficIncidents, newState: LayerStateLite.enabled)
} catch let mapSceneError {
print("Failed to enable traffic visualization. Cause: \(mapSceneError)")
}


Setting a new layer state is performed synchronously, but it requires a valid map scene that must have been loaded before. Also, setting a new layer state while a new map scene is being loaded, may result in an error. For hiding a layer, you can call the above with LayerStateLite.disabled instead of LayerStateLite.enabled.

The traffic flow lines are color coded as follows:

• Green: Normal traffic
• Amber/Yellow: High traffic
• Red: Very high traffic
• Black: Blocking traffic

A usage example is available on GitHub as part of the Traffic example app.

## Use MapSceneConfig to Enable More than One Layer Together with a New Map Scene

Sometimes it is more convenient to load the map scene using a MapSceneConfigLite. For example, if you want to enable visualization for traffic incidents, traffic flows and a new map scene at the same time, call this:

var mapSceneConfig = MapSceneConfigLite()
mapSceneConfig.mapLayers[MapLayerLite.trafficFlow] = LayerStateLite.enabled
mapSceneConfig.mapLayers[MapLayerLite.trafficIncidents] = LayerStateLite.enabled


Then implement the optional callback to know if loading the scene has succeeded:

func onLoadScene(errorCode: MapSceneLite.ErrorCode?) {
if let error = errorCode {
print("Error: New map scene not loaded: \(error)")
}
}


Here, the mapSceneConfig holds the desired layers, trafficFlow and trafficIncidents, together with their new state. By default, the initial state for both layers is disabled. When loading a new map scene, mapSceneConfig can be passed together with the desired map style as parameters.

For hiding both layers at the same time while setting a new map scene, you can call the above with .disabled instead of .enabled. Alternatively, you can independently control the state of a map layer using a synchronous call to setLayerState(layer:newState:) as shown above.

## Query Incidents with the TrafficEngine

With the TrafficEngine, you can retrieve detailed information about ongoing traffic incidents. You can search for incidents along a route via a GeoCorridor, in a GeoBox or in a GeoCircle.

You can also set multiple options, for example, to search only for specific types of incidents. As a result you get results on the affected vehicle types, date information, location information, localizable descriptions, summaries and much more.

Start by creating a new instance of the TrafficEngine:

do {
try trafficEngine = TrafficEngine()
} catch let engineInstantiationError {
fatalError("Failed to initialize TrafficEngine. Cause: \(engineInstantiationError)")
}


Below we search inside a GeoCircle for possible TrafficIncidents:

private func queryForIncidents(centerCoords: GeoCoordinates) {
let geoCircle = GeoCircle(center: centerCoords, radiusInMeters: 1000)
let trafficIncidentsQueryOptions = TrafficIncidentsQueryOptions()
// Optionally, specify a language:
// If the language is not supported, then the default behavior is applied and
// the language of the country where the incident occurs is used.
// trafficIncidentsQueryOptions.languageCode = LanguageCode.enUs
trafficEngine.queryForIncidents(inside: geoCircle,
queryOptions: trafficIncidentsQueryOptions,
completion: onTrafficIncidentsFound);
}

// TrafficIncidentQueryCompletionHandler to receive traffic items.
func onTrafficIncidentsFound(error: TrafficQueryError?,
trafficIncidentsList: [TrafficIncident]?) {
if let trafficQueryError = error {
print("TrafficQueryError: \(trafficQueryError)")
return
}

// If error is nil, it is guaranteed that the list will not be nil.
var trafficMessage = "Found \(trafficIncidentsList!.count) result(s). See log for details."
let nearestIncident = getNearestTrafficIncident(currentGeoCoords: tappedGeoCoordinates,
trafficIncidentsList: trafficIncidentsList!)
trafficMessage.append(contentsOf: " Nearest incident: \(nearestIncident?.description.text ?? "nil")")
showDialog(title: "Nearby traffic incidents",
message: trafficMessage)

for trafficIncident in trafficIncidentsList! {
print(trafficIncident.description.text)
}
}


For each found TrafficIncident, we log its description. If we search in Germany, then by default the results will be in German. This may sound like this:

Berlin, Sachsendamm zwischen Gotenstraße und Priesterweg Fahrbahn auf einen Fahrstreifen verengt, Staugefahr, Bauarbeiten, bis voraussichtlich 20.02.2028

You can also specify another language, for example, by setting this:

trafficIncidentsQueryOptions.languageCode = LanguageCode.enUs


Note that trafficIncidents is a layer that renders traffic icons and lines to indicate the location of incidents.

Each TrafficIncident contains a GeoPolyline that indicates its location. By comparing a tapped location on the map with the geographic coordinates contained in the polyline, you can find the closest incident to a tapped location on the map:

private func getNearestTrafficIncident(currentGeoCoords: GeoCoordinates,
trafficIncidentsList: [TrafficIncident]) -> TrafficIncident? {
if trafficIncidentsList.count == 0 {
return nil
}

// By default, traffic incidents results are not sorted by distance.
var nearestDistance: Double = Double.infinity
var nearestTrafficIncident: TrafficIncident!
for trafficIncident in trafficIncidentsList {
// In case lengthInMeters == 0 then the polyline consistes of two equal coordinates.
// It is guaranteed that each incident has a valid polyline.
for geoCoords in trafficIncident.location.polyline.vertices {
let currentDistance = currentGeoCoords.distance(to: geoCoords)
if currentDistance < nearestDistance {
nearestDistance = currentDistance
nearestTrafficIncident = trafficIncident
}
}
}

return nearestTrafficIncident
}


Of course, it is also possible to render the polyline of an incident by yourself on the map, by adding a MapPolyline. You can also add your own icons as MapMarker - depending on the type of the incident you may decide to choose a different image.