Skip to main content

Get started with Navigation

|

The Maps SDK for C++ provides developers with comprehensive tools to build a robust turn-by-turn navigation system. This functionality enables applications to track the current device location relative to a predefined route and deliver real-time navigational guidance.

Navigating on route

Key Features:

  • Turn-by-Turn Directions: Provides detailed route instructions based on the device’s current location, ensuring accurate navigation.
  • Live Guidance: Navigation instructions can be delivered as text and integrated with a Text-to-Speech (TTS) system for voice-based guidance.
  • Warning Alerts: A versatile alert system that notifies users of conditions such as speed limits, traffic reports, and other important events along the route.
  • Offline Functionality: Essential navigation features remain operational offline, provided that map data has been pre-downloaded or cached.

The turn-by-turn navigation system relies on continuous acquisition of device data, including location, speed, and heading. These data points are matched against the mapped route and used to generate accurate guidance for the user. Instructions are dynamically updated as the user progresses along the route.

In the event that the user deviates from the planned route, the system will notify them of their off-track distance and provide the option for route recalculations or updates. Additionally, the system can dynamically adjust the route based on real-time traffic conditions, offering more efficient and faster alternatives to optimize navigation.

Additionally, developers can leverage a built-in location simulator to test navigation functionalities during the app development phase.

How does it work?

To enable navigation, the first step is to compute a valid, navigable route (note that non-navigable routes, such as range routes, are not supported).

The SDK offers two methods for navigating a route:

  • Navigation: This method relies on the position data provided by the PositionService to guide the user along the route.
  • Simulation: This method does not require user-provided position data. Instead, it simulates the navigation instructions that would be delivered to the user, allowing developers to test and preview the experience without needing an actual position.

If we are in navigation mode, the position is provided by PositionService.It can use:

  • Real GPS Data: When PositionService::setDataSource is called with sense::DataSourceFactory::produceLive(), the service will use real-time GPS data to provide position updates. This requires the appropriate application permissions, which differ between Android and iOS. Additionally, the application must programmatically request these permissions from the user.
  • Custom Position Data: In this mode, a custom data source can be configured to supply position updates. No permissions are required in this case, as the positions are provided through the custom source rather than the device's GPS. If you want to use a custom position take a look at Custom positioning.

Currently, only one of navigation and simulation can be active at a time, regardless of the number of maps present within the application.

Starting a navigation

Given that a route has been computed, the simplest way to navigate it is by implementing the following code:

// Implement your own version of INavigationListener in order to listen to navigation specific events.
auto navigationListenerPtr = StrongPointerFactory<YourNavigationListenerImpl>();

// Implement your own version of IProgressListener. This will be used for tracking the operation of recalculate route.
auto progressListenerPtr = StrongPointerFactory<YourProgressListenerImpl>();

// Start navigation.
int err = NavigationService().startNavigation(
route,
navigationListenerPtr, // navigation listener
progressListenerPtr // progress listener (used on recalculation)
);

// Handle start errors
if (err != KNoError)
{
GEM_INFO_LOG("Failed to start navigation: %d", err);
}

// [Optional] Set the camera to follow position.
// Usually we want this when in navigation mode
mapView->startFollowingPosition();
// At any moment, we can cancel the navigation
// NavigationService().cancelNavigation(navigationListenerPtr);

The error provided by the onNavigationError function can have the following values:

ValueSignificance
KNoErrorsuccessfully completed
error::KCancelcancelled by the user
error::KWaypointAccesscouldn't be found with the current preferences
error::KConnectionRequiredif allowOnlineCalculation = false in the routing preferences and the calculation can't be done on the client side due to missing data
error::KExpiredcalculation can't be done on client side due to missing necessary data and the client world map data version is no longer supported by the online routing service
error::KRouteTooLongrouting was executed on the online service and the operation took too much time to complete (usually more than 1 min, depending on the server overload state)
error::KInvalidatedthe offline map data changed ( offline map downloaded, erased, updated ) during the calculation
error::KNoMemoryrouting engine couldn't allocate the necessary memory for the calculation

The navigation can be stopped at any moment or it will be stopped when we reach the destination.

Navigating on route

Typically (optional), before starting navigation, we instruct the MapView to begin following the user's position.

To enhance navigation clarity, the route is displayed on a map. This also includes turn-by-turn navigation arrows that disappear once the user has passed them. More about presenting routes here.

Navigating on displayed route

Navigating on said route will change color of passed route portion with the color specified via setTraveledInnerColor method of RouteRenderSettings.

Parsed route is displayed with a gray color (default)

Starting a simulation

To start a simulation, you can use the following approach similar to starting a navigation:

// Start simulation.
int err = NavigationService().startSimulation(
route,
navigationListenerPtr,
progressListenerPtr,
2.0f // speed multiplier
);

When simulating we can specify a speedMultiplier to set the simulation speed (1.0 is default and corresponds to the maximum speed limit for each road segment). See simulationMinSpeedMultiplier and simulationMaxSpeedMultiplier getters from NavigationService for the range of allowed values.

Listen for navigation events

A wide range of navigation-related events can be monitored. Here is a list of them:

void onNavigationInstruction(const NavigationInstruction& navigationInstruction) {}

void onNavigationStarted() {}

void onWaypointReached(const Landmark& landmark) {}

void onDestinationReached(const Landmark& landmark) {}

void onRouteUpdated(const Route& route) {}

void onBetterRouteDetected(
const Route& route, int travelTime, int delay, int timeGain) {}

void onBetterRouteRejected(int error /*gem::error*/) {}

void onBetterRouteInvalidated() {}

void onSkipNextIntermediateDestinationDetected() {}

void onTurnAround() {}

These events are described in the following table:

EventExplanation
onNavigationInstruction(const NavigationInstruction& navigationInstruction)Triggered when a new navigation instruction is available, providing details about the instruction.
onNavigationStarted()Called when navigation begins, signaling the start of the route guidance.
onWaypointReached(const Landmark& landmark)Invoked when a waypoint in the route is reached, including details of the waypoint.
onDestinationReached(const Landmark& landmark)Called upon reaching the final destination, with information about the destination landmark.
onRouteUpdated(const Route& route)Fired when the current route is updated, providing the new route details.
onBetterRouteDetected(const Route& route, int travelTime, int delay, int timeGain)Triggered when a better alternative route is detected, including the new route and details such as travel time, delays caused by traffic and time gains. See the Better route detection guide for more details.
onBetterRouteRejected(int error)Called when a check for better routes fails, with details of the rejection error. Used especially for debugging.
onBetterRouteInvalidated()Indicates that a previously suggested better route is no longer valid.
onSkipNextIntermediateDestinationDetected()Indicates we are getting away from the first intermediary waypoint. If this is received, it could be a good moment to call NavigationService().skipNextIntermediateDestination().
onTurnAround()Called when user travel direction violates a link one way restriction or after a navigation route recalculation, if the new route is heading on the opposite user travel direction.
note

Most callbacks from the table provided above can be used for both simulation and navigation. The onSkipNextIntermediateDestinationDetected and onTurnAround methods do not make sense on a simulation and will not be called.

note

When getting the onSkipNextIntermediateDestinationDetected() notification it makes sense to drop the first intermediary waypoint. This can be done like this (can make sense also in other situations):

NavigationService().skipNextIntermediateDestination();

Data source based navigation

Navigation typically relies on the current GPS position. However, it is also entirely valid to perform navigation using custom-defined positions.

This this can be done by creating a custom data source, setting the position service to the given data source, starting the data source and starting navigation as you would with live data source.

See the custom positioning guide for more information on how to create a custom data source.

Stop navigation/simulation

The cancelNavigation method from the NavigationService class can be used to stop both navigations and simulations, by passing the same INavigationListener implementation used in startSimulation or startNavigation methods. At the moment it is not possible to pause the simulation.

note

After stopping the simulation the data source used in the position service is set back to the previous data source if it exists.

Export Navigation instruction

The exportAs method serializes the current navigation instruction into a DataBuffer.
For now, the only supported format is EPathFileFormat::PFF_PackedGeometry.

  DataBuffer buff = instruction.exportAs(EPathFileFormat::PFF_PackedGeometry);
warning

exportAs only works with EPathFileFormat::PFF_PackedGeometry. Passing any other value will return an empty DataBuffer.