11package com.mapbox.navigation.ui.maps.internal.camera
22
33import androidx.annotation.RestrictTo
4+ import androidx.annotation.VisibleForTesting
45import com.mapbox.common.location.Location
56import com.mapbox.geojson.Point
67import com.mapbox.maps.CameraOptions
@@ -14,6 +15,7 @@ import com.mapbox.navigation.base.internal.utils.areSameRoutes
1415import com.mapbox.navigation.base.internal.utils.isSameRoute
1516import com.mapbox.navigation.base.route.NavigationRoute
1617import com.mapbox.navigation.base.trip.model.RouteProgress
18+ import com.mapbox.navigation.base.utils.DecodeUtils.stepGeometryToPoints
1719import com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSource.Companion.BEARING_NORTH
1820import com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSource.Companion.EMPTY_EDGE_INSETS
1921import com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSource.Companion.NULL_ISLAND_POINT
@@ -29,12 +31,29 @@ import com.mapbox.navigation.utils.internal.logW
2931import com.mapbox.navigation.utils.internal.toPoint
3032import kotlin.math.min
3133
34+ private data class RouteIndices (
35+ val legIndex : Int ,
36+ val stepIndex : Int ,
37+ val legGeometryIndex : Int ,
38+ )
39+
40+ private data class CachedRemainingPoints (
41+ val indices : RouteIndices ,
42+ val remainingPointsOnCurrentStep : List <Point >,
43+ )
44+
3245@RestrictTo(RestrictTo .Scope .LIBRARY_GROUP_PREFIX )
33- class OverviewViewportDataSource (
46+ class OverviewViewportDataSource @VisibleForTesting internal constructor (
3447 private val mapboxMap : MapboxMap ,
3548 internalOptions : InternalViewportDataSourceOptions ,
49+ private val indicesConverter : RoutesIndicesConverter ,
3650) {
3751
52+ constructor (
53+ mapboxMap: MapboxMap ,
54+ internalOptions: InternalViewportDataSourceOptions ,
55+ ) : this (mapboxMap, internalOptions, RoutesIndicesConverter ())
56+
3857 internal var internalOptions = internalOptions
3958 set(value) {
4059 if (field != value) {
@@ -47,10 +66,10 @@ class OverviewViewportDataSource(
4766
4867 private var navigationRoutes: List <NavigationRoute > = emptyList()
4968 private var routeProgress: RouteProgress ? = null
50- private var pointsToFrameOnCurrentStep: List <Point > = emptyList()
5169 private var simplifiedCompleteRoutesPoints: List <List <List <List <Point >>>> = emptyList()
5270 private var simplifiedRemainingPointsOnRoutes: List <Point > = emptyList()
5371 private var targetLocation: Location ? = null
72+ private var cachedRemainingPoints: MutableMap <String , CachedRemainingPoints > = hashMapOf()
5473
5574 @OptIn(ExperimentalPreviewMapboxNavigationAPI ::class )
5675 var debugger: MapboxNavigationViewportDataSourceDebugger ? = null
@@ -85,7 +104,7 @@ class OverviewViewportDataSource(
85104
86105 private fun reevaluate () {
87106 calculateRouteData(navigationRoutes)
88- routeProgress?.let { onRouteProgressChanged(it, pointsToFrameOnCurrentStep ) }
107+ routeProgress?.let { onRouteProgressChanged(it) }
89108 evaluate()
90109 }
91110
@@ -101,15 +120,22 @@ class OverviewViewportDataSource(
101120 if (routes.isEmpty()) {
102121 clearRouteData()
103122 } else {
104- val completeRoutePoints = routes
123+ val completeRoutesPoints = routes
105124 .mapIndexedNotNull { index, route ->
106125 if (index == 0 || internalOptions.overviewAlternatives) {
107126 processRoutePoints(route.directionsRoute)
108127 } else {
109128 null
110129 }
111130 }
112- simplifiedCompleteRoutesPoints = completeRoutePoints.map {
131+ indicesConverter.onRoutesChanged(
132+ if (internalOptions.overviewAlternatives) {
133+ routes
134+ } else {
135+ routes.take(1 )
136+ },
137+ )
138+ simplifiedCompleteRoutesPoints = completeRoutesPoints.map {
113139 simplifyCompleteRoutePoints(
114140 options.overviewFrameOptions.geometrySimplification.enabled,
115141 options.overviewFrameOptions.geometrySimplification.simplificationFactor,
@@ -124,6 +150,7 @@ class OverviewViewportDataSource(
124150
125151 fun clearRouteData () {
126152 this .navigationRoutes = emptyList()
153+ indicesConverter.onRoutesChanged(emptyList())
127154 runIfActive {
128155 simplifiedCompleteRoutesPoints = emptyList()
129156 simplifiedRemainingPointsOnRoutes = emptyList()
@@ -132,7 +159,7 @@ class OverviewViewportDataSource(
132159
133160 fun clearProgressData () {
134161 this .routeProgress = null
135- pointsToFrameOnCurrentStep = emptyList ()
162+ cachedRemainingPoints = hashMapOf ()
136163 runIfActive {
137164 simplifiedRemainingPointsOnRoutes = simplifiedCompleteRoutesPoints
138165 .flatten().flatten().flatten()
@@ -141,10 +168,8 @@ class OverviewViewportDataSource(
141168
142169 fun onRouteProgressChanged (
143170 routeProgress : RouteProgress ,
144- pointsToFrameOnCurrentStep : List <Point >,
145171 ) {
146172 this .routeProgress = routeProgress
147- this .pointsToFrameOnCurrentStep = pointsToFrameOnCurrentStep
148173 val currentRoute = this .navigationRoutes.firstOrNull()
149174 if (currentRoute == null ) {
150175 return
@@ -158,37 +183,71 @@ class OverviewViewportDataSource(
158183 routeProgress.currentLegProgress,
159184 routeProgress.currentLegProgress?.currentStepProgress,
160185 ) { currentLegProgress, currentStepProgress ->
161- val primaryPoints = getRemainingPointsOnRoute(
162- simplifiedCompleteRoutesPoints.first(),
163- pointsToFrameOnCurrentStep,
164- internalOptions.overviewMode,
165- currentLegProgress.legIndex,
166- currentStepProgress.stepIndex,
167- )
168- val alternativePoints = if (internalOptions.overviewAlternatives) {
169- navigationRoutes.drop(1 ).mapIndexedNotNull { index, route ->
170- val alternativeIndices = routeProgress
171- .internalAlternativeRouteIndices()[route.id]
172- if (alternativeIndices == null ) {
186+ simplifiedRemainingPointsOnRoutes =
187+ navigationRoutes.mapIndexedNotNull { index, route ->
188+ if (index > 0 && ! internalOptions.overviewAlternatives) {
173189 null
174190 } else {
175- getRemainingPointsOnRoute(
176- simplifiedCompleteRoutesPoints[index + 1 ],
177- emptyList(), // already overviewed by primary route
178- internalOptions.overviewMode,
179- alternativeIndices.legIndex,
180- alternativeIndices.stepIndex,
181- )
191+ val indices = if (index == 0 ) {
192+ RouteIndices (
193+ currentLegProgress.legIndex,
194+ currentStepProgress.stepIndex,
195+ currentLegProgress.geometryIndex,
196+ )
197+ } else {
198+ routeProgress.internalAlternativeRouteIndices()[route.id]?.let {
199+ RouteIndices (it.legIndex, it.stepIndex, it.legGeometryIndex)
200+ }
201+ }
202+ if (indices == null ) {
203+ null
204+ } else {
205+ if (indices != cachedRemainingPoints[route.id]?.indices) {
206+ val stepGeometryIndex = indicesConverter.convert(
207+ route.id,
208+ indices.legIndex,
209+ indices.stepIndex,
210+ indices.legGeometryIndex,
211+ )
212+ if (stepGeometryIndex != null ) {
213+ cachedRemainingPoints[route.id] = getCachedRemainingPoints(
214+ route,
215+ indices,
216+ stepGeometryIndex,
217+ )
218+ }
219+ }
220+ getRemainingPointsOnRoute(
221+ simplifiedCompleteRoutesPoints[index],
222+ cachedRemainingPoints[route.id]?.remainingPointsOnCurrentStep
223+ .orEmpty(),
224+ internalOptions.overviewMode,
225+ indices.legIndex,
226+ indices.stepIndex,
227+ )
228+ }
182229 }
183230 }.flatten()
184- } else {
185- emptyList()
186- }
187- simplifiedRemainingPointsOnRoutes = primaryPoints + alternativePoints
188231 }
189232 }
190233 }
191234
235+ private fun getCachedRemainingPoints (
236+ route : NavigationRoute ,
237+ indices : RouteIndices ,
238+ stepGeometryIndex : Int ,
239+ ): CachedRemainingPoints {
240+ val remainingPointsOnCurrentStep = route.directionsRoute.legs()
241+ ?.getOrNull(indices.legIndex)
242+ ?.steps()
243+ ?.getOrNull(indices.stepIndex)?.let {
244+ route.directionsRoute.stepGeometryToPoints(it)
245+ }
246+ ?.drop(stepGeometryIndex)
247+ .orEmpty()
248+ return CachedRemainingPoints (indices, remainingPointsOnCurrentStep)
249+ }
250+
192251 fun onLocationChanged (location : Location ) {
193252 this .targetLocation = location
194253 }
0 commit comments