Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't continual reroute user if standing still, allow user time to get to route start #84

Merged
merged 8 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions MapboxNavigation/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public var RouteControllerHighAlertInterval: TimeInterval = 15
public var RouteControllerManeuverZoneRadius: CLLocationDistance = 40


/*
Maximum number of seconds the user can travel away from the start of the route before rerouting occurs
*/
public var MaxSecondsSpentTravelingAwayFromStartOfRoute: TimeInterval = 3
Copy link
Contributor

Choose a reason for hiding this comment

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

We don’t consider the start of the route at all anymore, do we? #84 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. Maximum time spent moving away from first step



/*
Distance in meters for the minimum length of a step for giving a `medium` alert.
*/
Expand Down
50 changes: 43 additions & 7 deletions MapboxNavigation/RouteController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import MapboxDirections
@objc(MBRouteController)
open class RouteController: NSObject {

var lastUserDistanceToStartOfRoute = Double.infinity

var lastTimeStampSpentMovingAwayFromStart = Date()

/*
Monitor users location along route.

Expand Down Expand Up @@ -87,13 +91,6 @@ extension RouteController: CLLocationManagerDelegate {
return
}

guard userIsOnRoute(location) else {
NotificationCenter.default.post(name: RouteControllerShouldReroute, object: self, userInfo: [
RouteControllerNotificationShouldRerouteKey: location
])
return
}

// Notify observers if the step’s remaining distance has changed.
let currentStepProgress = routeProgress.currentLegProgress.currentStepProgress
let currentStep = currentStepProgress.step
Expand All @@ -110,9 +107,48 @@ extension RouteController: CLLocationManagerDelegate {
}
}

let step = routeProgress.currentLegProgress.currentStepProgress.step
if step.maneuverType == .depart && !userIsOnRoute(location) {

guard let userSnappedDistanceToClosestCoordinate = closestCoordinate(on: step.coordinates!, to: location.coordinate)?.distance else {
return
}

// Give the user x seconds of moving away from the start of the route before rerouting
guard Date().timeIntervalSince(lastTimeStampSpentMovingAwayFromStart) > MaxSecondsSpentTravelingAwayFromStartOfRoute else {
lastUserDistanceToStartOfRoute = userSnappedDistanceToClosestCoordinate
return
}

// Don't check `userIsOnRoute` if the user has not moved
guard userSnappedDistanceToClosestCoordinate != lastUserDistanceToStartOfRoute else {
lastUserDistanceToStartOfRoute = userSnappedDistanceToClosestCoordinate
return
}

if userSnappedDistanceToClosestCoordinate > lastUserDistanceToStartOfRoute {
lastTimeStampSpentMovingAwayFromStart = location.timestamp
}

lastUserDistanceToStartOfRoute = userSnappedDistanceToClosestCoordinate
}

guard userIsOnRoute(location) else {
resetStartCounter()
NotificationCenter.default.post(name: RouteControllerShouldReroute, object: self, userInfo: [
RouteControllerNotificationShouldRerouteKey: location
])
return
}

monitorStepProgress(location)
}

func resetStartCounter() {
lastTimeStampSpentMovingAwayFromStart = Date()
lastUserDistanceToStartOfRoute = Double.infinity
}

public func userIsOnRoute(_ location: CLLocation) -> Bool {
// Find future location of user
let metersInFrontOfUser = location.speed * RouteControllerDeadReckoningTimeInterval
Expand Down
12 changes: 9 additions & 3 deletions MapboxNavigationTests/MapboxNavigationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,22 @@ class MapboxNavigationTests: XCTestCase {
func testShouldReroute() {
let navigation = RouteController(route: route)
navigation.resume()
let reroutePoint = CLLocation(coordinate: CLLocationCoordinate2D(latitude: 38, longitude: -123), altitude: 1, horizontalAccuracy: 1, verticalAccuracy: 1, course: 0, speed: 10, timestamp: Date())

let reroutePoint1 = CLLocation(latitude: 38, longitude: -123)
let reroutePoint2 = CLLocation(latitude: 38, longitude: -124)

self.expectation(forNotification: RouteControllerShouldReroute.rawValue, object: navigation) { (notification) -> Bool in
XCTAssertEqual(notification.userInfo?.count, 1)

let location = notification.userInfo![RouteControllerNotificationShouldRerouteKey] as? CLLocation
return location == reroutePoint
return location == reroutePoint2
}

navigation.locationManager(navigation.locationManager, didUpdateLocations: [reroutePoint])
navigation.locationManager(navigation.locationManager, didUpdateLocations: [reroutePoint1])

_ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
navigation.locationManager(navigation.locationManager, didUpdateLocations: [reroutePoint2])
}

waitForExpectations(timeout: waitForInterval)
}
Expand Down