Routing | Mobile SDK | 2GIS Documentation
iOS SDK

Routing

To create a route on the map, you need to create two objects: TrafficRouter to find an optimal route and a RouteMapObjectSource data source to display the route on the map.

To find a route between two points, call the findRoute() method and specify the coordinates of the start and end points as RouteSearchPoint objects. You can additionally specify route parameters (RouteSearchOptions) and a list of intermediate points (list of RouteSearchPoint objects).

let startPoint = RouteSearchPoint(coordinates: GeoPoint(latitude: 55.759909, longitude: 37.618806))
let finishPoint = RouteSearchPoint(coordinates: GeoPoint(latitude: 55.752425, longitude: 37.613983))
let routeSearchOptions = RouteSearchOptions.car(CarRouteSearchOptions())

let trafficRouter = TrafficRouter(context: sdk.context)
let routesFuture = trafficRouter.findRoute(
	startPoint: startPoint,
	finishPoint: finishPoint,
	routeSearchOptions: routeSearchOptions
)

The findRoute() call returns a deferred result with a list of TrafficRoute objects. To display the found route on the map, you need to use these objects to create RouteMapObject objects and add them to a RouteMapObjectSource data source.

// Create a data source
let routeMapObjectSource = RouteMapObjectSource(context: sdk.context, routeVisualizationType: .normal)
map.addSource(source: routeMapObjectSource)

// Find a route
self.routeSearchCancellable = routesFuture.sink { routes in
	// After receiving the route, add it to the map
	for (index, route) in routes.enumerated() {
		let routeMapObject = RouteMapObject(
			route: route,
			isActive: index == 0,
			index: RouteIndex(value: UInt64(index)),
			displayFlags: nil
		)
		routeMapObjectSource.addObject(item: routeMapObject)
	}
} failure: { error in
	print("Can't find route: \(error)")
}

To build a route, you need to get points of the GeoPoint type, which are then used to create RouteSearchPoint. You can do it in multiple ways, two of them are described below.

To get geographic coordinates of the tap point, get a ScreenPoint like in the example of Getting objects using screen coordinates:

func tap(location: CGPoint) {
	let scale = UIScreen.main.nativeScale
	let point = ScreenPoint(x: Float(location.x * scale), y: Float(location.y * scale))
	...

You can transfer the ScreenPoint into geographic coordinates using the screenToMap() method:

func tap(location: CGPoint) {
	let scale = UIScreen.main.nativeScale
	let point = ScreenPoint(x: Float(location.x * scale), y: Float(location.y * scale))
	let geoPoint = map.camera.projection.screenToMap(point: point)
	...

As a result, you get coordinates of the map tap point.

You can get coordinates of an object (building, road) that is located at the tap point: use the getRenderedObjects() method. In this method, get an object of the DgisMapObject class with the id field. This ID is a stable numerical identifier of a directory object that allows you to send a search request and get information about an object, including geographic coordinates of its center.

private func tap(point: ScreenPoint, tapRadius: ScreenDistance) {
	let scale = UIScreen.main.nativeScale
	let point = ScreenPoint(x: Float(location.x * scale), y: Float(location.y * scale))
	self.getRenderedObjectsCancellable?.cancel()
	let cancel = self.map.getRenderedObjects(centerPoint: point).sink(
		receiveValue: {
			infos in
			// Getting a DgisMapObject class object that is the closest to the tap
				guard let info = infos.first(
					where: {
						$0.item.item is DgisMapObject
					}
				) else { return }
				let mapObject = info.item.item as! DgisMapObject

				// Creating a search request using the ID of this object
				self.searchCancellable?.cancel()
				self.searchCancellable = self.searchManager.searchByDirectoryObjectId(
					objectId: mapObject.id
				)
				// Getting an object from the search request
				.sinkOnMainThread(receiveValue: { [weak self] object in
					self?.directoryObject = object
					// Getting object coordinates as GeoPoint
					let geoPoint = self?.directoryObject?.markerPosition?.point
				},
					failure: { .. }
				)

		},
		failure: { ... }
	)
	...
}

Important

Coordinates of a center of a large object (for example, long and complicated ring roads) can be located far away from the camera viewport as the received object does not contain information on the camera location or the map tap spot. In such cases, use other methods to get coordinates.

For a route with intermediate points, a user is expected to visit each point in the defined order. If an intermediate point is missed, a route may be rebuilt:

  • If the GPS data shows that the user is moving not in the direction of the expected intermediate point, the route is rebuilt relatively to the current user location so that they visit the missed point. When the visit of the intermediate point is detected, the route continues.
  • If the moment of visiting the intermediate point is not detected due to a weak GPS signal but later the user location is detected on the route or next to it towards the next point, the previous intermediate point is considered visited and the route continues.