Skip to content

Commit b53d874

Browse files
committed
Compare routes using step names
1 parent fcc9280 commit b53d874

File tree

9 files changed

+227
-24
lines changed

9 files changed

+227
-24
lines changed

examples/src/main/java/com/mapbox/navigation/examples/core/ReplayActivity.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.mapbox.navigation.base.internal.extensions.applyDefaultParams
2323
import com.mapbox.navigation.base.internal.extensions.coordinates
2424
import com.mapbox.navigation.core.MapboxNavigation
2525
import com.mapbox.navigation.core.directions.session.RoutesRequestCallback
26+
import com.mapbox.navigation.core.fasterroute.FasterRouteObserver
2627
import com.mapbox.navigation.core.replay.MapboxReplayer
2728
import com.mapbox.navigation.core.replay.ReplayLocationEngine
2829
import com.mapbox.navigation.core.replay.route.ReplayRouteMapper
@@ -39,7 +40,7 @@ import kotlinx.android.synthetic.main.activity_replay_route_layout.*
3940

4041
/**
4142
* This activity shows how to use the MapboxNavigation
42-
* class with the Navigation SDK's [ReplayHistoryLocationEngine].
43+
* class with the Navigation SDK's [MapboxReplayer] and [ReplayLocationEngine].
4344
*/
4445
class ReplayActivity : AppCompatActivity(), OnMapReadyCallback {
4546

@@ -82,6 +83,13 @@ class ReplayActivity : AppCompatActivity(), OnMapReadyCallback {
8283
navigationMapboxMap?.restoreFrom(state)
8384
}
8485
initializeFirstLocation()
86+
87+
mapboxNavigation?.attachFasterRouteObserver(object : FasterRouteObserver {
88+
override fun onFasterRoute(currentRoute: DirectionsRoute, alternatives: List<DirectionsRoute>, isAlternativeFaster: Boolean) {
89+
navigationMapboxMap?.drawRoutes(alternatives)
90+
mapboxNavigation?.setRoutes(alternatives)
91+
}
92+
})
8593
}
8694
mapboxMap.addOnMapLongClickListener { latLng ->
8795
mapboxMap.locationComponent.lastKnownLocation?.let { originLocation ->
@@ -110,7 +118,7 @@ class ReplayActivity : AppCompatActivity(), OnMapReadyCallback {
110118
override fun onRoutesReady(routes: List<DirectionsRoute>) {
111119
MapboxLogger.d(Message("route request success $routes"))
112120
if (routes.isNotEmpty()) {
113-
navigationMapboxMap?.drawRoute(routes[0])
121+
navigationMapboxMap?.drawRoutes(routes)
114122

115123
val replayEvents = replayRouteMapper.mapGeometry(routes[0].geometry()!!)
116124
mapboxReplayer.pushEvents(replayEvents)

examples/src/main/java/com/mapbox/navigation/examples/core/ReplayHistoryActivity.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.mapbox.navigation.base.internal.extensions.applyDefaultParams
2323
import com.mapbox.navigation.base.internal.extensions.coordinates
2424
import com.mapbox.navigation.core.MapboxNavigation
2525
import com.mapbox.navigation.core.directions.session.RoutesRequestCallback
26+
import com.mapbox.navigation.core.fasterroute.FasterRouteObserver
2627
import com.mapbox.navigation.core.replay.MapboxReplayer
2728
import com.mapbox.navigation.core.replay.ReplayLocationEngine
2829
import com.mapbox.navigation.core.replay.history.CustomEventMapper
@@ -171,6 +172,13 @@ class ReplayHistoryActivity : AppCompatActivity() {
171172
}
172173
})
173174

175+
mapboxNavigation.attachFasterRouteObserver(object : FasterRouteObserver {
176+
override fun onFasterRoute(currentRoute: DirectionsRoute, alternatives: List<DirectionsRoute>, isAlternativeFaster: Boolean) {
177+
navigationContext?.navigationMapboxMap?.drawRoutes(alternatives)
178+
navigationContext?.mapboxNavigation?.setRoutes(alternatives)
179+
}
180+
})
181+
174182
playReplay.setOnClickListener {
175183
mapboxReplayer.play()
176184
mapboxNavigation.startTripSession()
@@ -235,7 +243,7 @@ class ReplayHistoryActivity : AppCompatActivity() {
235243
override fun onRoutesReady(routes: List<DirectionsRoute>) {
236244
MapboxLogger.d(Message("route request success $routes"))
237245
if (routes.isNotEmpty()) {
238-
navigationContext?.navigationMapboxMap?.drawRoute(routes[0])
246+
navigationContext?.navigationMapboxMap?.drawRoutes(routes)
239247
navigationContext?.startNavigation()
240248
}
241249
}

libnavigation-core/src/main/java/com/mapbox/navigation/core/MapboxNavigation.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import com.mapbox.navigation.core.directions.session.DirectionsSession
3333
import com.mapbox.navigation.core.directions.session.RoutesObserver
3434
import com.mapbox.navigation.core.directions.session.RoutesRequestCallback
3535
import com.mapbox.navigation.core.fasterroute.FasterRouteController
36+
import com.mapbox.navigation.core.fasterroute.FasterRouteDetector
3637
import com.mapbox.navigation.core.fasterroute.FasterRouteObserver
38+
import com.mapbox.navigation.core.fasterroute.RouteComparator
3739
import com.mapbox.navigation.core.internal.MapboxDistanceFormatter
3840
import com.mapbox.navigation.core.internal.accounts.MapboxNavigationAccounts
3941
import com.mapbox.navigation.core.internal.trip.service.TripService
@@ -195,7 +197,12 @@ class MapboxNavigation(
195197
)
196198
}
197199

198-
fasterRouteController = FasterRouteController(directionsSession, tripSession, logger)
200+
fasterRouteController = FasterRouteController(
201+
directionsSession,
202+
tripSession,
203+
logger,
204+
FasterRouteDetector(RouteComparator())
205+
)
199206
routeRefreshController = RouteRefreshController(directionsSession, tripSession, logger)
200207
routeRefreshController.start()
201208

libnavigation-core/src/main/java/com/mapbox/navigation/core/fasterroute/FasterRouteController.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import java.util.concurrent.TimeUnit
1515
internal class FasterRouteController(
1616
private val directionsSession: DirectionsSession,
1717
private val tripSession: TripSession,
18-
private val logger: Logger
18+
private val logger: Logger,
19+
private val fasterRouteDetector: FasterRouteDetector
1920
) {
2021

2122
private val fasterRouteTimer = MapboxTimer()
22-
private val fasterRouteDetector = FasterRouteDetector()
2323
private var fasterRouteObserver: FasterRouteObserver? = null
2424

2525
fun attach(fasterRouteObserver: FasterRouteObserver) {

libnavigation-core/src/main/java/com/mapbox/navigation/core/fasterroute/FasterRouteDetector.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ package com.mapbox.navigation.core.fasterroute
33
import com.mapbox.api.directions.v5.models.DirectionsRoute
44
import com.mapbox.navigation.base.trip.model.RouteProgress
55

6-
internal class FasterRouteDetector {
7-
fun isRouteFaster(newRoute: DirectionsRoute, routeProgress: RouteProgress): Boolean {
8-
val newRouteDuration = newRoute.duration() ?: return false
6+
internal class FasterRouteDetector(
7+
private val routeComparator: RouteComparator
8+
) {
9+
10+
fun isRouteFaster(alternativeRoute: DirectionsRoute, routeProgress: RouteProgress): Boolean {
11+
val alternativeDuration = alternativeRoute.duration() ?: return false
912
val weightedDuration = routeProgress.durationRemaining * PERCENTAGE_THRESHOLD
10-
return newRouteDuration < weightedDuration
13+
val isNewRouteFaster = alternativeDuration < weightedDuration
14+
return isNewRouteFaster && routeComparator.isNewRoute(routeProgress, alternativeRoute)
1115
}
1216

1317
companion object {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.mapbox.navigation.core.fasterroute
2+
3+
import com.mapbox.api.directions.v5.models.DirectionsRoute
4+
import com.mapbox.api.directions.v5.models.LegStep
5+
import com.mapbox.navigation.base.trip.model.RouteProgress
6+
7+
/**
8+
* Compares if an alternative route is different from the current route progress.
9+
*/
10+
internal class RouteComparator {
11+
12+
private val mapLegStepToName: (LegStep) -> String = { it.name() ?: "" }
13+
14+
/**
15+
* @param routeProgress current route progress
16+
* @param alternativeRoute suggested new route
17+
*
18+
* @return true when the alternative route has different
19+
* geometry from the current route progress
20+
*/
21+
fun isNewRoute(routeProgress: RouteProgress, alternativeRoute: DirectionsRoute): Boolean {
22+
val currentDescription = routeDescription(routeProgress)
23+
val alternativeDescription = alternativeDescription(alternativeRoute)
24+
alternativeDescription.ifEmpty {
25+
return false
26+
}
27+
28+
return isNewRoute(currentDescription, alternativeDescription)
29+
}
30+
31+
private fun routeDescription(routeProgress: RouteProgress): String {
32+
val routeLeg = routeProgress.currentLegProgress?.routeLeg
33+
val steps = routeLeg?.steps()
34+
val stepIndex = routeProgress.currentLegProgress?.currentStepProgress?.stepIndex
35+
?: return ""
36+
37+
return steps?.listIterator(stepIndex)?.asSequence()
38+
?.joinToString(transform = mapLegStepToName) ?: ""
39+
}
40+
41+
private fun alternativeDescription(directionsRoute: DirectionsRoute): String {
42+
val steps = directionsRoute.legs()?.firstOrNull()?.steps()
43+
return steps?.asSequence()
44+
?.joinToString(transform = mapLegStepToName) ?: ""
45+
}
46+
47+
private fun isNewRoute(currentGeometry: String, alternativeGeometry: String): Boolean {
48+
return currentGeometry != alternativeGeometry
49+
}
50+
}

libnavigation-core/src/test/java/com/mapbox/navigation/core/fasterroute/FasterRouteControllerTest.kt

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,18 @@ class FasterRouteControllerTest {
2727
val coroutineRule = MainCoroutineRule()
2828

2929
private val directionsSession: DirectionsSession = mockk()
30-
private val tripSession: TripSession = mockk()
30+
private val tripSession: TripSession = mockk {
31+
every { getRouteProgress() } returns mockk()
32+
}
3133
private val fasterRouteObserver: FasterRouteObserver = mockk {
3234
every { restartAfterMillis() } returns FasterRouteObserver.DEFAULT_INTERVAL_MILLIS
3335
every { onFasterRoute(any(), any(), any()) } returns Unit
3436
}
3537
private val routesRequestCallbacks = slot<RoutesRequestCallback>()
36-
3738
private val logger: Logger = mockk()
38-
private val fasterRouteController = FasterRouteController(directionsSession, tripSession, logger)
39+
private val fasterRouteDetector: FasterRouteDetector = mockk()
40+
41+
private val fasterRouteController = FasterRouteController(directionsSession, tripSession, logger, fasterRouteDetector)
3942

4043
@Before
4144
fun setup() {
@@ -111,25 +114,21 @@ class FasterRouteControllerTest {
111114

112115
@Test
113116
fun `should notify observer of a faster route`() = coroutineRule.runBlockingTest {
117+
every { fasterRouteDetector.isRouteFaster(any(), any()) } returns true
114118
val currentRoute: DirectionsRoute = mockk {
115119
every { routeIndex() } returns "0"
116-
every { duration() } returns 801.332
117120
}
118121
every { directionsSession.routes } returns listOf(currentRoute)
119122
every { tripSession.getEnhancedLocation() } returns mockk {
120123
every { latitude } returns -33.874308
121124
every { longitude } returns 151.206087
122125
}
123-
every { tripSession.getRouteProgress() } returns mockk {
124-
every { durationRemaining } returns 601.334
125-
}
126126
every { directionsSession.requestFasterRoute(any(), capture(routesRequestCallbacks)) } returns mockk()
127127

128128
fasterRouteController.attach(fasterRouteObserver)
129129
coroutineRule.testDispatcher.advanceTimeBy(TimeUnit.MINUTES.toMillis(6))
130130
val routes = listOf<DirectionsRoute>(mockk {
131131
every { routeIndex() } returns "0"
132-
every { duration() } returns 351.013
133132
})
134133
routesRequestCallbacks.captured.onRoutesReady(routes)
135134

@@ -141,25 +140,21 @@ class FasterRouteControllerTest {
141140

142141
@Test
143142
fun `should notify observer if current route is fastest`() = coroutineRule.runBlockingTest {
143+
every { fasterRouteDetector.isRouteFaster(any(), any()) } returns false
144144
val currentRoute: DirectionsRoute = mockk {
145145
every { routeIndex() } returns "0"
146-
every { duration() } returns 801.332
147146
}
148147
every { directionsSession.routes } returns listOf(currentRoute)
149148
every { tripSession.getEnhancedLocation() } returns mockk {
150149
every { latitude } returns -33.874308
151150
every { longitude } returns 151.206087
152151
}
153-
every { tripSession.getRouteProgress() } returns mockk {
154-
every { durationRemaining } returns 751.334
155-
}
156152
every { directionsSession.requestFasterRoute(any(), capture(routesRequestCallbacks)) } returns mockk()
157153

158154
fasterRouteController.attach(fasterRouteObserver)
159155
coroutineRule.testDispatcher.advanceTimeBy(TimeUnit.MINUTES.toMillis(6))
160156
val routes = listOf<DirectionsRoute>(mockk {
161157
every { routeIndex() } returns "0"
162-
every { duration() } returns 951.013
163158
})
164159
routesRequestCallbacks.captured.onRoutesReady(routes)
165160

libnavigation-core/src/test/java/com/mapbox/navigation/core/fasterroute/FasterRouteDetectorTest.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ import org.junit.Assert.assertTrue
99
import org.junit.Test
1010

1111
class FasterRouteDetectorTest {
12+
private val routeComparator: RouteComparator = mockk {
13+
every { isNewRoute(any(), any()) } returns true
14+
}
1215

13-
private val fasterRouteDetector = FasterRouteDetector()
16+
private val fasterRouteDetector = FasterRouteDetector(routeComparator)
1417

1518
@Test
1619
fun shouldDetectWhenRouteIsFaster() {
20+
every { routeComparator.isNewRoute(any(), any()) } returns true
1721
val newRoute: DirectionsRoute = mockk()
1822
every { newRoute.duration() } returns 402.6
1923
val routeProgress: RouteProgress = mockk()
@@ -24,6 +28,19 @@ class FasterRouteDetectorTest {
2428
assertTrue(isFasterRoute)
2529
}
2630

31+
@Test
32+
fun shouldDetectWhenRouteIsFasterOnlyIfDifferent() {
33+
every { routeComparator.isNewRoute(any(), any()) } returns false
34+
val newRoute: DirectionsRoute = mockk()
35+
every { newRoute.duration() } returns 402.6
36+
val routeProgress: RouteProgress = mockk()
37+
every { routeProgress.durationRemaining } returns 797.447
38+
39+
val isFasterRoute = fasterRouteDetector.isRouteFaster(newRoute, routeProgress)
40+
41+
assertFalse(isFasterRoute)
42+
}
43+
2744
@Test
2845
fun shouldDetectWhenRouteIsSlower() {
2946
val newRoute: DirectionsRoute = mockk()

0 commit comments

Comments
 (0)