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

Rerouting Issue in iOS SDK #2272

Closed
soheilnikbin opened this issue Nov 17, 2019 · 7 comments
Closed

Rerouting Issue in iOS SDK #2272

soheilnikbin opened this issue Nov 17, 2019 · 7 comments

Comments

@soheilnikbin
Copy link

soheilnikbin commented Nov 17, 2019

Navigation keeps on constantly rerouting after every route progress even though the user device location is on the same route. I thought Mapbox automatically handles rerouting only when the user leaves the current route. After I read this part of the documentation, I thought I needed to handle it manually.

Based on documentation, I used below code to handle rerouting manually but the code is deprecated.

func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool {
        return navigationViewController.routeController.userIsOnRoute(location)
    }

So crash redirects me to this part of Mapbox SDK

@available(*, deprecated, renamed: "navigationService", message: "NavigationViewController no longer directly manages a RouteController. See MapboxNavigationService, which contains a protocol-bound reference to the RouteController, for more information.")
/// :nodoc: obsoleted
@objc public final var routeController: RouteController! {
    get {
        fatalError()
    }
    set {
        fatalError()
    }
}

but navigationService not containing userIsOnRoute function. Is there an alternative function I could use, or is this a bug?

@soheilnikbin
Copy link
Author

soheilnikbin commented Nov 18, 2019

@luugiathuy suggestion to modifying SDK did the trick to stop rerouting but this problem definitely needs to be fixed.

@avi-c
Copy link
Contributor

avi-c commented Nov 18, 2019

@soheilnikbin Do you have a sample project that reproduces the problem that you could share? If you don’t have a whole project, then maybe some of the code you are using?

Finally, can you share a starting/ending coordinate for the original route that is being calculated?

@soheilnikbin
Copy link
Author

soheilnikbin commented Nov 20, 2019

Unfortunately I cannot share the entire project here but I can share the code written for Mapbox navigation as below:

So in this code I'm getting current location of the user to init route and than calling calculateDirections to get Navigation Route.

  func setupSequences() {
      viewDidLoadSubject
          .flatMapLatest { [weak self] _ -> Observable<CLLocation?> in
              guard let `self` = self else { return .create { _ in return Disposables.create()} }
              self.manager.requestWhenInUseAuthorization()
              self.manager.startUpdatingLocation()
              //
              return self.manager.rx
                  .location
                  .takeUntil(.inclusive, predicate: { $0 != nil })
      }
      .filterNil()
      .flatMapLatest { [weak self] location -> Single<Route> in
          guard let `self` = self else { return .create { _ in return Disposables.create()} }
          self.manager.stopUpdatingLocation()
          return self.calculateDirections(currentLocation: location)
      }
      .subscribe(onNext: routeSubject.onNext)
      .disposed(by: disposeBag)
      //
  }
    
  func calculateDirections(currentLocation: CLLocation) -> Single<Route> {
      let origin = Waypoint(coordinate: CLLocationCoordinate2D(latitude: currentLocation.coordinate.latitude,
                                                                 longitude: currentLocation.coordinate.longitude), name: "Origin")
      //
      let destination = Waypoint(coordinate: CLLocationCoordinate2D(latitude: inProgressJob.location.latitude,
                                                                      longitude: inProgressJob.location.longitude), name: "\(inProgressJob.account.name.fullName)'s Location")
      //
      let options = NavigationRouteOptions(waypoints: [origin, destination])
      options.shapeFormat = RouteShapeFormat.polyline
      options.distanceMeasurementSystem = .metric
      //
      return .create { event in
          Directions.shared.calculate(options) { ( _, routes, error) in
              guard let route = routes?.first, error == nil else {
                  event(.error(error._rlmInferWrappedType()))
                      return
              }
              event(.success(route))
          }
          return Disposables.create()
      }
  }

And then here after getting route to create NavigationViewController. I've tested with simulating .always, .never and .onPoorGPS. Result was same.

viewModel.outputs
            .didGetRoute
            .bind { [weak self] route in
                guard let `self` = self else { return }
                //
                let navigationService = MapboxNavigationService(route: route, simulating: .always)
                let options = NavigationOptions(
                        styles: [CustomNightStyle(), CustomDayStyle()],
                        navigationService: navigationService
                )
                
                //
                let navigationViewController = NavigationViewController(
                    for: route,
                    options: options)
                
                NavigationSettings.shared.distanceUnit = .kilometer
                navigationViewController.route.routeOptions.distanceMeasurementSystem = .metric
                navigationViewController.delegate = self
                //
                self.addChild(navigationViewController)
                self.container.addSubview(navigationViewController.view)
                navigationViewController.view.translatesAutoresizingMaskIntoConstraints = false
                //
                NSLayoutConstraint.activate([
                    navigationViewController.view.leadingAnchor.constraint(equalTo: self.container.leadingAnchor, constant: 0),
                    navigationViewController.view.trailingAnchor.constraint(equalTo: self.container.trailingAnchor, constant: 0),
                    navigationViewController.view.topAnchor.constraint(equalTo: self.container.topAnchor, constant: 0),
                    navigationViewController.view.bottomAnchor.constraint(equalTo: self.container.bottomAnchor, constant: 0)
                ])
                self.didMove(toParent: self)
            }
            .disposed(by: disposeBag)

This code tested on this coordinates
Origin | latitude = 3.1554527282714844, longitude = 101.59706281742993
Destination | latitude = 3.1196545760414183, longitude = 101.61728408242021

This informations also might be helpful

 - Mapbox-iOS-SDK (5.5.0)
  - MapboxCoreNavigation (0.38.0):
    - MapboxDirections.swift (~> 0.30.0)
    - MapboxMobileEvents (~> 0.9.5)
    - MapboxNavigationNative (~> 6.2.1)
    - Turf (~> 0.3.0)
  - MapboxDirections.swift (0.30.0):
    - Polyline (~> 4.2)
  - MapboxMobileEvents (0.9.5)
  - MapboxNavigation (0.38.0):
    - Mapbox-iOS-SDK (~> 5.2)
    - MapboxCoreNavigation (= 0.38.0)
    - MapboxSpeech (~> 0.1.0)
    - Solar (~> 2.1)
  - MapboxNavigationNative (6.2.1)
  - MapboxSpeech (0.1.1)

@JThramer
Copy link
Contributor

JThramer commented Nov 20, 2019

@soheilnikbin:

You can access the function you require using navigationService.router.userIsOnRoute(_:), but this is completely necessary, as this is what the SDK does by default:

let willReroute = !userIsOnRoute(location) && delegate?.router?(self, shouldRerouteFrom: location)
?? DefaultBehavior.shouldRerouteFromLocation

@soheilnikbin
Copy link
Author

Great, its working perfectly fine now.

func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool {
        return navigationViewController.navigationService.router.userIsOnRoute(location)
    }

This line of the code should clearly mention in documentation, or by default SDK should use userIsOnRoute to keep track of device location. If I just remove this function everything goes crazy from the voice command to route.

@soheilnikbin
Copy link
Author

Problem is still there

@1ec5
Copy link
Contributor

1ec5 commented Jan 7, 2020

This is a duplicate of #2125. You’re setting options.shapeFormat = RouteShapeFormat.polyline, which is supported when using LegacyRouteController, but RouteController relies on MapboxNavigationNative, which only supports the polyline6 shape format. Leaving shapeFormat set to the default shape format should be a suitable workaround for now. It doesn’t affect the coordinates that you access via Route.coordinates or RouteStep.coordinates.

@1ec5 1ec5 closed this as completed Jan 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants