Skip to content

Commit 6bc02c3

Browse files
authored
Merge pull request #1883 from mapbox/jerrad/nearby-lookaround
Multi-leg nearby coordinate lookups.
2 parents 07973bb + d4b77ee commit 6bc02c3

14 files changed

+94
-42
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
* Fixed an issue where the CarPlay navigation map’s vanishing point and user puck initially remained centered on screen, instead of accounting for the maneuver panel, until the navigation bar was shown. ([#1856](https://github.com/mapbox/mapbox-navigation-ios/pull/1856))
99
* Fixed an issue where route shields and exit numbers appeared blurry in the maneuver panel on CarPlay devices and failed to appear in the CarPlay simulator. ([#1868](https://github.com/mapbox/mapbox-navigation-ios/pull/1868))
1010
* Added `VisualInstruction.containsLaneIndications`, `VisualInstruction.maneuverImageSet(side:)`, `VisualInstruction.shouldFlipImage(side:)`, and `VisualInstruction.carPlayManeuverLabelAttributedText(bounds:shieldHeight:window:)`. ([#1860](https://github.com/mapbox/mapbox-navigation-ios/pull/1860))
11+
* `RouteLegProgress.upComingStep` has been renamed to `upcomingStep`. ([#1860](https://github.com/mapbox/mapbox-navigation-ios/pull/1860))
1112

1213
### Other changes
1314

1415
* The `NavigationSettings.shared` property is now accessible in Objective-C code as `MBNavigationSettings.sharedSettings`. ([#1882](https://github.com/mapbox/mapbox-navigation-ios/pull/1882))
1516
* Fixed spurious rerouting on multi-leg routes. ([#1884](https://github.com/mapbox/mapbox-navigation-ios/pull/1884))
17+
* Adding property `RouteController.nearbyCoordinates`, which offers similar behavior to `RouteLegProgress.nearbyCoordinates`, which the addition of step lookahead/lookbehind in multi-leg routes. ([#1883](https://github.com/mapbox/mapbox-navigation-ios/pull/1883))
1618

1719
## v0.25.0 (November 22, 2018)
1820

MapboxCoreNavigation/CLLocation.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ extension CLLocation {
8686

8787
//MARK: - Route Snapping
8888

89-
func snapped(to legProgress: RouteLegProgress) -> CLLocation? {
90-
let coords = coordinates(for: legProgress)
89+
func snapped(to routeProgress: RouteProgress) -> CLLocation? {
90+
let legProgress = routeProgress.currentLegProgress
91+
let coords = coordinates(for: routeProgress)
9192

9293
guard let closest = Polyline(coords).closestCoordinate(to: coordinate) else { return nil }
9394
guard let calculatedCourseForLocationOnStep = interpolatedCourse(along: coords) else { return nil }
@@ -104,13 +105,14 @@ extension CLLocation {
104105
/**
105106
Calculates the proper coordinates to use when calculating a snapped location.
106107
*/
107-
func coordinates(for legProgress: RouteLegProgress) -> [CLLocationCoordinate2D] {
108-
let nearbyCoordinates = legProgress.nearbyCoordinates
108+
func coordinates(for routeProgress: RouteProgress) -> [CLLocationCoordinate2D] {
109+
let legProgress = routeProgress.currentLegProgress
110+
let nearbyCoordinates = routeProgress.nearbyCoordinates
109111
let stepCoordinates = legProgress.currentStep.coordinates!
110112

111113
// If the upcoming maneuver a sharp turn, only look at the current step for snapping.
112114
// Otherwise, we may get false positives from nearby step coordinates
113-
if let upcomingStep = legProgress.upComingStep,
115+
if let upcomingStep = legProgress.upcomingStep,
114116
let initialHeading = upcomingStep.initialHeading,
115117
let finalHeading = upcomingStep.finalHeading {
116118

MapboxCoreNavigation/EventDetails.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,10 @@ extension RouteLegProgress: Encodable {
271271

272272
public func encode(to encoder: Encoder) throws {
273273
var container = encoder.container(keyedBy: CodingKeys.self)
274-
try container.encodeIfPresent(upComingStep?.instructions, forKey: .upcomingInstruction)
275-
try container.encodeIfPresent(upComingStep?.maneuverType.description, forKey: .upcomingType)
276-
try container.encodeIfPresent(upComingStep?.maneuverDirection.description, forKey: .upcomingModifier)
277-
try container.encodeIfPresent(upComingStep?.names?.joined(separator: ";"), forKey: .upcomingName)
274+
try container.encodeIfPresent(upcomingStep?.instructions, forKey: .upcomingInstruction)
275+
try container.encodeIfPresent(upcomingStep?.maneuverType.description, forKey: .upcomingType)
276+
try container.encodeIfPresent(upcomingStep?.maneuverDirection.description, forKey: .upcomingModifier)
277+
try container.encodeIfPresent(upcomingStep?.names?.joined(separator: ";"), forKey: .upcomingName)
278278
try container.encodeIfPresent(currentStep.instructions, forKey: .previousInstruction)
279279
try container.encode(currentStep.maneuverType.description, forKey: .previousType)
280280
try container.encode(currentStep.maneuverDirection.description, forKey: .previousModifier)

MapboxCoreNavigation/RouteController.swift

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ open class RouteController: NSObject, Router {
156156
- important: If the rawLocation is outside of the route snapping tolerances, this value is nil.
157157
*/
158158
var snappedLocation: CLLocation? {
159-
return rawLocation?.snapped(to: routeProgress.currentLegProgress)
159+
return rawLocation?.snapped(to: routeProgress)
160160
}
161161

162162
var heading: CLHeading?
@@ -221,14 +221,8 @@ open class RouteController: NSObject, Router {
221221
Monitors the user's course to see if it is consistantly moving away from what we expect the course to be at a given point.
222222
*/
223223
func userCourseIsOnRoute(_ location: CLLocation) -> Bool {
224-
// if we have yet to travel along the current leg, don't check for heading conformance
225-
guard routeProgress.currentLegProgress.distanceTraveled > 0 else {
226-
movementsAwayFromRoute = 0
227-
return true
228-
}
229-
230-
let nearByCoordinates = routeProgress.currentLegProgress.nearbyCoordinates
231-
guard let calculatedCourseForLocationOnStep = location.interpolatedCourse(along: nearByCoordinates) else { return true }
224+
let nearbyCoordinates = routeProgress.nearbyCoordinates
225+
guard let calculatedCourseForLocationOnStep = location.interpolatedCourse(along: nearbyCoordinates) else { return true }
232226

233227
let maxUpdatesAwayFromRouteGivenAccuracy = Int(location.horizontalAccuracy / Double(RouteControllerIncorrectCourseMultiplier))
234228

@@ -435,7 +429,7 @@ extension RouteController: CLLocationManagerDelegate {
435429

436430

437431
func checkForFasterRoute(from location: CLLocation) {
438-
guard let currentUpcomingManeuver = routeProgress.currentLegProgress.upComingStep else {
432+
guard let currentUpcomingManeuver = routeProgress.currentLegProgress.upcomingStep else {
439433
return
440434
}
441435

@@ -553,7 +547,7 @@ extension RouteController: CLLocationManagerDelegate {
553547
let currentStepProgress = routeProgress.currentLegProgress.currentStepProgress
554548

555549
// The intersections array does not include the upcoming maneuver intersection.
556-
if let upcomingStep = routeProgress.currentLegProgress.upComingStep, let upcomingIntersection = upcomingStep.intersections, let firstUpcomingIntersection = upcomingIntersection.first {
550+
if let upcomingStep = routeProgress.currentLegProgress.upcomingStep, let upcomingIntersection = upcomingStep.intersections, let firstUpcomingIntersection = upcomingIntersection.first {
557551
intersections += [firstUpcomingIntersection]
558552
}
559553

@@ -577,7 +571,7 @@ extension RouteController: CLLocationManagerDelegate {
577571

578572
// Bearings need to normalized so when the `finalHeading` is 359 and the user heading is 1,
579573
// we count this as within the `RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion`
580-
if let upcomingStep = routeProgress.currentLegProgress.upComingStep, let finalHeading = upcomingStep.finalHeading, let initialHeading = upcomingStep.initialHeading {
574+
if let upcomingStep = routeProgress.currentLegProgress.upcomingStep, let finalHeading = upcomingStep.finalHeading, let initialHeading = upcomingStep.initialHeading {
581575
let initialHeadingNormalized = initialHeading.wrap(min: 0, max: 360)
582576
let finalHeadingNormalized = finalHeading.wrap(min: 0, max: 360)
583577
let userHeadingNormalized = location.course.wrap(min: 0, max: 360)
@@ -596,7 +590,7 @@ extension RouteController: CLLocationManagerDelegate {
596590
}
597591
}
598592

599-
let step = routeProgress.currentLegProgress.upComingStep?.maneuverLocation ?? routeProgress.currentLegProgress.currentStep.maneuverLocation
593+
let step = routeProgress.currentLegProgress.upcomingStep?.maneuverLocation ?? routeProgress.currentLegProgress.currentStep.maneuverLocation
600594
let userAbsoluteDistance = step.distance(to: location.coordinate)
601595
let lastKnownUserAbsoluteDistance = routeProgress.currentLegProgress.currentStepProgress.userDistanceToManeuverLocation
602596

MapboxCoreNavigation/RouteProgress.swift

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,54 @@ open class RouteProgress: NSObject {
9797
Returns the progress along the current `RouteLeg`.
9898
*/
9999
@objc public var currentLegProgress: RouteLegProgress
100+
101+
@objc public var priorLeg: RouteLeg? {
102+
return legIndex > 0 ? route.legs[legIndex - 1] : nil
103+
}
104+
105+
/**
106+
The step prior to the current step along this route.
107+
108+
The prior step may be part of a different RouteLeg than the current step. If the current step is the first step along the route, this property is set to nil.
109+
*/
110+
111+
@objc public var priorStep: RouteStep? {
112+
return currentLegProgress.priorStep ?? priorLeg?.steps.last
113+
}
114+
115+
/**
116+
The leg following the current leg along this route.
117+
118+
If this leg is the last leg of the route, this property is set to nil.
119+
*/
120+
121+
@objc public var upcomingLeg: RouteLeg? {
122+
return legIndex + 1 < route.legs.endIndex ? route.legs[legIndex + 1] : nil
123+
}
124+
125+
/**
126+
The step following the current step along this route.
127+
128+
The upcoming step may be part of a different RouteLeg than the current step. If it is the last step along the route, this property is set to nil.
129+
*/
130+
131+
public var upcomingStep: RouteStep? {
132+
return currentLegProgress.upcomingStep ?? upcomingLeg?.steps.first
133+
}
134+
135+
/**
136+
Returns an array of `CLLocationCoordinate2D` of the coordinates along the current step and any adjacent steps.
137+
138+
- important: The adjacent steps may be part of legs other than the current leg.
139+
*/
100140

141+
@objc public var nearbyCoordinates: [CLLocationCoordinate2D] {
142+
let priorCoordinates = priorStep?.coordinates?.dropLast() ?? []
143+
let currentCoordinates = currentLegProgress.currentStep.coordinates ?? []
144+
let upcomingCoordinates = upcomingStep?.coordinates?.dropFirst() ?? []
145+
return priorCoordinates + currentCoordinates + upcomingCoordinates
146+
}
147+
101148
/**
102149
Tuple containing a `CongestionLevel` and a corresponding `TimeInterval` representing the expected travel time for this segment.
103150
*/
@@ -321,7 +368,12 @@ open class RouteLegProgress: NSObject {
321368

322369
If there is no `upcomingStep`, nil is returned.
323370
*/
371+
@available(*, deprecated, renamed: "upcomingStep")
324372
@objc public var upComingStep: RouteStep? {
373+
return upcomingStep
374+
}
375+
376+
@objc public var upcomingStep: RouteStep? {
325377
guard stepIndex + 1 < leg.steps.endIndex else {
326378
return nil
327379
}
@@ -367,9 +419,11 @@ open class RouteLegProgress: NSObject {
367419
/**
368420
Returns an array of `CLLocationCoordinate2D` of the prior, current and upcoming step geometry.
369421
*/
422+
423+
@available(*, deprecated: 0.1, message: "Use RouteProgress.nearbyCoordinates")
370424
@objc public var nearbyCoordinates: [CLLocationCoordinate2D] {
371425
let priorCoords = priorStep?.coordinates ?? []
372-
let upcomingCoords = upComingStep?.coordinates ?? []
426+
let upcomingCoords = upcomingStep?.coordinates ?? []
373427
let currentCoords = currentStep.coordinates ?? []
374428
let nearby = priorCoords + currentCoords + upcomingCoords
375429
assert(!nearby.isEmpty, "Step must have coordinates")

MapboxCoreNavigationTests/LocationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class LocationTests: XCTestCase {
66

77
var setup: (progress: RouteProgress, firstLocation: CLLocation) {
88
let progress = RouteProgress(route: route)
9-
let firstCoord = progress.currentLegProgress.nearbyCoordinates.first!
9+
let firstCoord = progress.nearbyCoordinates.first!
1010
let firstLocation = CLLocation(latitude: firstCoord.latitude, longitude: firstCoord.longitude)
1111

1212
return (progress, firstLocation)
@@ -47,7 +47,7 @@ class LocationTests: XCTestCase {
4747
let initialHeadingOnFirstStep = progress.currentLegProgress.currentStep.finalHeading!
4848
let coordinateAlongFirstStep = firstLocation.coordinate.coordinate(at: 100, facing: initialHeadingOnFirstStep)
4949
let locationAlongFirstStep = CLLocation(latitude: coordinateAlongFirstStep.latitude, longitude: coordinateAlongFirstStep.longitude)
50-
guard let snapped = locationAlongFirstStep.snapped(to: progress.currentLegProgress) else {
50+
guard let snapped = locationAlongFirstStep.snapped(to: progress) else {
5151
return XCTFail("Location should have snapped to route")
5252
}
5353

MapboxCoreNavigationTests/NavigationServiceTests.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class NavigationServiceTests: XCTestCase {
2626

2727
let legProgress: RouteLegProgress = navigationService.router.routeProgress.currentLegProgress
2828

29-
let firstCoord = legProgress.nearbyCoordinates.first!
29+
let firstCoord = navigationService.router.routeProgress.nearbyCoordinates.first!
3030
let firstLocation = CLLocation(coordinate: firstCoord, altitude: 5, horizontalAccuracy: 10, verticalAccuracy: 5, course: 20, speed: 4, timestamp: Date())
3131

3232
let remainingStepCount = legProgress.remainingSteps.count
@@ -124,7 +124,7 @@ class NavigationServiceTests: XCTestCase {
124124
navigation.locationManager!(navigation.locationManager, didUpdateLocations: [firstLocation])
125125
XCTAssertEqual(navigation.router.location!.coordinate, firstLocation.coordinate, "Check snapped location is working")
126126

127-
let firstCoordinateOnUpcomingStep = navigation.router.routeProgress.currentLegProgress.upComingStep!.coordinates!.first!
127+
let firstCoordinateOnUpcomingStep = navigation.router.routeProgress.currentLegProgress.upcomingStep!.coordinates!.first!
128128
let firstLocationOnNextStepWithNoSpeed = CLLocation(coordinate: firstCoordinateOnUpcomingStep, altitude: 0, horizontalAccuracy: 10, verticalAccuracy: 10, course: 10, speed: 0, timestamp: Date())
129129

130130
navigation.locationManager!(navigation.locationManager, didUpdateLocations: [firstLocationOnNextStepWithNoSpeed])
@@ -144,9 +144,9 @@ class NavigationServiceTests: XCTestCase {
144144
navigation.locationManager!(navigation.locationManager, didUpdateLocations: [firstLocation])
145145
XCTAssertEqual(navigation.router.location!.coordinate, firstLocation.coordinate, "Check snapped location is working")
146146

147-
let firstCoordinateOnUpcomingStep = navigation.router.routeProgress.currentLegProgress.upComingStep!.coordinates!.first!
147+
let firstCoordinateOnUpcomingStep = navigation.router.routeProgress.currentLegProgress.upcomingStep!.coordinates!.first!
148148

149-
let finalHeading = navigation.router.routeProgress.currentLegProgress.upComingStep!.finalHeading!
149+
let finalHeading = navigation.router.routeProgress.currentLegProgress.upcomingStep!.finalHeading!
150150
let firstLocationOnNextStepWithDifferentCourse = CLLocation(coordinate: firstCoordinateOnUpcomingStep, altitude: 0, horizontalAccuracy: 30, verticalAccuracy: 10, course: -finalHeading, speed: 5, timestamp: Date())
151151

152152
navigation.locationManager!(navigation.locationManager, didUpdateLocations: [firstLocationOnNextStepWithDifferentCourse])
@@ -163,7 +163,7 @@ class NavigationServiceTests: XCTestCase {
163163
navigation.locationManager!(navigation.locationManager, didUpdateLocations: [firstLocation])
164164
XCTAssertEqual(navigation.router.location!.coordinate, firstLocation.coordinate, "Check snapped location is working")
165165

166-
let futureCoord = Polyline(navigation.router.routeProgress.currentLegProgress.nearbyCoordinates).coordinateFromStart(distance: 100)!
166+
let futureCoord = Polyline(navigation.router.routeProgress.nearbyCoordinates).coordinateFromStart(distance: 100)!
167167
let futureInaccurateLocation = CLLocation(coordinate: futureCoord, altitude: 0, horizontalAccuracy: 1, verticalAccuracy: 200, course: 0, speed: 5, timestamp: Date())
168168

169169
navigation.locationManager!(navigation.locationManager, didUpdateLocations: [futureInaccurateLocation])
@@ -181,9 +181,9 @@ class NavigationServiceTests: XCTestCase {
181181
route.accessToken = "foo"
182182
let navigation = MapboxNavigationService(route: route, directions: directions)
183183
let router = navigation.router!
184-
let firstCoord = router.routeProgress.currentLegProgress.nearbyCoordinates.first!
184+
let firstCoord = router.routeProgress.nearbyCoordinates.first!
185185
let firstLocation = CLLocation(latitude: firstCoord.latitude, longitude: firstCoord.longitude)
186-
let coordNearStart = Polyline(router.routeProgress.currentLegProgress.nearbyCoordinates).coordinateFromStart(distance: 10)!
186+
let coordNearStart = Polyline(router.routeProgress.nearbyCoordinates).coordinateFromStart(distance: 10)!
187187

188188
navigation.locationManager(navigation.locationManager, didUpdateLocations: [firstLocation])
189189

@@ -196,7 +196,7 @@ class NavigationServiceTests: XCTestCase {
196196

197197
// The course should not be the interpolated course, rather the raw course.
198198
XCTAssertEqual(directionToStart, router.location!.course, "The course should be the raw course and not an interpolated course")
199-
XCTAssertFalse(facingTowardsStartLocation.shouldSnap(toRouteWith: facingTowardsStartLocation.interpolatedCourse(along: router.routeProgress.currentLegProgress.nearbyCoordinates)!, distanceToFirstCoordinateOnLeg: facingTowardsStartLocation.distance(from: firstLocation)), "Should not snap")
199+
XCTAssertFalse(facingTowardsStartLocation.shouldSnap(toRouteWith: facingTowardsStartLocation.interpolatedCourse(along: router.routeProgress.nearbyCoordinates)!, distanceToFirstCoordinateOnLeg: facingTowardsStartLocation.distance(from: firstLocation)), "Should not snap")
200200
}
201201

202202
//TODO: Broken by PortableRoutecontroller & MBNavigator -- needs team discussion.

MapboxCoreNavigationTests/RouteProgressTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class RouteProgressTests: XCTestCase {
2020
XCTAssertEqual(routeProgress.currentLegProgress.fractionTraveled, 0)
2121
XCTAssertEqual(routeProgress.currentLegProgress.stepIndex, 0)
2222
XCTAssertEqual(routeProgress.currentLegProgress.followOnStep?.description, "Turn left onto Gough Street")
23-
XCTAssertEqual(routeProgress.currentLegProgress.upComingStep?.description, "Turn right onto Sacramento Street")
23+
XCTAssertEqual(routeProgress.currentLegProgress.upcomingStep?.description, "Turn right onto Sacramento Street")
2424
}
2525

2626
func testRouteStepProgress() {

MapboxNavigation/CarPlayNavigationViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ public class CarPlayNavigationViewController: UIViewController {
351351
tertiaryManeuver.attributedInstructionVariants = [attributedTertiary]
352352
}
353353

354-
if let upcomingStep = navService.routeProgress.currentLegProgress.upComingStep {
354+
if let upcomingStep = navService.routeProgress.currentLegProgress.upcomingStep {
355355
let distance = distanceFormatter.measurement(of: upcomingStep.distance)
356356
tertiaryManeuver.initialTravelEstimates = CPTravelEstimates(distanceRemaining: distance, timeRemaining: upcomingStep.expectedTravelTime)
357357
}

MapboxNavigation/NavigationMapView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
289289

290290
if UIDevice.current.isPluggedIn {
291291
preferredFramesPerSecond = FrameIntervalOptions.pluggedInFramesPerSecond
292-
} else if let upcomingStep = routeProgress.currentLegProgress.upComingStep,
292+
} else if let upcomingStep = routeProgress.currentLegProgress.upcomingStep,
293293
upcomingStep.maneuverDirection == .straightAhead || upcomingStep.maneuverDirection == .slightLeft || upcomingStep.maneuverDirection == .slightRight {
294294
preferredFramesPerSecond = shouldPositionCourseViewFrameByFrame ? FrameIntervalOptions.defaultFramesPerSecond : minimumFramesPerSecond
295295
} else if durationUntilNextManeuver > FrameIntervalOptions.durationUntilNextManeuver &&

0 commit comments

Comments
 (0)