Skip to content

Commit e5e4c85

Browse files
committed
- Changed experimental extension NavigationRoute#hasUnexpectedClosures -> RouteProgress#hasUnexpectedUpcomingClosures (#6841)
* - Changed experimental extension `NavigationRoute#hasUnexpectedClosures` -> `RouteProgress#hasUnexpectedUpcomingClosures`: the algorithm is checking upcoming closures only, ignoring closures where the puck is already at.
1 parent 85812e8 commit e5e4c85

File tree

6 files changed

+149
-33
lines changed

6 files changed

+149
-33
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Removed `NavigationRoute#hasUnexpectedClosures` and added `RouteProgress#hasUnexpectedUpcomingClosures` instead that checks whether route has upcoming unexpected closures (the algorithm does not take into account closures that the puck has already been on)

libnavigation-base/api/current.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,7 +1745,7 @@ package com.mapbox.navigation.base.utils {
17451745
package com.mapbox.navigation.base.utils.route {
17461746

17471747
public final class NavigationRouteUtils {
1748-
method @com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public static suspend Object? hasUnexpectedClosures(com.mapbox.navigation.base.route.NavigationRoute, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
1748+
method @com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public static suspend Object? hasUnexpectedUpcomingClosures(com.mapbox.navigation.base.trip.model.RouteProgress, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
17491749
}
17501750

17511751
}
Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,57 @@ import com.mapbox.api.directions.v5.models.RouteOptions
88
import com.mapbox.geojson.Point
99
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
1010
import com.mapbox.navigation.base.route.NavigationRoute
11+
import com.mapbox.navigation.base.trip.model.RouteProgress
1112
import com.mapbox.navigation.base.utils.DecodeUtils.stepGeometryToPoints
13+
import com.mapbox.navigation.utils.internal.ifNonNull
1214
import com.mapbox.navigation.utils.internal.logD
1315
import kotlinx.coroutines.Dispatchers
1416
import kotlinx.coroutines.withContext
1517

1618
private const val LOG_CATEGORY = "NavigationRouteUtils"
1719

1820
/**
19-
* This function checks whether the [NavigationRoute] has unexpected closures, which could be a reason to re-route.
21+
* This function checks whether the [NavigationRoute] has unexpected upcoming closures, which could be a reason to re-route.
2022
*
21-
* `true` is returned whenever there's any [RouteLeg.closures] outside of a direct region around a coordinate from [RouteOptions.coordinatesList]
23+
* The algorithm does not take to account current closures, where the puck is on.
24+
*
25+
* `true` is returned whenever there's any upcoming [RouteLeg.closures] outside of a direct region around a coordinate from [RouteOptions.coordinatesList]
2226
* that was allowed for snapping to closures with [RouteOptions.snappingIncludeClosuresList] or [RouteOptions.snappingIncludeStaticClosuresList].
2327
* flags. Otherwise, `false` is returned.
2428
*/
2529
@ExperimentalPreviewMapboxNavigationAPI
26-
suspend fun NavigationRoute.hasUnexpectedClosures(): Boolean =
30+
suspend fun RouteProgress.hasUnexpectedUpcomingClosures(): Boolean =
2731
withContext(Dispatchers.Default) {
28-
val snappingResultList = directionsRoute.getSnappingResultList()
32+
val snappingResultList = navigationRoute.directionsRoute.getSnappingResultList()
33+
34+
val routeProgressData = ifNonNull(
35+
currentLegProgress,
36+
) { legProgress ->
37+
RouteProgressData(legProgress.legIndex, legProgress.geometryIndex)
38+
}
2939

3040
var currentLegFirstWaypointIndex = 0
31-
directionsRoute.legs()?.forEachIndexed { routeLegIndex, routeLeg ->
41+
navigationRoute.directionsRoute.legs()?.forEachIndexed { routeLegIndex, routeLeg ->
3242

3343
val legLastGeometryIndex by lazy {
34-
directionsRoute.stepsGeometryToPoints(routeLeg).lastIndex
44+
navigationRoute.directionsRoute.stepsGeometryToPoints(routeLeg).lastIndex
3545
}
3646

3747
val silentWaypoints = routeLeg.silentWaypoints()
3848

3949
routeLeg.closures()?.forEach { closure ->
50+
if (routeProgressData != null) {
51+
if (routeProgressData.currentLegIndex > routeLegIndex) {
52+
// skipping passed legs
53+
return@forEach
54+
} else if (
55+
routeProgressData.currentLegIndex == routeLegIndex &&
56+
routeProgressData.currentGeometryLegIndex >= closure.geometryIndexStart()
57+
) {
58+
// skipping current and passed closures on the current leg
59+
return@forEach
60+
}
61+
}
4062
val silentWaypointsInClosureRange = silentWaypoints.inGeometryRange(
4163
closure.geometryIndexStart(),
4264
closure.geometryIndexEnd()
@@ -49,9 +71,10 @@ suspend fun NavigationRoute.hasUnexpectedClosures(): Boolean =
4971
snappingResultList.getOrNull(silentWaypointIndex) ?: false
5072
if (!isSnapAllowed) {
5173
logD(
52-
"Route with id [${this@hasUnexpectedClosures.id}] has closure " +
53-
"at leg index $routeLegIndex, that overlaps silent (via) " +
54-
"waypoint",
74+
"Route with id " +
75+
"[${this@hasUnexpectedUpcomingClosures.navigationRoute.id}] " +
76+
"has closure at leg index $routeLegIndex, that overlaps " +
77+
"silent (via) waypoint",
5578
LOG_CATEGORY
5679
)
5780
return@withContext true
@@ -63,17 +86,19 @@ suspend fun NavigationRoute.hasUnexpectedClosures(): Boolean =
6386
silentWaypointsInClosureRange.isEmpty()
6487
) {
6588
logD(
66-
"Route with id [${this@hasUnexpectedClosures.id}] has closure at leg " +
67-
"index $routeLegIndex",
89+
"Route with id " +
90+
"[${this@hasUnexpectedUpcomingClosures.navigationRoute.id}] has " +
91+
"closure at leg index $routeLegIndex",
6892
)
6993
return@withContext true
7094
}
7195
if (closure.geometryIndexStart() == 0 &&
7296
snappingResultList.getOrNull(currentLegFirstWaypointIndex) != true
7397
) {
7498
logD(
75-
"Route with id [${this@hasUnexpectedClosures.id}] has closure at the " +
76-
"start of the leg, leg index $routeLegIndex",
99+
"Route with id " +
100+
"[${this@hasUnexpectedUpcomingClosures.navigationRoute.id}] has " +
101+
"closure at the start of the leg, leg index $routeLegIndex",
77102
LOG_CATEGORY
78103
)
79104
return@withContext true
@@ -84,8 +109,9 @@ suspend fun NavigationRoute.hasUnexpectedClosures(): Boolean =
84109
) != true
85110
) {
86111
logD(
87-
"Route with id [${this@hasUnexpectedClosures.id}] has closure at " +
88-
"the end of the leg, leg index $routeLegIndex",
112+
"Route with id " +
113+
"[${this@hasUnexpectedUpcomingClosures.navigationRoute.id}] has " +
114+
"closure at the end of the leg, leg index $routeLegIndex",
89115
LOG_CATEGORY
90116
)
91117
return@withContext true
@@ -98,6 +124,11 @@ suspend fun NavigationRoute.hasUnexpectedClosures(): Boolean =
98124
return@withContext false
99125
}
100126

127+
private class RouteProgressData(
128+
val currentLegIndex: Int,
129+
val currentGeometryLegIndex: Int,
130+
)
131+
101132
private fun DirectionsRoute.getSnappingResultList(): List<Boolean> {
102133
val snappingIncludeClosuresList = routeOptions()?.snappingIncludeClosuresList()
103134
val snappingIncludeStaticClosuresList = routeOptions()?.snappingIncludeStaticClosuresList()
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith
3131
import org.junit.runners.Parameterized
3232
import java.net.URL
3333

34-
class NavigationRouteExTest {
34+
class RouteProgressExTest {
3535

3636
@Test
3737
fun `update Navigation route`() {
Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import com.mapbox.api.directions.v5.DirectionsCriteria
44
import com.mapbox.api.directions.v5.models.DirectionsRoute
55
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
66
import com.mapbox.navigation.base.route.NavigationRoute
7+
import com.mapbox.navigation.base.trip.model.RouteProgress
78
import com.mapbox.navigation.testing.FileUtils
89
import com.mapbox.navigation.testing.LoggingFrontendTestRule
910
import io.mockk.every
1011
import io.mockk.mockk
11-
import junit.framework.Assert
12+
import junit.framework.Assert.assertEquals
1213
import kotlinx.coroutines.runBlocking
1314
import org.junit.Rule
1415
import org.junit.Test
@@ -17,22 +18,32 @@ import org.junit.runners.Parameterized
1718

1819
private typealias BooleansProvider = () -> List<Boolean?>
1920

20-
class NavigationRouteExTest {
21+
class RouteProgressExTest {
2122

2223
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
2324
@RunWith(Parameterized::class)
24-
class RouteHasUnexpectedClosures(
25+
class RouteHasUnexpectedUpcomingClosures(
2526
private val description: String,
2627
private val routeRaw: String,
2728
private val snappingIncludeClosures: BooleansProvider?,
2829
private val snappingIncludeStaticClosures: BooleansProvider?,
29-
private val expectedHasUnexpectedClosures: Boolean,
30+
private val currentLegIndex: Int,
31+
private val currentGeometryLegIndex: Int,
32+
private val expectedHasUnexpectedUpcomingClosures: Boolean,
3033
) {
3134

3235
@get:Rule
3336
val loggerRule = LoggingFrontendTestRule()
3437

3538
companion object {
39+
/**
40+
* - `route_closure_start_coordinate`: closure[0, 8], leg [0];
41+
* - `route_closure_second_waypoint`: closure[5, 8], leg [0] and closure[0, 8], leg[1];
42+
* - `route_closure_second_silent_waypoint`: closure[5, 16], leg [0];
43+
* - `route_closure_last_coordinate`: closure[4, 7], leg [1];
44+
* - `route_closure_between_silent_and_regular_waypoints`: closure[12, 13], leg [0];
45+
* - `route_closure_between_two_regular_waypoints`: closure[2, 3], leg [1];
46+
*/
3647
@JvmStatic
3748
@Parameterized.Parameters(name = "{0}")
3849
fun data(): List<Array<Any?>> =
@@ -42,90 +53,147 @@ class NavigationRouteExTest {
4253
"multileg_route.json",
4354
{ null },
4455
{ null },
56+
0,
57+
0,
4558
false,
4659
),
4760
arrayOf(
48-
"route closure at starting waypoint, include closures = false",
61+
"route closure at starting waypoint, include closures = false; " +
62+
"the puck is in the very beginning",
4963
"route_closure_start_coordinate.json",
5064
provideBooleansProvider(false, true, true),
5165
provideBooleansProvider(false, true, true),
52-
true,
66+
0,
67+
0,
68+
false,
5369
),
5470
arrayOf(
5571
"route closure at starting waypoint, include closures = true",
5672
"route_closure_start_coordinate.json",
5773
provideBooleansProvider(true, false, false),
5874
provideBooleansProvider(true, false, false),
75+
0,
76+
0,
5977
false,
6078
),
6179
arrayOf(
6280
"route closure at starting waypoint, include closures = true",
6381
"route_closure_start_coordinate.json",
6482
provideBooleansProvider(false, false, false),
6583
provideBooleansProvider(true, false, false),
84+
0,
85+
0,
6686
false,
6787
),
6888
arrayOf(
6989
"route closure at starting waypoint, include closures = true",
7090
"route_closure_start_coordinate.json",
7191
provideBooleansProvider(true, false, false),
7292
provideBooleansProvider(false, false, false),
93+
0,
94+
0,
7395
false,
7496
),
7597
arrayOf(
7698
"route closure at second waypoint, include closures = false",
7799
"route_closure_second_waypoint.json",
78100
provideBooleansProvider(true, false, true),
79101
provideBooleansProvider(true, false, true),
102+
0,
103+
0,
80104
true,
81105
),
106+
arrayOf(
107+
"route closure at second waypoint, include closures = false; " +
108+
"the puck is on the first closure of 2",
109+
"route_closure_second_waypoint.json",
110+
provideBooleansProvider(true, false, true),
111+
provideBooleansProvider(true, false, true),
112+
0,
113+
6,
114+
true,
115+
),
116+
arrayOf(
117+
"route closure at second waypoint, include closures = false; " +
118+
"the puck is on the second closure of 2",
119+
"route_closure_second_waypoint.json",
120+
provideBooleansProvider(true, false, true),
121+
provideBooleansProvider(true, false, true),
122+
1,
123+
7,
124+
false,
125+
),
82126
arrayOf(
83127
"route closure at second waypoint, include closures = true",
84128
"route_closure_second_waypoint.json",
85129
provideBooleansProvider(false, true, false),
86130
provideBooleansProvider(false, true, false),
131+
0,
132+
0,
87133
false,
88134
),
89135
arrayOf(
90136
"route closure at second *silent* waypoint, include closures = false",
91-
"route_closure_second_silent_waypoin.json",
137+
"route_closure_second_silent_waypoint.json",
92138
provideBooleansProvider(true, false, true),
93139
provideBooleansProvider(true, false, true),
140+
0,
141+
5,
142+
false,
143+
),
144+
arrayOf(
145+
"route closure at second *silent* waypoint, include closures = false;" +
146+
"the puck has just stepped on the closure",
147+
"route_closure_second_silent_waypoint.json",
148+
provideBooleansProvider(true, false, true),
149+
provideBooleansProvider(true, false, true),
150+
0,
151+
0,
94152
true,
95153
),
96154
arrayOf(
97155
"route closure at second *silent* waypoint, include closures = true",
98-
"route_closure_second_silent_waypoin.json",
156+
"route_closure_second_silent_waypoint.json",
99157
provideBooleansProvider(false, true, false),
100158
provideBooleansProvider(false, true, false),
159+
0,
160+
0,
101161
false,
102162
),
103163
arrayOf(
104164
"route closure at last waypoint, include closures = false",
105165
"route_closure_last_coordinate.json",
106166
provideBooleansProvider(true, true, false),
107167
provideBooleansProvider(true, true, false),
168+
0,
169+
0,
108170
true,
109171
),
110172
arrayOf(
111173
"route closure at last waypoint, include closures = true",
112174
"route_closure_last_coordinate.json",
113175
provideBooleansProvider(false, false, true),
114176
provideBooleansProvider(false, false, true),
177+
0,
178+
0,
115179
false,
116180
),
117181
arrayOf(
118182
"route closure between silent and regular waypoints",
119183
"route_closure_between_silent_and_regular_waypoints.json",
120184
provideBooleansProvider(true, true, true),
121185
provideBooleansProvider(true, true, true),
186+
0,
187+
0,
122188
true,
123189
),
124190
arrayOf(
125191
"route closure between two regular waypoints",
126192
"route_closure_between_two_regular_waypoints.json",
127193
provideBooleansProvider(true, true, true),
128194
provideBooleansProvider(true, true, true),
195+
0,
196+
0,
129197
true,
130198
),
131199
)
@@ -158,25 +226,41 @@ class NavigationRouteExTest {
158226
}
159227
}
160228

229+
private fun mockRouteProgress(
230+
navigationRoute: NavigationRoute,
231+
currentLegIndex: Int,
232+
currentLegGeometryIndex: Int,
233+
): RouteProgress = mockk {
234+
every { this@mockk.navigationRoute } returns navigationRoute
235+
every { currentLegProgress } returns mockk {
236+
every { legIndex } returns currentLegIndex
237+
every { geometryIndex } returns currentLegGeometryIndex
238+
}
239+
}
240+
161241
private fun provideBooleansProvider(
162242
vararg bool: Boolean?,
163243
): BooleansProvider = { bool.asList() }
164244
}
165245

166246
@Test
167247
fun testCases() = runBlocking {
168-
val navRoute = mockNavigationRoute(
169-
routeRaw,
170-
snappingIncludeClosures,
171-
snappingIncludeStaticClosures,
248+
val routeProgress = mockRouteProgress(
249+
mockNavigationRoute(
250+
routeRaw,
251+
snappingIncludeClosures,
252+
snappingIncludeStaticClosures,
253+
),
254+
currentLegIndex,
255+
currentGeometryLegIndex,
172256
)
173257

174-
val hasUnexpectedClosures = navRoute.hasUnexpectedClosures()
258+
val hasUnexpectedUpcomingClosures = routeProgress.hasUnexpectedUpcomingClosures()
175259

176-
Assert.assertEquals(
260+
assertEquals(
177261
description,
178-
expectedHasUnexpectedClosures,
179-
hasUnexpectedClosures
262+
expectedHasUnexpectedUpcomingClosures,
263+
hasUnexpectedUpcomingClosures
180264
)
181265
}
182266
}
File renamed without changes.

0 commit comments

Comments
 (0)