Skip to main content

Simulate Route

Last updated: April 24, 2026 | 5 minutes read

This example demonstrates how to use GEMKit in a UIKit application to calculate a route and simulate driving it at an accelerated speed with turn-by-turn voice guidance.

Check the full implementation on GitHub.

Initial screen
Simulating Route

UI and Map Integration

The view controller embeds a MapViewController and sets up delegates for both map interaction and navigation event callbacks:

ViewController.swiftView on GitHub
class ViewController: UIViewController, MapViewControllerDelegate, NavigationContextDelegate {

var mapViewController: MapViewController?

var navigationContext: NavigationContext?
var soundContext: SoundContext?
var trafficContext: TrafficContext?
var alarmContext: AlarmContext?

var mainRoute: RouteObject?
var panelNavigationViewController: NavigationViewController?

override func viewDidLoad() {

super.viewDidLoad()

self.createMapView()
self.setMapFollowPositionPreferences()
self.mapViewController!.startRender()

self.addRouteButton()
self.addLabelText()
}

func setMapFollowPositionPreferences() {

guard let mapViewController = self.mapViewController else { return }

let followPositionPreferences = mapViewController.getPreferences().getFollowPositionPreferences()

// Allow user to change follow position angle and zoom by touch (pinch or 2x finger drag)
followPositionPreferences.setTouchHandlerModifyPersistent(true)
}

Calculating and Simulating the Route

Once waypoints are set, the route is calculated and the simulation starts, auto-following the simulated position at 2× speed:

ViewController.swiftView on GitHub
let preferences = RoutePreferencesObject.init()
preferences.setTransportMode(.car)
preferences.setRouteType(.fastest)
preferences.setAvoidMotorways(false)
preferences.setAvoidTollRoads(false)
preferences.setAvoidFerries(false)
preferences.setAvoidUnpavedRoads(true)

self.navigationContext = NavigationContext.init(preferences: preferences)
self.navigationContext?.delegate = self

self.soundContext = SoundContext.init()
self.soundContext?.setUseTtsWithCompletionHandler({ success in })

self.alarmContext = AlarmContext.init()
self.alarmContext?.setAlarmDistance(600)
self.alarmContext?.setMonitorWithoutRoute(false)
self.alarmContext?.registerSafetyCameraNotifications(completionHandler: { success in })
self.alarmContext?.registerSocialReportNotifications(completionHandler: { success in })

self.departure = LandmarkObject.landmark(
withName: "Munich 1", location: CoordinatesObject.coordinates(withLatitude: 48.15741, longitude: 11.53739))
self.destination = LandmarkObject.landmark(
withName: "Munich 2", location: CoordinatesObject.coordinates(withLatitude: 48.166730, longitude: 11.53687))

self.navigationContext?
.calculateRoute(withWaypoints: [self.departure!, self.destination!],
completionHandler: { [weak self] (results: [RouteObject]) in

guard let strongSelf = self else { return }

if !results.isEmpty {

strongSelf.mapViewController?
.presentRoutes(results, withTraffic: strongSelf.trafficContext, showSummary: true, animationDuration: 1600)
}
})

Starting Simulation

After a route is presented, tapping the play button starts the simulation at 2× real speed:

ViewController.swiftView on GitHub
@objc func startSimulation(item: UIBarButtonItem) {

self.navigationContext!
.simulate(withRoute: self.mainRoute!, speedMultiplier: 2) { [weak self] (success) in

guard let strongSelf = self else { return }

if success {

strongSelf.mapViewController!.showRoutes([strongSelf.mainRoute!], withTraffic: nil, showSummary: false)
}
}
}
info

The NavigationViewController used in this example is a full-featured turn-by-turn panel displaying turn images, distance, lane guidance, traffic events, signpost overlays, and safety alerts. Due to its size it is not reproduced here — check the full implementation on GitHub.