maplibre-navigation-android
maplibre-navigation-android copied to clipboard
Update route onProgress (cut trail)
Android API: 29
Maplibre Navigation SDK version : Latest
Steps to trigger behavior
I want to update route in realtime and cut the trail of the route til the user has been travelled
This is how I do it
class MapRouteProgressChangeListener(private val mapRoute: NavigationMapRoute) :
ProgressChangeListener {
private val executorService = Executors.newCachedThreadPool()
private val handler = Handler(Looper.getMainLooper())
override fun onProgressChange(location: Location, routeProgress: RouteProgress) {
val directionsRoutes = mapRoute.retrieveDirectionsRoutes()
val primaryRouteIndex = mapRoute.retrievePrimaryRouteIndex()
if (!executorService.isShutdown) {
executorService.execute {
val newRoute = getNewRoute(routeProgress, location)
handler.postDelayed({
addNewRoute(newRoute, directionsRoutes, primaryRouteIndex)
mapRoute.addUpcomingManeuverArrow(routeProgress)
}, 1350)
}
}else {
mapRoute.removeRoute()
}
}
/**
* this must be removed on exit button call
*/
fun removeHandler() {
handler.removeCallbacksAndMessages(null)
executorService.shutdown()
}
private fun addNewRoute(
currentRoute: DirectionsRoute?, directionsRoutes: List<DirectionsRoute>,
primaryRouteIndex: Int
) {
if (isANewRoute(currentRoute, directionsRoutes, primaryRouteIndex)) {
mapRoute.addRoute(currentRoute)
}
}
private fun getNewRoute(progress: RouteProgress, loc: Location): DirectionsRoute {
val step = progress.currentLegProgress().currentStep()
if (step.geometry() == null) {
return progress.directionsRoute()
}
val start = Point.fromLngLat(loc.longitude, loc.latitude)
val points = PolylineUtils.decode(step.geometry()!!, 5)
val end = points.last()
if (start.latitude() == end.latitude() && start.longitude() == end.longitude()) {
return progress.directionsRoute()
}
step.geometry()?.let {
val newGeoMetre = getSlicedLine(it, start, end)
val polyline = progress.directionsRoute()
val newStep = polyline.legs()?.get(progress.legIndex())?.steps()?.get(
progress.currentLegProgress()
.stepIndex()
)?.toBuilder()?.geometry(newGeoMetre)?.build()
val newRoute = updatePolyLine(polyline, start)
newRoute?.let { route ->
route.legs()?.get(progress.legIndex())?.steps()?.set(
progress.currentLegProgress().stepIndex(), newStep
)
return newRoute
}
}
return progress.directionsRoute()
}
private fun updatePolyLine(polyline: DirectionsRoute?, start: Point): DirectionsRoute? {
polyline?.geometry()?.let {
val points = PolylineUtils.decode(
it, 5
)
val newGeoRetry = getSlicedLine(start, points)
return polyline.toBuilder().geometry(newGeoRetry).build()
}
return null
}
private fun getSlicedLine(polyline: String, start: Point, end: Point): String {
val points = PolylineUtils.decode(polyline, 5)
val finalLine = TurfMisc.lineSlice(start, end, LineString.fromLngLats(points))
return finalLine.toPolyline(5)
}
private fun getSlicedLine(start: Point, points: List<Point>): String {
val finalLine =
TurfMisc.lineSlice(start, points.last(), LineString.fromLngLats(points))
return finalLine.toPolyline(5)
}
private fun isANewRoute(
currentRoute: DirectionsRoute?, directionsRoutes: List<DirectionsRoute>,
primaryRouteIndex: Int
): Boolean {
val noRoutes = directionsRoutes.isEmpty()
return noRoutes || currentRoute != directionsRoutes[primaryRouteIndex]
}
}
This works but as you can see I am giving 1350 ms delay to keep this in sync with user current location marker. This also depends on the speed of the user from which he is travelling. Sometime it does not get synced properly and current location marker move a little ahead with some lag. Can you help me how can get implement it correctly. I want it to behave as Google Maps. (remove the trail of the route respective of current user location)