Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
* Fixed an issue where route line blinks when style is changed during active navigation. ([#3613](https://github.com/mapbox/mapbox-navigation-ios/pull/3613))
* Fixed an issue where route line missing traffic colors after refresh or rerouting. ([#3622](https://github.com/mapbox/mapbox-navigation-ios/pull/3622))
* Fixed an issue when user goes offline and the route line grows back when `NavigationViewController.routeLineTracksTraversal` enabled. When the distance of user location to the route is larger than certain distance threshold, the vanishing effect of route line would stop until the new route line gets generated. ([#3385](https://github.com/mapbox/mapbox-navigation-ios/pull/3385))
* If the user walks away from the route, they may be rerouted onto a route that initially travels in the opposite direction. This is only the case along steps that require walking on foot. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As tail work, we should consider not suppressing the initial “Head north on” instruction after a reroute if it starts out going in the opposite direction.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Will cut ticket now :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ticket is here: #3627.

* Added `RouteControllerNotificationUserInfoKey.headingKey` to the user info dictionary of `Notification.Name.routeControllerWillReroute`, `Notification.Name.routeControllerDidReroute`, and `Notification.Name.routeControllerProgressDidChange` notifications. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620))
* Added a `Router.heading` property that may contain a heading from the location manager. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620))

### Banners and guidance instructions

Expand Down Expand Up @@ -58,6 +61,7 @@
### Camera

* Fixed an issue where on routes with large distances between current location and next manuever camera zoom level was too low. To control navigation camera zoom level use `IntersectionDensity.averageDistanceMultiplier` coefficient. ([#3616](https://github.com/mapbox/mapbox-navigation-ios/pull/3616))
* While the user is walking, the map rotates according to the user’s heading instead of their course. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620))

### Other changes

Expand Down
11 changes: 8 additions & 3 deletions Sources/MapboxCoreNavigation/CoreConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public extension Notification.Name {
/**
Posted when `RouteController` receives a user location update representing movement along the expected route.

The user info dictionary contains the keys `RouteController.NotificationUserInfoKey.routeProgressKey`, `RouteController.NotificationUserInfoKey.locationKey`, and `RouteController.NotificationUserInfoKey.rawLocationKey`.
The user info dictionary contains the keys `RouteController.NotificationUserInfoKey.routeProgressKey`, `RouteController.NotificationUserInfoKey.locationKey`, and `RouteController.NotificationUserInfoKey.rawLocationKey`, and `RouteController.NotificationUserInfoKey.headingKey`.

- seealso: `passiveLocationManagerDidUpdate`
*/
Expand All @@ -174,14 +174,14 @@ public extension Notification.Name {
/**
Posted after the user diverges from the expected route, just before `RouteController` attempts to calculate a new route.

The user info dictionary contains the key `RouteController.NotificationUserInfoKey.locationKey`.
The user info dictionary contains the keys `RouteController.NotificationUserInfoKey.locationKey` and `RouteController.NotificationUserInfoKey.headingKey`.
*/
static let routeControllerWillReroute: Notification.Name = .init(rawValue: "RouteControllerWillReroute")

/**
Posted when `RouteController` obtains a new route in response to the user diverging from a previous route.

The user info dictionary contains the keys `RouteController.NotificationUserInfoKey.locationKey` and `RouteController.NotificationUserInfoKey.isProactiveKey`.
The user info dictionary contains the keys `RouteController.NotificationUserInfoKey.locationKey`, `RouteController.NotificationUserInfoKey.isProactiveKey`, and `RouteController.NotificationUserInfoKey.headingKey`.
*/
static let routeControllerDidReroute: Notification.Name = .init(rawValue: "RouteControllerDidReroute")

Expand Down Expand Up @@ -274,6 +274,11 @@ extension RouteController {
*/
public static let rawLocationKey: NotificationUserInfoKey = .init(rawValue: "rawLocation")

/**
A key in the user info dictionary of a `Notification.Name.routeControllerProgressDidChange` notification. The corresponding value is a `CLHeading` object representing the current user heading.
*/
public static let headingKey: NotificationUserInfoKey = .init(rawValue: "heading")

/**
A key in the user info dictionary of a `Notification.Name.currentRoadNameDidChange` notification. The corresponding value is a `NSString` object representing the current road name.
*/
Expand Down
2 changes: 1 addition & 1 deletion Sources/MapboxCoreNavigation/LegacyRouteController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa
return rawLocation?.snapped(to: routeProgress)
}

var heading: CLHeading?
public var heading: CLHeading?

/**
The most recently received user location.
Expand Down
23 changes: 17 additions & 6 deletions Sources/MapboxCoreNavigation/RouteController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ open class RouteController: NSObject {
*/
public weak var delegate: RouterDelegate?

var heading: CLHeading?
/**
The route controller’s heading.
*/
public var heading: CLHeading?
var isFirstLocation: Bool = true

/**
Expand Down Expand Up @@ -220,6 +223,10 @@ open class RouteController: NSObject {
}
}

public func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
heading = newHeading
}

/**
Asynchronously updates NavNative navigator with the new `RouteProgress`.

Expand Down Expand Up @@ -464,11 +471,15 @@ open class RouteController: NSObject {
delegate?.router(self, didUpdate: progress, with: location, rawLocation: rawLocation)

//Fire the notification (for now)
NotificationCenter.default.post(name: .routeControllerProgressDidChange, object: self, userInfo: [
NotificationUserInfoKey.routeProgressKey: progress,
NotificationUserInfoKey.locationKey: location, //guaranteed value
NotificationUserInfoKey.rawLocationKey: rawLocation, //raw
])

var userInfo: [RouteController.NotificationUserInfoKey: Any] = [
.routeProgressKey: progress,
.locationKey: location, // guaranteed value
.rawLocationKey: rawLocation, // raw
]
userInfo[.headingKey] = heading

NotificationCenter.default.post(name: .routeControllerProgressDidChange, object: self, userInfo: userInfo)
}

private func announcePassage(of spokenInstructionPoint: SpokenInstruction, routeProgress: RouteProgress) {
Expand Down
10 changes: 6 additions & 4 deletions Sources/MapboxCoreNavigation/RouteProgress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ open class RouteProgress: Codable {
self.calculateLegsCongestion()
}

func reroutingOptions(with current: CLLocation) -> RouteOptions {
func reroutingOptions(from location: CLLocation) -> RouteOptions {
let oldOptions = routeOptions
let user = Waypoint(coordinate: current.coordinate)
let user = Waypoint(coordinate: location.coordinate)

if (current.course >= 0) {
user.heading = current.course
// A pedestrian can turn on a dime; there's no problem with a route that starts out by turning the pedestrian around.
let transportType = currentLegProgress.currentStep.transportType
if transportType != .walking && location.course >= 0 {
user.heading = location.course
user.headingAccuracy = RouteProgress.reroutingAccuracy
}
let newWaypoints = [user] + remainingWaypointsForCalculatingRoute()
Expand Down
22 changes: 15 additions & 7 deletions Sources/MapboxCoreNavigation/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public protocol Router: CLLocationManagerDelegate {
*/
var rawLocation: CLLocation? { get }

/**
The most recently received user heading, if any.
*/
var heading: CLHeading? { get }

/**
If true, the `RouteController` attempts to calculate a more optimal route for the user on an interval defined by `RouteControllerProactiveReroutingInterval`. If `refreshesRoute` is enabled too, reroute attempt will be fired after route refreshing.
*/
Expand Down Expand Up @@ -329,7 +334,7 @@ extension InternalRouter where Self: Router {
*/
func calculateRoutes(from origin: CLLocation, along progress: RouteProgress, completion: @escaping IndexedRouteCompletionHandler) {
routeTask?.cancel()
let options = progress.reroutingOptions(with: origin)
let options = progress.reroutingOptions(from: origin)

lastRerouteLocation = origin

Expand All @@ -350,16 +355,19 @@ extension InternalRouter where Self: Router {

func announceImpendingReroute(at location: CLLocation) {
delegate?.router(self, willRerouteFrom: location)
NotificationCenter.default.post(name: .routeControllerWillReroute, object: self, userInfo: [
RouteController.NotificationUserInfoKey.locationKey: location,
])

var userInfo: [RouteController.NotificationUserInfoKey: Any] = [
.locationKey: location,
]
userInfo[.headingKey] = heading

NotificationCenter.default.post(name: .routeControllerWillReroute, object: self, userInfo: userInfo)
}

func announce(reroute newRoute: Route, at location: CLLocation?, proactive: Bool) {
var userInfo = [RouteController.NotificationUserInfoKey: Any]()
if let location = location {
userInfo[.locationKey] = location
}
userInfo[.locationKey] = location
userInfo[.headingKey] = heading
userInfo[.isProactiveKey] = proactive
NotificationCenter.default.post(name: .routeControllerDidReroute, object: self, userInfo: userInfo)
delegate?.router(self, didRerouteAlong: routeProgress.route, at: location, proactive: proactive)
Expand Down
1 change: 1 addition & 0 deletions Sources/MapboxNavigation/NavigationMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ open class NavigationMapView: UIView {
}

let cameraOptions = CameraOptions(cameraState: mapView.cameraState)

userCourseView.update(location: location,
pitch: cameraOptions.pitch!,
direction: cameraOptions.bearing!,
Expand Down
32 changes: 30 additions & 2 deletions Sources/MapboxNavigation/NavigationViewportDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public class NavigationViewportDataSource: ViewportDataSource {

var viewportDataSourceType: ViewportDataSourceType = .passive

var heading: CLHeading?

// MARK: Initializer Methods

/**
Expand Down Expand Up @@ -113,6 +115,8 @@ public class NavigationViewportDataSource: ViewportDataSource {
let passiveLocation = notification.userInfo?[PassiveLocationManager.NotificationUserInfoKey.locationKey] as? CLLocation
let activeLocation = notification.userInfo?[RouteController.NotificationUserInfoKey.locationKey] as? CLLocation
let routeProgress = notification.userInfo?[RouteController.NotificationUserInfoKey.routeProgressKey] as? RouteProgress
heading = notification.userInfo?[RouteController.NotificationUserInfoKey.headingKey] as? CLHeading

let cameraOptions = self.cameraOptions(passiveLocation: passiveLocation,
activeLocation: activeLocation,
routeProgress: routeProgress)
Expand Down Expand Up @@ -287,7 +291,19 @@ public class NavigationViewportDataSource: ViewportDataSource {

bearing = self.bearing(location.course, coordinatesToManeuver: coordinatesForIntersections)

followingMobileCamera.bearing = bearing
var headingDirection: CLLocationDirection?
let isWalking = routeProgress.currentLegProgress.currentStep.transportType == .walking
if isWalking {
if let trueHeading = heading?.trueHeading, trueHeading >= 0 {
headingDirection = trueHeading
} else if let magneticHeading = heading?.magneticHeading, magneticHeading >= 0 {
headingDirection = magneticHeading
} else {
headingDirection = bearing
}
}

followingMobileCamera.bearing = !isWalking ? bearing : headingDirection
followingCarPlayCamera.bearing = bearing
}

Expand Down Expand Up @@ -380,7 +396,19 @@ public class NavigationViewportDataSource: ViewportDataSource {
// of bearing will be also ignored.
let bearing = 0.0

overviewMobileCamera.bearing = bearing
var headingDirection: CLLocationDirection?
let isWalking = routeProgress.currentLegProgress.currentStep.transportType == .walking
if isWalking {
if let trueHeading = heading?.trueHeading, trueHeading >= 0 {
headingDirection = trueHeading
} else if let magneticHeading = heading?.magneticHeading, magneticHeading >= 0 {
headingDirection = magneticHeading
} else {
headingDirection = bearing
}
}

overviewMobileCamera.bearing = !isWalking ? bearing : headingDirection
overviewCarPlayCamera.bearing = bearing
}

Expand Down