Skip to content

Commit

Permalink
readme, metadata, and offline provision info
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham7109 committed Feb 4, 2025
1 parent 598cd9e commit 7ee8c68
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 22 deletions.
67 changes: 67 additions & 0 deletions samples/navigate-route-with-rerouting/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,68 @@
# Navigate route with rerouting

Navigate between two points and dynamically recalculate an alternate route when the original route is unavailable.

![Image of navigate route with rerouting](navigate-route-with-rerouting.png)

## Use case

While traveling between destinations, field workers use navigation to get live directions based on their locations. In cases where a field worker makes a wrong turn, or if the route suggested is blocked due to a road closure, it is necessary to calculate an alternate route to the original destination.

## How to use the sample

Tap "Navigate" to simulate traveling and to receive directions from a preset starting point to a preset destination. Observe how the route is recalculated when the simulation does not follow the suggested route. Tap "Recenter" to reposition the viewpoint. Tap "Reset" to start the simulation from the beginning.

## How it works

1. Create a `RouteTask` using local network data.
2. Generate default `RouteParameters` using `RouteTask.createDefaultParameters()`.
3. Set `returnRoutes`, `returnStops`, and `returnDirections` on the `RouteParameters` to `true`.
4. Add `Stop`s to the parameters' list of `stops` using `RouteParameters.setStops()`.
5. Solve the route using `routeTask.solveRoute(routeParameters)` to get an `RouteResult`.
6. Create an `RouteTracker` using the route result, and the index of the desired route to take.
7. Enable rerouting in the route tracker using `routeTracker.enableRerouting(reroutingParameters)`. Pass `ReroutingStrategy.ToNextWaypoint` as the value of `strategy` to specify that in the case of a reroute, the new route goes from present location to next waypoint or stop.
8. Implement `RouteTracker.trackLocation()` to track the location of the device and update the route tracking status.
9. Implement `RouteTracker.TrackingStatusChangedListener()` to be notified of `TrackingStatus` changes, and use them to display updated route information. `TrackingStatus` includes a variety of information on the route progress, such as the remaining distance, remaining geometry or traversed geometry (represented by an `Polyline`), or the remaining time (`Double`), amongst others.
10. You can also query the tracking status for the current `DirectionManeuver` index by retrieving that maneuver from the `Route` and getting its direction text to display in the GUI.
11. To establish whether the destination has been reached, get the `DestinationStatus` from the tracking status. If the destination status is `DestinationStatus.Reached` and the `DirectionManeuvers.size` is 1, you have arrived at the destination and can stop routing. If there are several destinations on your route and the remaining destination count is greater than 1, switch the route tracker to the next destination.

## Relevant API

* DestinationStatus
* DirectionManeuver
* Location
* LocationDataSource
* ReroutingStrategy
* Route
* RouteParameters
* RouteTask
* RouteTracker
* RouteTrackerLocationDataSource
* SimulatedLocationDataSource
* Stop
* VoiceGuidance

## Offline data

1. Download the data from [ArcGIS Online](https://arcgisruntime.maps.arcgis.com/home/item.html?id=df193653ed39449195af0c9725701dca).
2. Extract the contents of the downloaded zip file to disk.
3. Open your command prompt and navigate to the folder where you extracted the contents of the data from step 1.
4. Execute the following commands:

`adb push sandiego.geodatabase /Android/data/com.esri.arcgisruntime.sample.offlinerouting/files/sandiego.geodatabase`

Link | Local Location
---------|-------|
|[San Diego Geodatabase](https://arcgisruntime.maps.arcgis.com/home/item.html?id=df193653ed39449195af0c9725701dca)| /Android/data/com.esri.arcgisruntime.sample.offlinerouting/files/sandiego.geodatabase |

## About the data

The route taken in this sample goes from the San Diego Convention Center, site of the annual Esri User Conference, to the Fleet Science Center, San Diego.

## Additional information

The route tracker will start a rerouting calculation automatically as necessary when the device's location indicates that it is off-route. The route tracker also validates that the device is "on" the transportation network. If it is not (e.g. in a parking lot), rerouting will not occur until the device location indicates that it is back "on" the transportation network.

## Tags

directions, maneuver, navigation, route, turn-by-turn, voice
46 changes: 40 additions & 6 deletions samples/navigate-route-with-rerouting/README.metadata.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,54 @@
{
"category": "Routing and Logistics",
"description": "TODO",
"description": "Navigate between two points and dynamically recalculate an alternate route when the original route is unavailable.",
"formal_name": "NavigateRouteWithRerouting",
"ignore": false,
"images": [
"navigate-route-with-rerouting.png"
],
"keywords": [ ],
"keywords": [
"directions",
"maneuver",
"navigation",
"route",
"turn-by-turn",
"voice",
"DestinationStatus",
"DirectionManeuver",
"Location",
"LocationDataSource",
"ReroutingStrategy",
"Route",
"RouteParameters",
"RouteTask",
"RouteTracker",
"RouteTrackerLocationDataSource",
"SimulatedLocationDataSource",
"Stop",
"VoiceGuidance"
],
"language": "kotlin",
"redirect_from": "",
"relevant_apis": [ ],
"relevant_apis": [
"DestinationStatus",
"DirectionManeuver",
"Location",
"LocationDataSource",
"ReroutingStrategy",
"Route",
"RouteParameters",
"RouteTask",
"RouteTracker",
"RouteTrackerLocationDataSource",
"SimulatedLocationDataSource",
"Stop",
"VoiceGuidance"
],
"snippets": [
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/DownloadActivity.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/NavigateRouteWithReroutingViewModel.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/NavigateRouteWithReroutingScreen.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/MainActivity.kt"
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/components/NavigateRouteWithReroutingViewModel.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/MainActivity.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/screens/NavigateRouteWithReroutingScreen.kt"
],
"title": "Navigate route with rerouting"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ package com.esri.arcgismaps.sample.navigateroutewithrerouting.components
import android.app.Application
import android.speech.tts.TextToSpeech
import android.text.format.DateUtils
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.content.ContextCompat
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.arcgismaps.Color
import com.arcgismaps.geometry.Geometry
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.Polyline
import com.arcgismaps.geometry.SpatialReference
Expand All @@ -44,8 +46,13 @@ import com.arcgismaps.mapping.view.Graphic
import com.arcgismaps.mapping.view.GraphicsOverlay
import com.arcgismaps.mapping.view.LocationDisplay
import com.arcgismaps.navigation.DestinationStatus
import com.arcgismaps.navigation.ReroutingParameters
import com.arcgismaps.navigation.ReroutingStrategy
import com.arcgismaps.navigation.RouteTracker
import com.arcgismaps.navigation.TrackingStatus
import com.arcgismaps.tasks.networkanalysis.DirectionManeuver
import com.arcgismaps.tasks.networkanalysis.Route
import com.arcgismaps.tasks.networkanalysis.RouteParameters
import com.arcgismaps.tasks.networkanalysis.RouteResult
import com.arcgismaps.tasks.networkanalysis.RouteTask
import com.arcgismaps.tasks.networkanalysis.Stop
Expand Down Expand Up @@ -75,6 +82,12 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
// the route tracker for navigation. Use delegate methods to update tracking status
private var routeTracker: RouteTracker? = null

// generate a route with directions and stops for navigation
val routeTask = RouteTask(
pathToDatabase = "$provisionPath/sandiego.geodatabase",
networkName = "Streets_ND"
)

// destination list of stops for the RouteParameters
private val routeStops = listOf(
// San Diego Convention Center
Expand All @@ -83,6 +96,15 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
Stop(Point(-117.146679, 32.730351, SpatialReference.wgs84()))
)

// a list to keep track of directions solved by the route task
private val directionManeuvers = mutableListOf<DirectionManeuver>()

// the calculated route with direction maneuvers and route geometry
private var route: Route? = null

// the route parameters needed to calculate a route from a start and stop point
private var routeParameters: RouteParameters? = null

// passed to the composable MapView to set the mapViewProxy
val mapViewProxy = MapViewProxy()

Expand All @@ -92,6 +114,7 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
// default location display object, which is updated by rememberLocationDisplay
private var locationDisplay: LocationDisplay = LocationDisplay()

// the resulted route from the route task using the route parameters
private var routeResult: RouteResult? = null

// instance of the route ahead polyline
Expand Down Expand Up @@ -124,6 +147,11 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
// instance of Android text-speech
private var textToSpeech: TextToSpeech? = null

// the JSON of polylines of the path for the simulated data source
private val polylineJSON: String by lazy {
application.getString(R.string.simulation_path_json)
}

// create a ViewModel to handle dialog interactions
val messageDialogVM: MessageDialogViewModel = MessageDialogViewModel()

Expand All @@ -137,16 +165,9 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
}
}


// generate a route with directions and stops for navigation
val routeTask = RouteTask(
pathToDatabase = "$provisionPath/sandiego.geodatabase",
networkName = "Streets_ND"
)

viewModelScope.launch {
// load and set the route parameters
val routeParameters = routeTask.createDefaultParameters().getOrElse {
routeParameters = routeTask.createDefaultParameters().getOrElse {
return@launch messageDialogVM.showMessageDialog(
title = "Error creating default parameters",
description = it.message.toString()
Expand All @@ -159,7 +180,7 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
}

// get the solved route result
routeResult = routeTask.solveRoute(routeParameters).getOrElse {
routeResult = routeTask.solveRoute(routeParameters!!).getOrElse {
return@launch messageDialogVM.showMessageDialog(
title = "Error solving route",
description = it.message.toString()
Expand Down Expand Up @@ -193,10 +214,13 @@ class NavigateRouteWithReroutingViewModel(application: Application) :

// create the simulated data source using the geometry and parameters
val simulatedLocationDataSource = SimulatedLocationDataSource(
polyline = routeGeometry,
polyline = Geometry.fromJsonOrNull(polylineJSON) as Polyline,
parameters = simulationParameters
)

// TODO
route?.directionManeuvers?.let { directionManeuvers.addAll(it) }

// set up a RouteTracker for navigation along the calculated route
routeTracker = RouteTracker(
routeResult = routeResult,
Expand All @@ -208,11 +232,7 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
}
}

// create a route tracker location data source to snap the location display to the route
val routeTrackerLocationDataSource = RouteTrackerLocationDataSource(
routeTracker = routeTracker!!,
locationDataSource = simulatedLocationDataSource
)


locationDisplayJob = with(viewModelScope) {
launch {
Expand All @@ -222,6 +242,30 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
}

launch {
// check if this route task supports rerouting
if (routeTask.getRouteTaskInfo().supportsRerouting) {
// set up the re-routing parameters
val reroutingParameters = ReroutingParameters(
routeTask = routeTask,
routeParameters = routeParameters!!
).apply {
strategy = ReroutingStrategy.ToNextWaypoint
visitFirstStopOnStart = false
}
// enable automatic re-routing
routeTracker?.enableRerouting(parameters = reroutingParameters)?.onFailure {
messageDialogVM.showMessageDialog(
title = it.message.toString(),
description = it.cause.toString()
)
}
}

// create a route tracker location data source to snap the location display to the route
val routeTrackerLocationDataSource = RouteTrackerLocationDataSource(
routeTracker = routeTracker!!,
locationDataSource = simulatedLocationDataSource
)
// set the simulated location data source as the location data source for this app
locationDisplay.dataSource = routeTrackerLocationDataSource

Expand Down Expand Up @@ -261,6 +305,17 @@ class NavigateRouteWithReroutingViewModel(application: Application) :
isNavigateButtonEnabled = false
}
}
launch {
routeTracker?.rerouteStarted?.collect {
Log.e("REROUTE", "Started rerouting")
}
}
launch {
routeTracker?.rerouteCompleted?.collect {
val status = it.getOrNull()
Log.e("REROUTE", "Reroute completed: ${status?.javaClass?.simpleName}")
}
}
}
}

Expand Down
Loading

0 comments on commit 7ee8c68

Please sign in to comment.