maplibre-navigation-android icon indicating copy to clipboard operation
maplibre-navigation-android copied to clipboard

Update route onProgress (cut trail)

Open 1q09 opened this issue 2 years ago • 0 comments

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)

route should be updated in sync with the current user location and trail should be removed irrespective of user speed.

update route is not syncing with the current user location

1q09 avatar Oct 18 '22 13:10 1q09