Skip to content

Commit 04d1452

Browse files
chezzdevUdumft
andauthored
Add shape index parameter to route refresh (#4111)
* Add shape index parameter to route refresh * Pass through leg shape index * Use refresh with current geometry index * pad-geometry-index: Added RouteProgress tests; Code docs appended. * pad-geometry-index: CHANGELOG updated; Podfile.lock committed. * pad-geometry-indexL unit tests compilation fixed * pad-geometry-index: build warning fixed. * Adjust naming * Add more docs Co-authored-by: udumft <[email protected]>
1 parent e185362 commit 04d1452

File tree

10 files changed

+190
-48
lines changed

10 files changed

+190
-48
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
* `NavigationMapView.removeAlternativeRoutes()` and `NavigationMapView.removeContinuousAlternativeRoutesDurations()` were made public to provide a way to remove previously shown alternative routes and alternative routes duration annotations, respectively. ([#4134](https://github.com/mapbox/mapbox-navigation-ios/pull/4134))
2222
* Fixed an issue where tapping on a route duration annotation that overlaps a different route would cause the wrong route to be passed into `NavigationMapViewDelegate.navigationMapView(_:didSelect:)` or `NavigationMapViewDelegate.navigationMapView(_:didSelect:)`. ([#4133](https://github.com/mapbox/mapbox-navigation-ios/pull/4133))
2323

24+
### Routing
25+
26+
* Route refreshing now respects current user progress on a leg to reduce update size and improve updating longer routes. ([#4111](https://github.com/mapbox/mapbox-navigation-ios/pull/4111))
27+
* Added `RoutingProvider.refreshRoute(indexedRouteResponse:fromLegAtIndex:routeShapeIndex:legShapeIndex:completionHandler:)` to request a refresh starting from specified shape index. Updated `RouteLegProgress` and `RouteProgress` initializers to include shape indices, and added `RouteProgress.refreshRoute(with:at:legIndex:legShapeIndex:)` to apply partial route refresh. ([#4111](https://github.com/mapbox/mapbox-navigation-ios/pull/4111))
28+
2429
### Banners and guidance instructions
2530

2631
* Added replacement for `VisualInstruction.maneuverImageSet(side:)` method to generate a maneuver image on iOS 13 and above. ([#4161](https://github.com/mapbox/mapbox-navigation-ios/pull/4161))

Sources/MapboxCoreNavigation/Directions+RoutingProvider.swift

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,24 @@ extension Directions: RoutingProvider {
3131
@discardableResult public func calculateRoutes(options: MatchOptions, completionHandler: @escaping MatchCompletionHandler) -> NavigationProviderRequest? {
3232
return calculate(options, completionHandler: completionHandler)
3333
}
34-
34+
3535
@discardableResult public func refreshRoute(indexedRouteResponse: IndexedRouteResponse, fromLegAtIndex: UInt32, completionHandler: @escaping RouteCompletionHandler) -> NavigationProviderRequest? {
36+
_refreshRoute(indexedRouteResponse: indexedRouteResponse,
37+
fromLegAtIndex: Int(fromLegAtIndex),
38+
currentRouteShapeIndex: nil,
39+
currentLegShapeIndex: nil,
40+
completionHandler: completionHandler)
41+
}
42+
43+
@discardableResult public func refreshRoute(indexedRouteResponse: IndexedRouteResponse, fromLegAtIndex: UInt32, currentRouteShapeIndex: Int, currentLegShapeIndex: Int, completionHandler: @escaping RouteCompletionHandler) -> NavigationProviderRequest? {
44+
_refreshRoute(indexedRouteResponse: indexedRouteResponse,
45+
fromLegAtIndex: Int(fromLegAtIndex),
46+
currentRouteShapeIndex: currentRouteShapeIndex,
47+
currentLegShapeIndex: currentLegShapeIndex,
48+
completionHandler: completionHandler)
49+
}
50+
51+
private func _refreshRoute(indexedRouteResponse: IndexedRouteResponse, fromLegAtIndex startLegIndex: Int, currentRouteShapeIndex: Int?, currentLegShapeIndex: Int?, completionHandler: @escaping RouteCompletionHandler) -> NavigationProviderRequest? {
3652
guard case let .route(routeOptions) = indexedRouteResponse.routeResponse.options else {
3753
preconditionFailure("Invalid route data passed for refreshing. Expected `RouteResponse` containing `.route` `ResponseOptions` but got `.match`.")
3854
}
@@ -46,33 +62,54 @@ extension Directions: RoutingProvider {
4662
}
4763
return nil
4864
}
49-
50-
return refreshRoute(responseIdentifier: responseIdentifier,
51-
routeIndex: indexedRouteResponse.routeIndex,
52-
fromLegAtIndex: Int(fromLegAtIndex),
53-
completionHandler: { credentials, result in
54-
switch result {
55-
case .failure(let error):
56-
DispatchQueue.main.async {
57-
completionHandler(session, .failure(error))
58-
}
59-
case .success(let routeRefreshResponse):
60-
DispatchQueue.global().async {
61-
do {
62-
let routeResponse = try indexedRouteResponse.routeResponse.copy(with: routeOptions)
63-
routeResponse.routes?[indexedRouteResponse.routeIndex].refreshLegAttributes(from: routeRefreshResponse.route)
64-
routeResponse.routes?[indexedRouteResponse.routeIndex].refreshLegIncidents(from: routeRefreshResponse.route)
65-
DispatchQueue.main.async {
66-
completionHandler(session, .success(routeResponse))
67-
}
68-
} catch {
69-
DispatchQueue.main.async {
70-
completionHandler(session, .failure(.unknown(response: nil, underlying: error, code: nil, message: nil)))
71-
}
72-
}
73-
}
74-
}
75-
})
65+
66+
let completionHandler: RouteRefreshCompletionHandler = { credentials, result in
67+
switch result {
68+
case .failure(let error):
69+
DispatchQueue.main.async {
70+
completionHandler(session, .failure(error))
71+
}
72+
case .success(let routeRefreshResponse):
73+
DispatchQueue.global().async {
74+
do {
75+
let routeResponse = try indexedRouteResponse.routeResponse.copy(with: routeOptions)
76+
let route = routeResponse.routes?[indexedRouteResponse.routeIndex]
77+
if let currentLegShapeIndex = currentLegShapeIndex {
78+
route?.refreshLegAttributes(from: routeRefreshResponse.route,
79+
legIndex: startLegIndex,
80+
legShapeIndex: currentLegShapeIndex)
81+
route?.refreshLegIncidents(from: routeRefreshResponse.route,
82+
legIndex: startLegIndex,
83+
legShapeIndex: currentLegShapeIndex)
84+
} else {
85+
route?.refreshLegAttributes(from: routeRefreshResponse.route)
86+
route?.refreshLegIncidents(from: routeRefreshResponse.route)
87+
}
88+
89+
DispatchQueue.main.async {
90+
completionHandler(session, .success(routeResponse))
91+
}
92+
} catch {
93+
DispatchQueue.main.async {
94+
completionHandler(session, .failure(.unknown(response: nil, underlying: error, code: nil, message: nil)))
95+
}
96+
}
97+
}
98+
}
99+
}
100+
101+
if let currentRouteShapeIndex = currentRouteShapeIndex {
102+
return refreshRoute(responseIdentifier: responseIdentifier,
103+
routeIndex: indexedRouteResponse.routeIndex,
104+
fromLegAtIndex: startLegIndex,
105+
currentRouteShapeIndex: currentRouteShapeIndex,
106+
completionHandler: completionHandler)
107+
} else {
108+
return refreshRoute(responseIdentifier: responseIdentifier,
109+
routeIndex: indexedRouteResponse.routeIndex,
110+
fromLegAtIndex: startLegIndex,
111+
completionHandler: completionHandler)
112+
}
76113
}
77114
}
78115

Sources/MapboxCoreNavigation/MapboxRoutingProvider.swift

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,30 @@ public class MapboxRoutingProvider: RoutingProvider {
323323
@discardableResult public func refreshRoute(indexedRouteResponse: IndexedRouteResponse,
324324
fromLegAtIndex startLegIndex: UInt32 = 0,
325325
completionHandler: @escaping Directions.RouteCompletionHandler) -> NavigationProviderRequest? {
326+
_refreshRoute(indexedRouteResponse: indexedRouteResponse,
327+
fromLegAtIndex: startLegIndex,
328+
currentRouteShapeIndex: nil,
329+
currentLegShapeIndex: nil,
330+
completionHandler: completionHandler)
331+
}
332+
333+
@discardableResult public func refreshRoute(indexedRouteResponse: IndexedRouteResponse,
334+
fromLegAtIndex startLegIndex: UInt32,
335+
currentRouteShapeIndex: Int,
336+
currentLegShapeIndex: Int,
337+
completionHandler: @escaping Directions.RouteCompletionHandler) -> NavigationProviderRequest? {
338+
_refreshRoute(indexedRouteResponse: indexedRouteResponse,
339+
fromLegAtIndex: startLegIndex,
340+
currentRouteShapeIndex: currentRouteShapeIndex,
341+
currentLegShapeIndex: currentLegShapeIndex,
342+
completionHandler: completionHandler)
343+
}
344+
345+
private func _refreshRoute(indexedRouteResponse: IndexedRouteResponse,
346+
fromLegAtIndex startLegIndex: UInt32,
347+
currentRouteShapeIndex: Int? = nil,
348+
currentLegShapeIndex: Int? = nil,
349+
completionHandler: @escaping Directions.RouteCompletionHandler) -> NavigationProviderRequest? {
326350
guard case let .route(routeOptions) = indexedRouteResponse.routeResponse.options else {
327351
preconditionFailure("Invalid route data passed for refreshing. Expected `RouteResponse` containing `.route` `ResponseOptions` but got `.match`.")
328352
}
@@ -344,8 +368,8 @@ public class MapboxRoutingProvider: RoutingProvider {
344368
routeIndex: routeIndex,
345369
legIndex: startLegIndex,
346370
routingProfile: routeOptions.profileIdentifier.nativeProfile,
347-
currentRouteGeometryIndex: nil)
348-
371+
currentRouteGeometryIndex: currentRouteShapeIndex.map { NSNumber(value: $0) })
372+
349373
requestId = router.getRouteRefresh(for: refreshOptions, callback: { [weak self] result, _ in
350374
guard let self = self else { return }
351375

@@ -364,8 +388,19 @@ public class MapboxRoutingProvider: RoutingProvider {
364388
DispatchQueue.global().async {
365389
do {
366390
let routeResponse = try indexedRouteResponse.routeResponse.copy(with: routeOptions)
367-
routeResponse.routes?[indexedRouteResponse.routeIndex].refreshLegAttributes(from: routeRefreshResponse.route)
368-
routeResponse.routes?[indexedRouteResponse.routeIndex].refreshLegIncidents(from: routeRefreshResponse.route)
391+
let route = routeResponse.routes?[indexedRouteResponse.routeIndex]
392+
if let currentLegShapeIndex = currentLegShapeIndex {
393+
route?.refreshLegAttributes(from: routeRefreshResponse.route,
394+
legIndex: Int(startLegIndex),
395+
legShapeIndex: currentLegShapeIndex)
396+
route?.refreshLegIncidents(from: routeRefreshResponse.route,
397+
legIndex: Int(startLegIndex),
398+
legShapeIndex: currentLegShapeIndex)
399+
} else {
400+
route?.refreshLegAttributes(from: routeRefreshResponse.route)
401+
route?.refreshLegIncidents(from: routeRefreshResponse.route)
402+
}
403+
369404
DispatchQueue.main.async {
370405
completionHandler(session, .success(routeResponse))
371406
}

Sources/MapboxCoreNavigation/RouteController.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ open class RouteController: NSObject {
389389
with: snappedLocation,
390390
rawLocation: rawLocation,
391391
upcomingRouteAlerts: status.upcomingRouteAlerts,
392-
mapMatchingResult: MapMatchingResult(status: status))
392+
mapMatchingResult: MapMatchingResult(status: status),
393+
routeShapeIndex: Int(status.geometryIndex))
393394

394395
updateIndexes(status: status, progress: routeProgress)
395396
updateRouteLegProgress(status: status)
@@ -520,6 +521,8 @@ open class RouteController: NSObject {
520521
preconditionFailure("Route legs used for navigation must have destinations")
521522
}
522523
let remainingVoiceInstructions = legProgress.currentStepProgress.remainingSpokenInstructions ?? []
524+
525+
legProgress.shapeIndex = Int(status.shapeIndex)
523526

524527
// We are at least at the "You will arrive" instruction
525528
if legProgress.remainingSteps.count <= 2 && remainingVoiceInstructions.count <= 2 {
@@ -543,9 +546,10 @@ open class RouteController: NSObject {
543546
}
544547
}
545548

546-
private func update(progress: RouteProgress, with location: CLLocation, rawLocation: CLLocation, upcomingRouteAlerts routeAlerts: [UpcomingRouteAlert], mapMatchingResult: MapMatchingResult) {
549+
private func update(progress: RouteProgress, with location: CLLocation, rawLocation: CLLocation, upcomingRouteAlerts routeAlerts: [UpcomingRouteAlert], mapMatchingResult: MapMatchingResult, routeShapeIndex: Int) {
547550
progress.updateDistanceTraveled(with: location)
548551
progress.upcomingRouteAlerts = routeAlerts.map { RouteAlert($0) }
552+
progress.shapeIndex = routeShapeIndex
549553

550554
//Fire the delegate method
551555
delegate?.router(self, didUpdate: progress, with: location, rawLocation: rawLocation)

Sources/MapboxCoreNavigation/RouteLegProgress.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,25 @@ open class RouteLegProgress: Codable {
175175
return speedLimit
176176
}
177177
}
178+
179+
/**
180+
Index relative to leg shape, representing the point the user is currently located at.
181+
*/
182+
public internal(set) var shapeIndex: Int
178183

179184
/**
180185
Intializes a new `RouteLegProgress`.
181186

182187
- parameter leg: Leg on a `Route`.
183188
- parameter stepIndex: Current step the user is on.
189+
- parameter shapeIndex: Index relative to leg shape, representing the point the user is currently located at.
184190
*/
185-
public init(leg: RouteLeg, stepIndex: Int = 0, spokenInstructionIndex: Int = 0) {
191+
public init(leg: RouteLeg, stepIndex: Int = 0, spokenInstructionIndex: Int = 0, shapeIndex: Int = 0) {
186192
precondition(leg.steps.indices.contains(stepIndex), "It's not possible to set the stepIndex: \(stepIndex) when it's higher than steps count \(leg.steps.count) or not included.")
187193

188194
self.leg = leg
189195
self.stepIndex = stepIndex
196+
self.shapeIndex = shapeIndex
190197

191198
currentStepProgress = RouteStepProgress(step: leg.steps[stepIndex], spokenInstructionIndex: spokenInstructionIndex)
192199
}
@@ -247,5 +254,6 @@ open class RouteLegProgress: Codable {
247254
case stepIndex
248255
case userHasArrivedAtWaypoint
249256
case currentStepProgress
257+
case shapeIndex
250258
}
251259
}

Sources/MapboxCoreNavigation/RouteProgress.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ open class RouteProgress: Codable {
1515
- parameter route: The route to follow.
1616
- parameter options: The route options that were attached to the route request.
1717
- parameter legIndex: Zero-based index indicating the current leg the user is on.
18+
- parameter routeShapeIndex: Index relative to route shape, representing the point the user is currently located at.
19+
- parameter legShapeIndex: Index relative to leg shape, representing the point the user is currently located at.
1820
*/
19-
public init(route: Route, options: RouteOptions, legIndex: Int = 0, spokenInstructionIndex: Int = 0) {
21+
public init(route: Route, options: RouteOptions, legIndex: Int = 0, spokenInstructionIndex: Int = 0, routeShapeIndex: Int = 0, legShapeIndex: Int = 0) {
2022
self.route = route
2123
self.routeOptions = options
2224
self.legIndex = legIndex
23-
self.currentLegProgress = RouteLegProgress(leg: route.legs[legIndex], stepIndex: 0, spokenInstructionIndex: spokenInstructionIndex)
25+
self.shapeIndex = routeShapeIndex
26+
self.currentLegProgress = RouteLegProgress(leg: route.legs[legIndex], stepIndex: 0, spokenInstructionIndex: spokenInstructionIndex, shapeIndex: legShapeIndex)
2427

2528
self.calculateLegsCongestion()
2629
}
@@ -144,13 +147,28 @@ open class RouteProgress: Codable {
144147
public func refreshRoute(with refreshedRoute: RouteRefreshSource, at location: CLLocation) {
145148
route.refreshLegAttributes(from: refreshedRoute)
146149
route.refreshLegIncidents(from: refreshedRoute)
150+
commonRefreshRoute(at: location)
151+
}
152+
153+
public func refreshRoute(with refreshedRoute: RouteRefreshSource, at location: CLLocation, legIndex: Int, legShapeIndex: Int) {
154+
route.refreshLegAttributes(from: refreshedRoute, legIndex: legIndex, legShapeIndex: legShapeIndex)
155+
route.refreshLegIncidents(from: refreshedRoute, legIndex: legIndex, legShapeIndex: legShapeIndex)
156+
commonRefreshRoute(at: location)
157+
}
158+
159+
private func commonRefreshRoute(at location: CLLocation) {
147160
currentLegProgress = RouteLegProgress(leg: route.legs[legIndex],
148161
stepIndex: currentLegProgress.stepIndex,
149162
spokenInstructionIndex: currentLegProgress.currentStepProgress.spokenInstructionIndex)
150163
calculateLegsCongestion()
151164
updateDistanceTraveled(with: location)
152165
}
153-
166+
167+
/**
168+
Index relative to route shape, representing the point the user is currently located at.
169+
*/
170+
public internal(set) var shapeIndex: Int
171+
154172
/**
155173
Increments the progress according to new location specified.
156174
- parameter location: Updated user location.
@@ -353,6 +371,7 @@ open class RouteProgress: Codable {
353371
case routeOptions
354372
case legIndex
355373
case currentLegProgress
374+
case shapeIndex
356375
}
357376

358377
required public init(from decoder: Decoder) throws {
@@ -363,6 +382,7 @@ open class RouteProgress: Codable {
363382
self.routeOptions = try container.decode(RouteOptions.self, forKey: .routeOptions)
364383
self.legIndex = try container.decode(Int.self, forKey: .legIndex)
365384
self.currentLegProgress = try container.decode(RouteLegProgress.self, forKey: .currentLegProgress)
385+
self.shapeIndex = try container.decode(Int.self, forKey: .shapeIndex)
366386

367387
calculateLegsCongestion()
368388
}
@@ -374,5 +394,6 @@ open class RouteProgress: Codable {
374394
try container.encode(routeOptions, forKey: .routeOptions)
375395
try container.encode(legIndex, forKey: .legIndex)
376396
try container.encode(currentLegProgress, forKey: .currentLegProgress)
397+
try container.encode(shapeIndex, forKey: .shapeIndex)
377398
}
378399
}

0 commit comments

Comments
 (0)