Routing¶
This section explains the use of route computing functionality including multiple waypoints and alternate routes within an Android app.
Car, Truck and Pedestrian Routing¶
The Sygic Maps SDK for Android 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. Most of the managers need to be called asynchronously.
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
RouteRequest
is a class containing all info about the route we want to calculate. It contains start,
finish, via-points and another route options.
val startGeoCoordinates = GeoCoordinates(48.13308, 11.57249) // somewhere in Munich
val endGeoCoordinates = GeoCoordinates(47.54849, 9.68634) // the beautiful city of Lindau
val routeRequest = RouteRequest().apply {
setStart(startGeoCoordinates)
setDestination(endGeoCoordinates)
}
To adjust routing options, such as transport mode, dimensional restrictions, avoids and much more, create
a RoutingOptions
instance that you need to pass to the RouteRequest
afterwards:
val routingOptions = RoutingOptions().apply {
isUnpavedRoadAvoided = true
routingService = RoutingOptions.RoutingService.Online
transportMode = RoutingOptions.TransportMode.Car
tunnelRestriction = RoutingOptions.ADRTunnelType.B
addDimensionalRestriction(RoutingOptions.VehicleRestrictions.Height, 4500) // in mm, weight in kg
}
routeRequest.routingOptions = routingOptions
Computing the route is done with computeRouteWithAlternatives
method of an instance of the Router
class.
It takes PrimaryRouteRequest
, list of AlternativeRouteRequest
objects and a RouteComputeFinishedListener
which has
only one method onComputeFinished
containing all calculated routes (or null
in case of error).
To obtain more detailed data about calculated routes, each request (primary or alternative) has its own RouteComputeLister
.
Creating PrimaryRouteRequest
may look like this:
val primaryRouteComputeListener = object : RouteComputeListener {
override fun onProgress(progress: Int) {
// progress from 0 to 100
}
override fun onComputeFinished(route: Route?, status: Router.RouteComputeStatus) {
// calculated primary route or null in case of error
// status/result of route calculation - Success, UnreachableTarget, etc.
// we can add the primary route to the map using MapView
route?.let {
mapView.mapDataModel.addMapObject(
MapRoute.from(it).setType(MapRoute.RouteType.Primary).build()
)
}
}
}
// wrap listener togegher with routeRequest
val primaryRouteRequest = PrimaryRouteRequest(routeRequest, primaryRouteComputeListener)
Alternative route request is created in a similar way, but instead of routeRequest
we will specify a route alternative
type. For example, we would like to calculate two alternative routes - fastest and shortest:
val alternativeRouteComputeListener1 = object : RouteComputeListener {
override fun onProgress(progress: Int) {
// progress from 0 to 100
}
override fun onComputeFinished(route: Route?, status: Router.RouteComputeStatus) {
// calculated alternative route or null in case of error
// status/result of route calculation - Success, UnreachableTarget, etc.
// add the alternative route(s) to the map using MapView
route?.let {
mapView.mapDataModel.addMapObject(
MapRoute.from(it).setType(MapRoute.RouteType.Alternative).build()
)
}
}
}
val alternativeRouteRequest1 = AlternativeRouteRequest(
AlternativeRouteRequest.RouteAlternativeType.Fastest,
alternativeRouteComputeListener1
)
val alternativeRouteComputeListener2 = object : RouteComputeListener {
override fun onProgress(progress: Int) {
// progress from 0 to 100
}
override fun onComputeFinished(route: Route?, status: Router.RouteComputeStatus) {
// calculated alternative route or null in case of error
// status/result of route calculation - Success, UnreachableTarget, etc.
// add the alternative route(s) to the map using MapView
route?.let {
mapView.mapDataModel.addMapObject(
MapRoute.from(it).setType(MapRoute.RouteType.Alternative).build()
)
}
}
}
val alternativeRouteRequest2 = AlternativeRouteRequest(
AlternativeRouteRequest.RouteAlternativeType.Shortest,
alternativeRouteComputeListener1
)
Finally, we can start the compute process:
val routeComputeFinishedListener = object : RouteComputeFinishedListener {
override fun onComputeFinished(route: Route?, alternatives: List<AlternativeRouteResult>) {
// all route calculations are done here
}
}
router.computeRouteWithAlternatives(
primaryRouteRequest,
listOf(alternativeRouteRequest1, alternativeRouteRequest2),
routeComputeFinishedListener
)
Please note that the onProgress
callback gets continuous progress only in offline mode as the online routing progress
cannot be tracked (you only get 0 and then 100).
There are many possibilities how you can present calculated routes to the user using MapView class, for example:
// show the whole route to the user using its bounding box
mapView.cameraModel.setMapRectangle(
MapRectangle(
route.boundingBox,
0.15f,
0.15f,
0.15f,
0.15f
),
MapAnimation(
500,
MapAnimation.InterpolationCurve.AccelerateDecelerate
)
)
// add a SmartLabel showing the primary route's duration
mapView.mapDataModel.addMapObject(
MapSmartLabel
.with(route)
.setText(
(StyledText(
// formatDate() is a function that transforms an integer into a stringified format
formatDate(route.routeInfo.durationWithSpeedProfileAndTraffic)
))
)
.build()
)
// add a MapMarker at the start
mapView.mapDataModel.addMapObject(
MapMarker.at(route.start.navigablePosition).withIcon(R.drawable.sygic_sdk_map_pin).build()
)
// add a MapMarker at the end
mapView.mapDataModel.addMapObject(
MapMarker.at(route.destination.navigablePosition).withIcon(R.drawable.sygic_sdk_map_pin).build()
)
// and if you want to use one of the routes for navigation do not forget to set it into the NavigationManager
NavigationManagerProvider.getInstance().get().setRouteForNavigation(route)
Handling rerouting can be done using the NavigationManager's onRouteChanged listener. Setting
the new route for navigation is handled internally, all you need to do is check if the new route is not
null, remove the old MapRoute
from MapView
via mapDataModel
and add the new one.
Of course, if you have stored the RouteRequest
or the RouteInfo
, you need to assign the new ones
to your variables and also you can update the traffic data for route etc.
The MapRoute map object¶
The MapRoute
class is a type of MapObject
that displays a calculated route on a map. Typically,
an application creates a MapRoute
after a route calculation, passing the relevant Route
object
as a parameter to the MapRoute(Route)
constructor before adding the MapRoute
to the map by calling
MapView.mapDataModel.addMapObject(MapRoute)
.
To remove the route from the map, just call the removeMapObject()
function.
route?.let {
val alternativeRouteMapObject = MapRoute.from(it).setType(MapRoute.RouteType.Alternative).build()
mapView.mapDataModel.addMapObject(alternativeRouteMapObject)
mapView.mapDataModel.removeMapObject(alternativeRouteMapObject)
}
You can also process the Route without using it in map, e.g. to get textual instructions:
val instructionList = StringBuilder()
route.maneuvers.forEach {
when (it.type) {
RouteManeuver.Type.Left -> {
instructionList.append("Turn left onto " + it.nextRoadName + "\n")
}
RouteManeuver.Type.RoundaboutN -> {
instructionList.append("On the roundabout, continue straight using the exit #" +
it.roundaboutExit + "\n")
}
// more Route maneuver types
}
}
It is also possible to request the Route
's geometry should you need to work with it.
The method getRouteGeometry()
returns a List of GeoCoordinates
.
route.routeGeometry?.forEach {
print(it) // prints all of the GeoCoordinates of the route
}
Route Serialization¶
If you wish to save a route you have computed, you can use Route.serializeToBriefJSON()
val json = route.serializeToBriefJSON()
// use the serialized route - save it to a file, send it over network, sky is the limit...
To deserialize the JSON and get the Route
you can use Router.computeRouteFromJSONString()
.
router.computeRouteFromJSONString(json, object : RouteComputeListener {
override fun onProgress(progress: Int) {
}
override fun onComputeFinished(route: Route?, status: Router.RouteComputeStatus) {
// use the route
}
})
You can also extract the RouteRequest
first, e.g. if you want to edit it before computing:
router.createRouteRequestFromJSONString(json, object: OnRouteRequestDeserialized {
override fun onError(error: RouteRequestDeserializerError) {
// invalid json
}
override fun onSuccess(routeRequest: RouteRequest) {
// e.g. modify route request and use it for another route calculation
routeRequest.addViaPoint(GeoCoordinates(51.515436, -0.122045))
router.computeRouteWithAlternatives(...)
}
})
Routing Options¶
You can edit parameters of route before computing using RoutingOptions
.
val options = RoutingOptions().apply {
transportMode = RoutingOptions.TransportMode.Car
routingType = RoutingOptions.RoutingType.Economic
departureTime = Date(1476498000000) // 15 Oct 2016, 4:20am
}
routeRequest.routingOptions = options
By default, the route is computed at the instant.
You can also set a departure time using options.departureTime
, but only set it when you want to override
it as it computes the route without traffic and you wouldn't want that for a normal compute.
Avoids¶
To avoid certain elements on route like toll roads or unpaved roads, you can set flags on RoutingOptions
.
val routingOptions = RoutingOptions().apply { // this creates an object with default values
isTollRoadAvoided = true
isUnpavedRoadAvoided = true
}
val routeRequest = RouteRequest().apply {
routingOptions = routingOptions
}
RouterProvider.getInstance().get().computeRouteWithAlternatives(...)
After the route is computed, you can get RoutingOptions
from Route
in order to further edit the route.
You can get countries on route and set avoids individually for each or you can avoid a whole country altogether
as shown below.
val router = RouterProvider.getInstance().get()
val routingOptions = route.routingOptions
val avoidableCountries = setOf(routingOptions.avoidableCountries)
avoidableCountries.forEach {
if (it.equals("fr")) {
routingOptions.setTollRoadAvoided("fr", true)
}
if (it.equals("ch")) {
routingOptions.setCountryAvoided("ch", true)
}
}
// then assign the new routing options and compute the route again
routeRequest.routingOptions = routingOptions
router.computeRouteWithAlternatives(...)
It is possible that you would like to see what can be avoided on the route that was computed.
Imagine that the user computes a route from Bratislava, Slovakia to Saint-Malo, France. The route goes via Austria and
Germany. After the route is computed, you can get the countries that can be avoided.
In this case, Austria and Germany can be avoided.
Then, if you like, it's possible to avoid only certain types of roads in each country.
For example, the route is computed via Toll roads and Motorways in each country (except for Germany, as there are no
Toll roads). For example, the user should be able to avoid Toll roads in France, only.
Therefore, you can let the user decide for each country just like this:
val routingOptions = route.routingOptions
val transitCountries = route.transitCountries
transitCountries.forEach {
// ask for each country if the options are avoidable
if (routingOptions.isHighwayAvoidable(it)) {
// if highway is avoidable in the country, show it to the user
// and then set isHighwayAvoided to true if the user chooses to avoid it
routingOptions.isHighwayAvoided = true
}
if (routingOptions.isTollRoadAvoidable(it)) {
// same here
routingOptions.isTollRoadAvoided = true
}
// and for other avoids
}
// remember to recompute the route with the new options!
routeRequest.routingOptions = routingOptions
router.computeRouteWithAlternatives(...)
It is also possible to avoid a chosen GeoBoundingBox
. A GeoBoundingBox is a bounding box that consists of the top left
and bottom right GeoCoordinates
. Let's see an example of how to avoid two separate bounding boxes:
val geoRectangleAvoids = listOf(
GeoBoundingBox(
GeoCoordinates(48.814903, 18.599957),
GeoCoordinates(48.413607, 19.022931)
),
GeoBoundingBox(
GeoCoordinates(48.426366, 18.218182),
GeoCoordinates(48.309587, 18.696088)
)
)
val routingOptions = RoutingOptions()
for (geoRectangleAvoid in geoRectangleAvoids) {
routingOptions.addGeoRectangleAvoid(geoRectangleAvoid)
}
After setting the geographical rectangle avoids (geoRectangleAvoids
) and computing the route, the avoids will be
stored in the RoutingOptions
of the computed route so that you will be able to work with them.
Route Information¶
We will work with a route: Route
that we have computed in the previous chapters.
Some of the basic info can be received directly from the Route object:
val routingOptions = route.routingOptions
val boundingBox = route.boundingBox
val routeInfo = route.routeInfo
val routeManeuvers = route.maneuvers
The routingOptions
can be used to show the routing options that have been used to compute the route.
The boundingBox
of the route can be passed into the setMapRectangle
function to see just the whole
route on the map:
mapView.cameraModel.setMapRectangle(
MapRectangle(
route.boundingBox,
0.15f,
0.15f,
0.15f,
0.15f
), MapAnimation(500, MapAnimation.InterpolationCurve.AccelerateDecelerate)
)
routeManeuvers
can be used to show the all of the directions on the route beforehand. The routeInfo
object
holds information about the length of the route and three different durations - one includes speed profile
information and traffic delays, the other includes only speed profile information and the last one doesn't
use any of the additional information.
Route Warnings¶
If your route is starting on a toll road and you avoided toll roads, it is impossible to avoid it and this unavoidable part will be included in the route warnings. Please note that the route warnings are casted.
Or, as in this example, we check if the route warning is of type WeightRestriction and then we can work with it.
route.getRouteWarnings(object: RouteWarningsListener {
override fun onRouteWarnings(routeWarnings: List<RouteWarning>) {
routeWarnings.forEach { routeWarning ->
if (routeWarning is RouteWarning.SectionWarning.WeightRestriction){
routeWarning.limitValue // the value on the road in the map
routeWarning.realValue // the value of your vehicle (routing options)
routeWarning.section.geoCoordinates // list of geocoordinates of the violated section
}
}
}
})
Route Explorer¶
After computing a route, you can get the traffic information, places along the route and more
using the RouteExplorer
.
Again, we will work with a pre-computed route route
. Let's see how to explore the traffic on route
and its most important members:
TrafficManagerProvider.getInstance().get().enableTrafficService() // the traffic service has to be enabled!
RouteExplorer.exploreTrafficOnRoute(route, object: RouteExplorer.OnExploreTrafficOnRouteListener{
override fun onExploreTrafficLoaded(info: TrafficNotification) {
info.delayOnRoute // total delay of all traffic events
info.trafficLevel // from Low to High
info.trafficInfoList.forEach { // as there can be more traffic events
it.affectedArea // bounding box of the traffic
it.affectedLength // length of the traffic event
it.delay // delay in seconds
it.distance // distance from the last callback position
it.severity // Normal to Blocking
}
}
override fun onExploreTrafficError(error: TrafficManager.ErrorCode) {
// handle the error
}
})
Next, let's see how to explore the Places on route. Please note that this time, you also receive
progress
of the exploring and the operation is fully completed when it reaches the value 100
.
RouteExplorer.explorePlacesOnRoute(route, listOf(PlaceCategories.PetrolStation), object: RouteExplorer.OnExplorePlacesOnRouteListener{
override fun onExplorePlacesLoaded(
info: List<PlaceInfo>,
progress: Int
) {
if (progress == 100){
info.forEach {
print(it.distance) // distance to the place in meters
print(it.placeInfo.name) // name of the place
print(it.placeInfo.category) // category of the place
}
}
}
override fun onExplorePlacesError(error: PlacesManager.ErrorCode) {
// handle the error
}
})
You can also explore various types of incidents
on the route. Here we want to get only the
instances of static radars on our route, if there are any :
RouteExplorer.exploreIncidentsOnRoute(route, listOf(IncidentType.RadarStaticSpeed), object: RouteExplorer.OnExploreIncidentsOnRouteListener{
override fun onExploreIncidentsLoaded(
incidents: List<IncidentInfo>,
progress: Int
) {
if (progress == 100){
incidents.forEach{
print(it.distance) // distance to the incident in meters
print(it.recommendedSpeed) // recommended speed if there's any
it.incidentLink.location // GeoCoordinates of the incident
}
}
}
override fun onExploreIncidentsError(error: IncidentsManager.ErrorCode) {
// handle the error
}
})
Last but not least - if the maps that you use contain EV charging stations, you can explore those on your route.
This is most convenient when using the routing for electric vehicles. The function is similar to those above:
RouteExplorer.exploreChargingStationsOnRoute(route, evProfile, object: RouteExplorer.OnExploreChargingStationsOnRouteListener{
override fun onExploreChargingStationsLoaded(
info: List<ChargingStation>,
progress: Int
) {
if (progress == 100) {
info.forEach {
print(it.distance) // distance to the ChargingStation in meters
print(it.timeToFullCharge) // time in minutes needed to reach charging station and charge the battery
print(it.link.name) // name of the ChargingStation
}
}
}
override fun onExploreChargingStationsError(error: PlacesManager.ErrorCode) {
// handle the error
}
})
Next Durations¶
If you would like to show the "ideal" time to leave, you can do that using the computeNextDurations()
function.
It does not directly compute the Time to Leave, but you can achieve that on your own. Our engine can compute
the next durations of the route if a list of times is passed. For example, let's see how to compute the next
30 durations with a span of 15 minutes. As always, we will work with an already computed route, route
.
If you do not know how to compute a route, please refer to the top of this page.
val times = mutableListOf<Long>()
for (x in 0..30) {
// the time that we pass has to be in seconds, therefore we divide by 1000, and 900 stands for 15 minutes
times.add(System.currentTimeMillis() / 1000 + x * 900)
}
router.computeNextDurations(route, times, object: Router.RouteDurationListener{
override fun onRouteDurations(p0: Route?, p1: MutableList<Int>?) {
p1?.let {
for (item in p1){
// here you will get the durations as integers
}
}
}
}
Routing for electric vehicles¶
As Electromobility is one of the strongest trends in the automotive industry and with the increasing number of electric vehicles, we recognize the necessity of introducing a routing engine for such vehicles. You can find the Automatic EV routing in the newest versions of SygicMapsSDK.
Our EV routing works in the offline mode only, yet. The route is computed according to the EV Profile that
you set - if you wouldn't reach the destination with your current charge or capacity, the computing algorithm
will try to find places where you can charge your vehicle so that you reach your destination without your
vehicle running out of power. The time necessary to charge your vehicle is added to the final ETA and you
can check the delay of each ChargingWaypoint
.
You can (actually, you need to) define the Battery profile and a complete EV profile of your vehicle along with your preferences. You can choose from a wide range of connector types, according to your needs - e.g. CCS½, CHAdeMo, NEMA, Tesla etc.
Let's see what is required in order to compute an EV route. At first, we specify new EVPreferences
:
val evPreferences = EVPreferences(
chargeRangeLowVal = -1.0, // Lower margin of preferred EV station power output (-1 = unlimited)
chargeRangeUpperVal = -1.0, // Upper margin of preferred EV station power output (-1 = unlimited)
preferredProvider = listOf(
EVProvider("Provider 1"),
EVProvider("Provider 2", true)
), // List of preferred EV station providers
enforceDCChargers = false, // Use DC stations when possible
enforceNonstopChargers = false, // Use chargers without opening hours when possible
chargerPermission = EVPreferences.EVChargerAccessType.Any, // Controls accessibility of preferred chargers
payType = EVPreferences.EVPayType.Any // Indicates which payment method is preferred for EV station services
)
Then, we can configure the battery profile:
val batteryProfile = BatteryProfile(
batteryCapacity = 70f, // Battery capacity in kWh
remainingCapacity = 70f, // Remaining battery capacity in kWh
batteryChargingThreshold = .2f, // Percent of battery capacity when the next charging station should be reached
batteryFullChargeThreshold = .8f, // Percent of capacity when battery is considered fully charged
batteryMinimumReserveThreshold = .05f, // Percent of capacity as safety (will be never used)
chargingCurve = mapOf(5.0 to 10.0, 15.0 to 30.0) // Battery capacity kilowatt hours (kWh) to charging power in kilowatts (kW) curve
)
Next, we need to set up an EVProfile
in which we will use the information above and specify some new values.
val evProfile = EVProfile(
batteryProfile = batteryProfile,
chargingMaxPower = 100, // Max charging power in kW
connector = setOf(EVConnector.ConnectorType.Ccs2),
power = setOf(EVConnector.PowerType.DC),
consumptionCurve = mapOf(0.0 to 0.01, 50.0 to 0.25), // Velocity kilometers per hour (km/h) to consumption kilowatt hour per kilometer (kWh/km) curve
batteryMinimumDestinationThreshold = 0.05 // percent of capacity desired at the destination
)
Naturally, you can add more connector types into the connector
set. You can also add the EVConnector.PowerType.AC
to the power
set.
Next, we need to configure the Router
and RoutingOptions
just like we would do in a normal compute and then we
will call the computeRouteWithAlternatives()
method that is available via the Router
.
Info
The RouteComputeStatus
listener may return a status called SuccessWithWarnings
that computes the route to the destination,
but with either of two warnings: InsufficientBatteryCharge
(to reach any following station) or LowBatteryAtDestination
.
val options = RoutingOptions().apply {
routingService = RoutingOptions.RoutingService.Offline // as EV routing is available for Offline mode
transportMode = RoutingOptions.TransportMode.Car
}
val routeRequest = RouteRequest(evProfile, evPreferences).apply {
setStart(start) // GeoCoordinates
setDestination(destination) // GeoCoordinates
routingOptions = options
}
val primaryRouteRequest = PrimaryRouteRequest(
routeRequest, // route request created above
object : RouteComputeListener {
override fun onComputeFinished(route: Route?, status: Router.RouteComputeStatus) {
if (status == Router.RouteComputeStatus.SuccessWithWarnings) {
route?.getRouteWarnings(object: RouteWarningsListener {
override fun onRouteWarnings(routeWarnings: List<RouteWarning>) {
routeWarnings.forEach {
print(it.geoCoordinates) // where the warning occured
print(it.warningType) // what is the type of the warning
}
}
})
}
}
override fun onProgress(progress: Int) {
}
})
RouterProvider.getInstance().get().computeRouteWithAlternatives(
primaryRouteRequest,
listener = object : RouteComputeFinishedListener {
override fun onComputeFinished(
route: Route?,
alternatives: List<AlternativeRouteResult>
) {
// your code
}
})
Info
Please remember that the route that you obtain may contain ChargingWaypoint(s)! These are the waypoints that
are necessary to visit in order to charge the vehicle. You will also receive alternative charging stations for
each ChargingWaypoint
.
Navigate to a point in map¶
One of the main purposes of our SDK is to be able to navigate to a point that the user selects from the map. Let's see the idea on how it's done (please note that this is a really simple example, you wouldn't normally want to call the routing after tapping into the map):
// once you got the mapView from the onMapReady()
var destination : GeoCoordinates
val currentPosition = PositionManagerProvider.getInstance().get().lastKnownPosition
mapView.addMapGestureListener(object: MapGestureAdapter() {
override fun onMapClicked(
e: MotionEvent?,
isTwoFingers: Boolean
): Boolean {
if (isTwoFingers){
return false
}
e?.let { // request the objects at the point of the MotionEvent's x,y coordinates
mapView.requestObjectsAtPoint(e.x, e.y, object: RequestObjectCallback{
override fun onRequestResult(
p0: MutableList<ViewObject<ViewObjectData>>,
p1: Float,
p2: Float,
p3: Int
) {
destination = p0[0].position // here we work only with the position of the first result, but you can get more of them
routeRequest.start = currentPosition // you can get your current position via the PositionManager
routeRequest.destination = destination
router.computeRoute(routeRequest, ...) // compute the route just like in the examples above
}
})
}
return super.onMapClicked(e, isTwoFingers)
}
})
Computing a route using a polyline¶
It is possible to create a route and then use it for navigation if you know its polyline. It is necessary to
supply a GuidedRouteProfile
into the RouteRequest
as an argument and then you can compute the route just like in
the examples above. The engine will match the polyline on the map and the polyline can then be used as a navigable route.
val polyline = mutableListOf<GeoCoordinates>()
polyline.add(GeoCoordinates(41.85588,-87.64821))
polyline.add(GeoCoordinates(41.85601,-87.64822))
polyline.add(GeoCoordinates(41.85619,-87.64827))
polyline.add(GeoCoordinates(41.85658,-87.64823))
polyline.add(GeoCoordinates(41.85672,-87.64820))
polyline.add(GeoCoordinates(41.85671,-87.64749))
polyline.add(GeoCoordinates(41.85672,-87.64704))
polyline.add(GeoCoordinates(41.85670,-87.64634))
val guidedRouteProfile = GuidedRouteProfile(polyline)
val routeRequest = RouteRequest(guidedRouteProfile)
// compute the route using the Router object
Getting transit countries¶
Info
Available in SDK21.2.0
There are some cases in which you might need to retrieve the countries through which the computed route is passing. If the country has more regions, regions will be returned, too.
route?.getTransitCountriesInfo(object: TransitCountriesInfoListener {
override fun onTransitCountriesInfo(transitCountries: List<TransitCountryInfo>) {
transitCountries.forEach {
it.country // String
it.regions // List
}
}
})
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 RoutingOptions
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
.
val routingOptions = RoutingOptions()
routingOptions.turnPreference = TurnPreference.CrossoverLineTurn