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

Add waypoint handling #270

Merged
merged 71 commits into from
Aug 24, 2017
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
92a1d30
Add waypoint handling
Jun 8, 2017
d009fff
more waypoints
Jun 9, 2017
c33b154
Use sections
Jun 9, 2017
c6dabb3
clear map
Jun 11, 2017
2c6524a
remove destination
Jun 13, 2017
382ede6
Updates
Jun 13, 2017
52b867d
remove
Jun 13, 2017
315a681
use name
Jun 16, 2017
cbe2ce1
return waypoint when arriving at each waypoint
Jun 19, 2017
988dfd0
Merge branch 'master' into waypoints
Jun 20, 2017
753814a
update
Jun 20, 2017
275b973
Merge branch 'master' into waypoints
Jul 6, 2017
13b4ad1
update example
Jul 6, 2017
ebfa33f
Merge branch 'master' into waypoints
Jul 25, 2017
204eeff
update
Jul 25, 2017
85684aa
remove arg
Jul 26, 2017
e88e2b1
localize
Jul 26, 2017
d7828aa
remove comma
Jul 27, 2017
9f10ad9
Merge branch 'master' into waypoints
Jul 27, 2017
082c44e
whitespace
Jul 31, 2017
40d58cd
fix
Jul 31, 2017
2c26fe9
whitespace
Jul 31, 2017
6340c58
Merge branch 'master' into waypoints
Jul 31, 2017
f052af0
Style, confirm next
Jul 31, 2017
0ab7e26
move
Jul 31, 2017
3e95e9c
remove unused
Jul 31, 2017
8eb79fa
Merge branch 'master' into waypoints
Aug 3, 2017
ee9df0f
Remove waypoint once done
Aug 4, 2017
bb73e66
Merge branch 'master' into waypoints
Aug 7, 2017
edd881b
add clear button
Aug 7, 2017
b0247d6
Merge branch 'master' into waypoints
Aug 8, 2017
4369010
Make waypoint customizable
Aug 9, 2017
3c568c4
fix
Aug 9, 2017
f0ab02f
Improve names
Aug 9, 2017
0c5ae6f
Add back
Aug 9, 2017
cfa67b6
add back
Aug 9, 2017
7144f59
move around
Aug 9, 2017
087de57
remove
Aug 9, 2017
7b15853
remove
Aug 9, 2017
ba54bd0
Merge branch 'master' into waypoints
Aug 9, 2017
4934ad0
move arrow
Aug 9, 2017
84c3c41
add back
Aug 9, 2017
2f5602f
Merge branch 'master' into waypoints
Aug 10, 2017
8b41be7
Change names
Aug 10, 2017
5907c9a
Add translation
Aug 10, 2017
3f0e8ca
Wow, rename
Aug 10, 2017
deda53a
Update
Aug 10, 2017
20bc71e
increment
Aug 10, 2017
3f8214f
False
Aug 10, 2017
4305493
Add translation, update
Aug 11, 2017
b2562d6
fix
Aug 11, 2017
cb66468
Merge branch 'master' into waypoints
Aug 11, 2017
a1d4cbe
Merge branch 'master' into waypoints
Aug 14, 2017
8e17b03
change api
Aug 14, 2017
771dbca
remove
Aug 14, 2017
5b66ffd
Merge branch 'master' into waypoints
Aug 14, 2017
5ebb998
document
Aug 14, 2017
e177cd2
Consistent
Aug 14, 2017
1ab08d5
Merge branch 'master' into waypoints
Aug 16, 2017
1286a2e
remove annotations
Aug 16, 2017
9b2f21b
Merge branch 'master' into waypoints
Aug 17, 2017
306e55a
Merge branch 'master' into waypoints
Aug 17, 2017
518d535
Merge branch 'master' into waypoints
Aug 21, 2017
8ef4112
Merge branch 'master' into waypoints
Aug 22, 2017
f0dc3d5
Merge branch 'master' into waypoints
Aug 23, 2017
e5eb660
Always update
Aug 23, 2017
b9b3555
Flip
Aug 24, 2017
84a1f34
Update
Aug 24, 2017
de69c03
Make bolder
Aug 24, 2017
5995b2f
darker gray
Aug 24, 2017
26fec4b
Update docs
Aug 24, 2017
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
14 changes: 13 additions & 1 deletion Examples/Swift/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,20 @@
<constraint firstAttribute="trailing" secondItem="Tfo-Ic-OqD" secondAttribute="trailing" constant="16" id="veQ-GA-9Zk"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Mapbox Navigation" id="zxr-0T-HBr"/>
<navigationItem key="navigationItem" title="Mapbox Navigation" id="zxr-0T-HBr">
<barButtonItem key="leftBarButtonItem" style="plain" id="XbQ-fY-lUb">
<button key="customView" hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="6ux-mK-LQF">
<rect key="frame" x="16" y="7" width="83" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Clear map"/>
<connections>
<action selector="clearMapPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="SHt-XT-eUM"/>
</connections>
</button>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="clearMap" destination="6ux-mK-LQF" id="9M7-CK-q1M"/>
<outlet property="longPressHintView" destination="Tfo-Ic-OqD" id="gYu-YW-6FX"/>
<outlet property="mapView" destination="A3N-JT-loC" id="iZS-hq-X5f"/>
<outlet property="simulationButton" destination="iiq-Gf-SKY" id="DHR-zB-Mwv"/>
Expand Down
139 changes: 69 additions & 70 deletions Examples/Swift/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ enum ExampleMode {

class ViewController: UIViewController, MGLMapViewDelegate {

var destination: MGLPointAnnotation?
var waypoints: [Waypoint] = []
var currentRoute: Route? {
didSet {
self.startButton.isEnabled = currentRoute != nil
Expand All @@ -29,15 +29,16 @@ class ViewController: UIViewController, MGLMapViewDelegate {
@IBOutlet weak var simulationButton: UIButton!
@IBOutlet weak var startButton: UIButton!

@IBOutlet weak var clearMap: UIButton!

var exampleMode: ExampleMode?
var nextWaypoint: CLLocationCoordinate2D?

override func viewDidLoad() {
super.viewDidLoad()

automaticallyAdjustsScrollViewInsets = false
mapView.delegate = self

mapView.userTrackingMode = .follow

simulationButton.isSelected = true
Expand All @@ -56,15 +57,27 @@ class ViewController: UIViewController, MGLMapViewDelegate {
return
}

if let destination = destination {
mapView.removeAnnotation(destination)
clearMap.isHidden = false

if let annotation = mapView.annotations?.last, waypoints.count > 2 {
mapView.removeAnnotation(annotation)
}

if waypoints.count > 1 {
waypoints = Array(waypoints.suffix(1))
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: use dropFirst().

}

let coordinates = mapView.convert(sender.location(in: mapView), toCoordinateFrom: mapView)

let annotation = MGLPointAnnotation()
annotation.coordinate = coordinates
mapView.addAnnotation(annotation)

longPressHintView.isHidden = true

destination = MGLPointAnnotation()
destination?.coordinate = mapView.convert(sender.location(in: mapView), toCoordinateFrom: mapView)
mapView.addAnnotation(destination!)
let waypoint = Waypoint(coordinate: coordinates)
waypoint.coordinateAccuracy = -1
waypoints.append(waypoint)

requestRoute()
}
Expand All @@ -86,6 +99,13 @@ class ViewController: UIViewController, MGLMapViewDelegate {
simulationButton.isSelected = !simulationButton.isSelected
}

@IBAction func clearMapPressed(_ sender: Any) {
clearMap.isHidden = true
mapView.removeRoute()
mapView.removeAnnotations(mapView.annotations ?? [])
waypoints.removeAll()
}

@IBAction func startButtonPressed(_ sender: Any) {
let alertController = UIAlertController(title: "Start Navigation", message: "Select the navigation type", preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "Default UI", style: .default, handler: { (action) in
Expand All @@ -97,9 +117,11 @@ class ViewController: UIViewController, MGLMapViewDelegate {
alertController.addAction(UIAlertAction(title: "Styled UI", style: .default, handler: { (action) in
self.startStyledNavigation()
}))
alertController.addAction(UIAlertAction(title: "Multiple Stops", style: .default, handler: { (action) in
self.startMultipleWaypoints()
}))
if self.waypoints.count > 2 {
alertController.addAction(UIAlertAction(title: "Multiple Stops", style: .default, handler: { (action) in
self.startMultipleWaypoints()
}))
}
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
DispatchQueue.main.async {
self.present(alertController, animated: true, completion: nil)
Expand All @@ -108,12 +130,13 @@ class ViewController: UIViewController, MGLMapViewDelegate {

// Helper for requesting a route
func requestRoute() {
guard let destination = destination else { return }
guard waypoints.count > 0 else { return }

let options = RouteOptions(coordinates: [
mapView.userLocation!.coordinate,
destination.coordinate,
])
let userWaypoint = Waypoint(location: mapView.userLocation!.location!, heading: mapView.userLocation?.heading, name: "user")
userWaypoint.coordinateAccuracy = -1
waypoints.insert(userWaypoint, at: 0)

let options = RouteOptions(waypoints: waypoints)
options.includesSteps = true
options.routeShapeResolution = .full
options.profileIdentifier = .automobileAvoidingTraffic
Expand All @@ -123,7 +146,7 @@ class ViewController: UIViewController, MGLMapViewDelegate {

_ = Directions.shared.calculate(options) { [weak self] (waypoints, routes, error) in
guard error == nil else {
print(error!)
print(error!.localizedDescription)
return
}
guard let route = routes?.first else { return }
Expand All @@ -134,12 +157,12 @@ class ViewController: UIViewController, MGLMapViewDelegate {
self?.mapView.showRoute(route)
}
}

// MARK: - Basic Navigation

func startBasicNavigation() {
guard let route = currentRoute else { return }

exampleMode = .default

let navigationViewController = NavigationViewController(for: route, locationManager: locationManager())
Expand All @@ -155,18 +178,17 @@ class ViewController: UIViewController, MGLMapViewDelegate {
guard let route = self.currentRoute else { return }

guard let customViewController = storyboard?.instantiateViewController(withIdentifier: "custom") as? CustomViewController else { return }

exampleMode = .custom

customViewController.simulateLocation = simulationButton.isSelected
customViewController.userRoute = route
customViewController.destination = destination


present(customViewController, animated: true, completion: nil)
}

// MARK: - Styling the default UI

// MARK: - Styling the default UI

func startStyledNavigation() {
guard let route = self.currentRoute else { return }

Expand Down Expand Up @@ -211,7 +233,7 @@ class ViewController: UIViewController, MGLMapViewDelegate {

// Set a custom style URL
navigationViewController.mapView?.styleURL = URL(string: "mapbox://styles/mapbox/navigation-guidance-day-v2")

present(navigationViewController, animated: true, completion: nil)
}

Expand All @@ -226,67 +248,44 @@ class ViewController: UIViewController, MGLMapViewDelegate {
guard let route = self.currentRoute else { return }

exampleMode = .multipleWaypoints

// When the user arrives at their destination, we'll prompt them to return back to where they started
nextWaypoint = self.currentRoute?.coordinates?.first


let navigationViewController = NavigationViewController(for: route, locationManager: locationManager())
navigationViewController.navigationDelegate = self

present(navigationViewController, animated: true, completion: nil)
}

// By default, when the user arrives at a waypoint, the next leg starts immediately.
// If however you would like to pause and allow the user to provide input, set this delegate method to false.
// This does however require you to increment the leg count on your own. See the example below in `confirmationControllerDidConfirm()`.
func navigationViewController(_ navigationViewController: NavigationViewController, shouldIncrementLegWhenArrivingAtWaypoint waypoint: Waypoint) -> Bool {
return false
}
}

extension ViewController: WaypointConfirmationViewControllerDelegate {
func confirmationControllerDidConfirm(_ confirmationController: WaypointConfirmationViewController) {
confirmationController.dismiss(animated: true, completion: {
guard let navigationViewController = self.presentedViewController as? NavigationViewController else { return }

guard navigationViewController.routeController.routeProgress.route.legs.count > navigationViewController.routeController.routeProgress.legIndex + 1 else { return }
navigationViewController.routeController.routeProgress.legIndex += 1
})
}
}

extension ViewController: NavigationViewControllerDelegate {
func navigationViewController(_ navigationViewController: NavigationViewController, didArriveAt destination: MGLAnnotation) {
func navigationViewController(_ navigationViewController: NavigationViewController, didArriveAt waypoint: Waypoint) {

// Multiple waypoint demo
guard exampleMode == .multipleWaypoints, nextWaypoint != nil else { return }
guard exampleMode == .multipleWaypoints else { return }

// When the user arrives, present a view controller that prompts the user to continue to their next destination
// This typ of screen could show information about a destination, pickup/dropoff confirmation, instructions upon arrival, etc.
guard let confirmationController = self.storyboard?.instantiateViewController(withIdentifier: "waypointConfirmation") as? WaypointConfirmationViewController else { return }

confirmationController.delegate = self

navigationViewController.present(confirmationController, animated: true, completion: nil)
}
}

extension ViewController: WaypointConfirmationViewControllerDelegate {
func confirmationControllerDidConfirm(controller confirmationController: WaypointConfirmationViewController) {
guard let nextDestination = nextWaypoint else { return }
guard let navigationViewController = self.presentedViewController as? NavigationViewController else { return }

// Calculate directions to the next waypoint
let options = RouteOptions(coordinates: [
navigationViewController.mapView!.userLocation!.coordinate,
nextDestination,
])
options.includesSteps = true
options.routeShapeResolution = .full
options.profileIdentifier = navigationViewController.route.routeOptions.profileIdentifier

// Adding the optional attribute `.congestionLevel` ensures the route line will show the congestion along the route line
options.attributeOptions = [.congestionLevel]

_ = Directions.shared.calculate(options) { [weak self] (waypoints, routes, error) in
guard error == nil else {
print(error!)
return
}
guard let route = routes?.first else { return }

// update the navigationViewController with the route to the next waypoint
navigationViewController.route = route

// Set the next waypoint to our start point
// We'll continue this waypoint loop until the user exits navigation
self?.nextWaypoint = route.coordinates?.first

// Dismiss the confirmation screen
confirmationController.dismiss(animated: true, completion: nil)
}
}
}
4 changes: 2 additions & 2 deletions Examples/Swift/WaypointConfirmationViewController.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import UIKit

protocol WaypointConfirmationViewControllerDelegate: NSObjectProtocol {
func confirmationControllerDidConfirm(controller: WaypointConfirmationViewController)
func confirmationControllerDidConfirm(_ controller: WaypointConfirmationViewController)
}

class WaypointConfirmationViewController: UIViewController {

weak var delegate: WaypointConfirmationViewControllerDelegate?

@IBAction func continueButtonPressed(_ sender: Any) {
delegate?.confirmationControllerDidConfirm(controller: self)
delegate?.confirmationControllerDidConfirm(self)
}
}
13 changes: 12 additions & 1 deletion MapboxCoreNavigation/RouteController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public protocol RouteControllerDelegate: class {
@objc(routeController:shouldRerouteFromLocation:)
optional func routeController(_ routeController: RouteController, shouldRerouteFrom location: CLLocation) -> Bool

@objc(routeController:shouldIncrementLegWhenArrivingAtWaypoint:)
optional func routeController(_ routeController: RouteController, shouldIncrementLegWhenArrivingAtWaypoint waypoint: Waypoint) -> Bool
Copy link
Contributor

Choose a reason for hiding this comment

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

The Swift name should be routeController(_:shouldIncrementLegWhenArrivingAt:). “Waypoint” is inferred from the argument’s type.


/**
Called immediately before the route controller calculates a new route.

Expand Down Expand Up @@ -414,7 +417,8 @@ extension RouteController: CLLocationManagerDelegate {
let userSnapToStepDistanceFromManeuver = distance(along: routeProgress.currentLegProgress.currentStep.coordinates!, from: location.coordinate)
let secondsToEndOfStep = userSnapToStepDistanceFromManeuver / location.speed

guard routeProgress.currentLegProgress.alertUserLevel != .arrive else {
guard routeProgress.currentLegProgress.alertUserLevel != .arrive,
routeProgress.remainingWaypoints.count > 0 else {
NotificationCenter.default.post(name: RouteControllerProgressDidChange, object: self, userInfo: [
RouteControllerProgressDidChangeNotificationProgressKey: routeProgress,
RouteControllerProgressDidChangeNotificationLocationKey: location,
Expand Down Expand Up @@ -532,6 +536,7 @@ extension RouteController: CLLocationManagerDelegate {

if routeProgress.currentLegProgress.alertUserLevel != newlyCalculatedAlertLevel || updateStepIndex {
routeProgress.currentLegProgress.alertUserLevel = newlyCalculatedAlertLevel

// Use fresh user location distance to end of step
// since the step could of changed
let userDistance = distance(along: routeProgress.currentLegProgress.currentStep.coordinates!, from: location.coordinate)
Expand All @@ -540,6 +545,12 @@ extension RouteController: CLLocationManagerDelegate {
RouteControllerAlertLevelDidChangeNotificationRouteProgressKey: routeProgress,
RouteControllerAlertLevelDidChangeNotificationDistanceToEndOfManeuverKey: userDistance
])

if routeProgress.currentLegProgress.alertUserLevel == .arrive,
routeProgress.remainingWaypoints.count > 1,
(delegate?.routeController?(self, shouldIncrementLegWhenArrivingAtWaypoint: routeProgress.currentLeg.destination) ?? true) {
routeProgress.legIndex += 1
}
}
}

Expand Down
1 change: 1 addition & 0 deletions MapboxCoreNavigation/RouteProgress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ open class RouteProgress: NSObject {
didSet {
assert(legIndex >= 0 && legIndex < route.legs.endIndex)
// TODO: Set stepIndex to 0 or last index based on whether leg index was incremented or decremented.
currentLegProgress.alertUserLevel = .none
currentLegProgress = RouteLegProgress(leg: currentLeg)
}
}
Expand Down
Loading