Routing¶
This section explains the use of route computing functionality including multiple waypoints and alternate routes within an iOS app.
Car and Pedestrian Routing¶
Sygic Maps SDK for iOS supports route calculation with multiple waypoints, optimized for walking or driving. A route describes a path between at least two waypoints, the starting point and the destination, with optional intermediate waypoints in between.
Applications can provide route information to users in two ways:
- A line rendered on a map that displays a connecting path between all waypoints
- Turn-by-turn directions in text format
Example¶
This guide explains how to compute a route for a car with one additional waypoint.
Expected to continue in ViewController.swift from Getting Started. The final project is available in Sygic SDK Examples: BasicRouting.
Create waypoints¶
SYWaypoint
represents a waypoint, it's used to specify start, destination, and optional waypoints between them.
func createRoute() {
let start = SYWaypoint(
position: SYGeoCoordinate(latitude: 51.500432, longitude: -0.126051),
type: .start,
name: nil
)
let end = SYWaypoint(
position: SYGeoCoordinate(latitude: 51.505431, longitude: -0.103124),
type: .end,
name: nil
)
let via = SYWaypoint(
position: SYGeoCoordinate(latitude: 51.504387, longitude: -0.115477),
type: .via,
name: nil
)
// ...
}
Create routing options¶
SYRoutingOptions
class represents routing options applicable for the selected route,
transportMode
property provides the following modes of routing:
- Car (default)
- Pedestrian
- Other (see
SYTransportMode
enum)
let routingOptions = SYRoutingOptions()
routingOptions.transportMode = .car
routingOptions.routingType = .fastest
A lot of other settings can be set in the routing options, such as settings that trucks would use:
let routingOptions = SYRoutingOptions()
routingOptions.transportMode = .transportTruck
routingOptions.dimensionalOptions?.totalWeight = 44000 // in kg
routingOptions.dimensionalOptions?.height = 4000 // in mm
routingOptions.emission = .euro6
routingOptions.vehicleYear = 2023
routingOptions.hazmatSettings = SYHazmatSettings.init(isGeneralHazardousMaterial: true, isExplosiveMaterial: false, isGoodsHarmfulToWater: false)
routingOptions.fuel = .diesel
routingOptions.maxSpeed = 90 // in kmh
routingOptions.useEndpointProtection = true
Please note that this will only affect the calculated route. If you would like to see the restrictions on map,
you can use the SYMapView
's method setLogisticInfoSettings
:
let logisticInfoSettings = SYMapLogisticInfoSettings()
logisticInfoSettings.vehicleType = .truck
logisticInfoSettings.hazmatSettings = SYHazmatSettings(isGeneralHazardousMaterial: true, isExplosiveMaterial: false, isGoodsHarmfulToWater: false)
logisticInfoSettings.totalVehicleLength = 16500 // in mm
mapView.setLogisticInfoSettings(logisticInfoSettings)
Define a route¶
The route is defined by specifying start, destination, waypoints and options (waypoints can be nil
).
let request = SYRouteRequest(start: start, destination: end, options: routingOptions, viaPoints: [via])
Prepare a request for primary route¶
SYPrimaryRequest
represents a request for computing the primary route. It also delivers details of the computing
process specifically for this route (progress and completion events can be ignored by setting to nil
).
let primary = SYPrimaryRequest(request) { (progress) in
print("Primary progress: \(Int(progress * 100))%")
} completion: { [weak self] (route, computeResult) in
print("Primary compute done: \(route?.info.length ?? 0) meters")
// TODO: check computeResult
// TODO: show route on map
}
Compute the route¶
Call SYRouting.computeRoute(_:alternatives:completion:)
to perform the compute. In our case we request
only the primary route. Optionally, you can request alternative routes by providing an array of SYAlternativeRequest
.
When computing of all requested routes is finished (each can succeed or fail), the completion is called.
Completion of this method provides only the general info of the results. Closer information is available
in corresponding events of SYPrimaryRequest
and SYAlternativeRequest
.
SYRouting.computeRoute(primary, alternatives: nil) { [weak self] (primaryRoute, alternatives) in
print("Compute fully finished")
// TODO: check results, show overview of all routes
}
Show the route on map¶
Typically the route is represented on map by SYMapRoute
and SYMapRouteLabel
, they are subclasses of SYMapObject
.
First, prepare to keep track of the routes already added to the map, in order to remove them later.
class ViewController: UIViewController {
var routeMapObjects = [SYMapObject]()
// ...
func removeAllRoutesFromMap() {
mapView.remove(routeMapObjects)
routeMapObjects.removeAll()
}
Add newly computed routes to the map.
func addRouteToMap(_ route: SYRoute, type: SYMapRouteType) {
let text = "My route\n\(route.info.length) meters"
let newMapObjects = [
SYMapRoute(route: route, type: type),
SYMapRouteLabel(text: text, textStyle: nil, placeOn: route)
]
routeMapObjects.append(contentsOf: newMapObjects)
mapView.add(newMapObjects)
}
Show the overview of a few routes by animating SYMapView
to their bounding box:
func showBoundingBox(routes: [SYRoute]) {
guard let firstRoute = routes.first else { return }
let unionBox = routes.reduce(firstRoute.box) { partialResult, route in
partialResult.union(with: route.box) ?? partialResult
}
// Zoom out with animation to display full route.
mapView.camera.setViewBoundingBox(
unionBox,
with: UIEdgeInsets.init(top: 0.15, left: 0.15, bottom: 0.15, right: 0.15),
duration: 1.0,
curve: .accelerateDecelerate,
completion: nil
)
}
Download this project¶
The final project by this guide is a part of Sygic SDK Examples, find it in BasicRouting directory.
Route Serialization¶
Route serialization feature allows to convert an already computed route into JSON representation, to restore it later or transfer to another device.
Example:
func saveRoute(_ route: SYRoute) {
let serializer = SYRouteSerializerBrief()
guard let json = serializer.serializeRoute(route) else {
print("Failed to serialize the route")
return
}
UserDefaults.standard.set(json, forKey: "serializedRoute")
}
func restoreRoute() {
guard let json = UserDefaults.standard.string(forKey: "serializedRoute") else {
return
}
SYRouting.computeRoute(fromJson: json) { (progress) in
print("Compute from JSON progress: \(Int(progress * 100))%")
} completion: { [weak self] (route, result) in
guard let self = self else { return }
guard let route = route else {
print("Failed to compute from JSON: \(result.rawValue)")
return
}
self.addRouteToMap(route, type: .primary)
self.showBoundingBox(routes: [route])
}
}
Turn preference setting¶
It is now possible to choose/let the user choose whether it is preferred to use right turns (left turns in the UK, Australia)
or turns that cross the line of opposite direction. This can be easily set in the SYRoutingOptions
object.
There are two possibilities:
Adjacent road turn: Prefer turns to adjacent roads without crossing the line of opposite driving direction. For example, in countries with driving on the right side of the road this means to prefer right turns.
Crossover line turn: Prefer turns with crossing the line of opposite driving direction. For example, in countries with driving on the right side of the road this means to prefer left turns.
Default is adjacentRoadTurn
.
let options = SYRoutingOptions()
options.turnPreference = .crossoverLineTurn