diff --git a/Cartfile b/Cartfile index 1adbd0c686e..8da34ca97f2 100644 --- a/Cartfile +++ b/Cartfile @@ -1,6 +1,6 @@ binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" ~> 5.2 binary "https://www.mapbox.com/ios-sdk/MapboxNavigationNative.json" ~> 6.2.1 -github "mapbox/MapboxDirections.swift" ~> 0.30.0 +github "mapbox/MapboxDirections.swift" "jerrad/objc-delenda-est" #~> 0.30.0 github "mapbox/turf-swift" ~> 0.3 github "mapbox/mapbox-events-ios" ~> 0.9.5 github "ceeK/Solar" ~> 2.1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index fee82c1017c..66e538eda6e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -5,7 +5,7 @@ github "CedarBDD/Cedar" "v1.0" github "Quick/Nimble" "v8.0.4" github "Quick/Quick" "v2.2.0" github "ceeK/Solar" "2.1.0" -github "mapbox/MapboxDirections.swift" "v0.30.0" +github "mapbox/MapboxDirections.swift" "a0a01d7f6a1459c1253ba2bbf48ebfbe192b129c" github "mapbox/MapboxGeocoder.swift" "v0.10.2" github "mapbox/mapbox-events-ios" "v0.9.5" github "mapbox/mapbox-speech-swift" "v0.1.1" diff --git a/MapboxCoreNavigation/CLLocation.swift b/MapboxCoreNavigation/CLLocation.swift index 5d6a3f6e8f3..dfd88dfe49c 100644 --- a/MapboxCoreNavigation/CLLocation.swift +++ b/MapboxCoreNavigation/CLLocation.swift @@ -40,7 +40,7 @@ extension CLLocation { Returns a Boolean value indicating whether the receiver is within a given distance of a route step. */ func isWithin(_ maximumDistance: CLLocationDistance, of routeStep: RouteStep) -> Bool { - guard let closestCoordinate = Polyline(routeStep.coordinates!).closestCoordinate(to: coordinate) else { + guard let coords = routeStep.shape?.coordinates, let closestCoordinate = Polyline(coords).closestCoordinate(to: coordinate) else { return false } return closestCoordinate.distance < maximumDistance @@ -57,7 +57,7 @@ extension CLLocation { let userCourse = calculatedCourseForLocationOnStep let userCoordinate = closest.coordinate - guard let firstCoordinate = legProgress.leg.steps.first?.coordinates?.first else { return nil } + guard let firstCoordinate = legProgress.leg.steps.first?.shape?.coordinates.first else { return nil } guard shouldSnap(toRouteWith: calculatedCourseForLocationOnStep, distanceToFirstCoordinateOnLeg: self.coordinate.distance(to: firstCoordinate)) else { return nil } @@ -70,7 +70,7 @@ extension CLLocation { func coordinates(for routeProgress: RouteProgress) -> [CLLocationCoordinate2D] { let legProgress = routeProgress.currentLegProgress let nearbyCoordinates = routeProgress.nearbyCoordinates - let stepCoordinates = legProgress.currentStep.coordinates! + let stepCoordinates = legProgress.currentStep.shape!.coordinates // If the upcoming maneuver a sharp turn, only look at the current step for snapping. // Otherwise, we may get false positives from nearby step coordinates diff --git a/MapboxCoreNavigation/CoreFeedbackEvent.swift b/MapboxCoreNavigation/CoreFeedbackEvent.swift index 17d6e2143d0..acd90ba15b6 100644 --- a/MapboxCoreNavigation/CoreFeedbackEvent.swift +++ b/MapboxCoreNavigation/CoreFeedbackEvent.swift @@ -33,7 +33,7 @@ class FeedbackEvent: CoreFeedbackEvent { class RerouteEvent: CoreFeedbackEvent { func update(newRoute: Route) { - if let geometry = newRoute.coordinates { + if let geometry = newRoute.shape?.coordinates { eventDictionary["newGeometry"] = Polyline(coordinates: geometry).encodedPolyline eventDictionary["newDistanceRemaining"] = round(newRoute.distance) eventDictionary["newDurationRemaining"] = round(newRoute.expectedTravelTime) diff --git a/MapboxCoreNavigation/EventDetails.swift b/MapboxCoreNavigation/EventDetails.swift index d5c16e4ec8c..3bc8ec0d134 100644 --- a/MapboxCoreNavigation/EventDetails.swift +++ b/MapboxCoreNavigation/EventDetails.swift @@ -120,14 +120,14 @@ struct NavigationEventDetails: EventDetails { requestIdentifier = dataSource.routeProgress.route.routeIdentifier if let location = dataSource.router.rawLocation, - let coordinates = dataSource.routeProgress.route.coordinates, + let coordinates = dataSource.routeProgress.route.shape?.coordinates, let lastCoord = coordinates.last { userAbsoluteDistanceToDestination = location.distance(from: CLLocation(latitude: lastCoord.latitude, longitude: lastCoord.longitude)) } else { userAbsoluteDistanceToDestination = nil } - if let geometry = session.originalRoute.coordinates { + if let geometry = session.originalRoute.shape?.coordinates { originalGeometry = Polyline(coordinates: geometry) originalDistance = round(session.originalRoute.distance) originalEstimatedDuration = round(session.originalRoute.expectedTravelTime) @@ -139,7 +139,7 @@ struct NavigationEventDetails: EventDetails { originalStepCount = nil } - if let geometry = session.currentRoute.coordinates { + if let geometry = session.currentRoute.shape?.coordinates { self.geometry = Polyline(coordinates: geometry) distance = round(session.currentRoute.distance) estimatedDuration = round(session.currentRoute.expectedTravelTime) @@ -314,12 +314,12 @@ extension RouteLegProgress: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(upcomingStep?.instructions, forKey: .upcomingInstruction) - try container.encodeIfPresent(upcomingStep?.maneuverType.description, forKey: .upcomingType) - try container.encodeIfPresent(upcomingStep?.maneuverDirection.description, forKey: .upcomingModifier) + try container.encodeIfPresent(upcomingStep?.maneuverType, forKey: .upcomingType) + try container.encodeIfPresent(upcomingStep?.maneuverDirection, forKey: .upcomingModifier) try container.encodeIfPresent(upcomingStep?.names?.joined(separator: ";"), forKey: .upcomingName) try container.encodeIfPresent(currentStep.instructions, forKey: .previousInstruction) - try container.encode(currentStep.maneuverType.description, forKey: .previousType) - try container.encode(currentStep.maneuverDirection.description, forKey: .previousModifier) + try container.encode(currentStep.maneuverType, forKey: .previousType) + try container.encode(currentStep.maneuverDirection, forKey: .previousModifier) try container.encode(currentStep.names?.joined(separator: ";"), forKey: .previousName) try container.encode(Int(currentStep.distance), forKey: .distance) try container.encode(Int(currentStep.expectedTravelTime), forKey: .duration) diff --git a/MapboxCoreNavigation/LegacyRouteController.swift b/MapboxCoreNavigation/LegacyRouteController.swift index 851b0ae91f1..1754228094a 100644 --- a/MapboxCoreNavigation/LegacyRouteController.swift +++ b/MapboxCoreNavigation/LegacyRouteController.swift @@ -133,7 +133,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa } func updateDistanceToManeuver() { - guard let coordinates = routeProgress.currentLegProgress.currentStep.coordinates, let coordinate = rawLocation?.coordinate else { + guard let coordinates = routeProgress.currentLegProgress.currentStep.shape?.coordinates, let coordinate = rawLocation?.coordinate else { userSnapToStepDistanceFromManeuver = nil return } @@ -175,9 +175,13 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa } public func userIsOnRoute(_ location: CLLocation) -> Bool { + + guard let destination = routeProgress.currentLeg.destination else { + return true + } // If the user has arrived, do not continue monitor reroutes, step progress, etc if routeProgress.currentLegProgress.userHasArrivedAtWaypoint && - (delegate?.router(self, shouldPreventReroutesWhenArrivingAt: routeProgress.currentLeg.destination) ?? + (delegate?.router(self, shouldPreventReroutesWhenArrivingAt: destination) ?? RouteController.DefaultBehavior.shouldPreventReroutesWhenArrivingAtWaypoint) { return true } @@ -280,7 +284,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa let step = stepProgress.step //Increment the progress model - let polyline = Polyline(step.coordinates!) + let polyline = Polyline(step.shape!.coordinates) if let closestCoordinate = polyline.closestCoordinate(to: rawLocation.coordinate) { let remainingDistance = polyline.distance(from: closestCoordinate.coordinate) let distanceTraveled = step.distance - remainingDistance @@ -305,9 +309,11 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa } func updateRouteLegProgress(for location: CLLocation) { - let currentDestination = routeProgress.currentLeg.destination + let legProgress = routeProgress.currentLegProgress - guard let remainingVoiceInstructions = legProgress.currentStepProgress.remainingSpokenInstructions else { return } + guard let currentDestination = legProgress.leg.destination, let remainingVoiceInstructions = legProgress.currentStepProgress.remainingSpokenInstructions else { + return + } // We are at least at the "You will arrive" instruction if legProgress.remainingSteps.count <= 1 && remainingVoiceInstructions.count <= 1 && currentDestination != previousArrivalWaypoint { @@ -408,7 +414,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa routeProgress.currentLegProgress.currentStepProgress.intersectionsIncludingUpcomingManeuverIntersection = intersections if let upcomingIntersection = routeProgress.currentLegProgress.currentStepProgress.upcomingIntersection { - routeProgress.currentLegProgress.currentStepProgress.userDistanceToUpcomingIntersection = Polyline(currentStepProgress.step.coordinates!).distance(from: location.coordinate, to: upcomingIntersection.location) + routeProgress.currentLegProgress.currentStepProgress.userDistanceToUpcomingIntersection = Polyline(currentStepProgress.step.shape!.coordinates).distance(from: location.coordinate, to: upcomingIntersection.location) } if routeProgress.currentLegProgress.currentStepProgress.intersectionDistances == nil { @@ -508,7 +514,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa } func updateIntersectionDistances() { - if let coordinates = routeProgress.currentLegProgress.currentStep.coordinates, let intersections = routeProgress.currentLegProgress.currentStep.intersections { + if let coordinates = routeProgress.currentLegProgress.currentStep.shape?.coordinates, let intersections = routeProgress.currentLegProgress.currentStep.intersections { let polyline = Polyline(coordinates) let distances: [CLLocationDistance] = intersections.map { polyline.distance(from: coordinates.first, to: $0.location) } routeProgress.currentLegProgress.currentStepProgress.intersectionDistances = distances diff --git a/MapboxCoreNavigation/NavigationService.swift b/MapboxCoreNavigation/NavigationService.swift index 23623f6770b..308c92ece21 100644 --- a/MapboxCoreNavigation/NavigationService.swift +++ b/MapboxCoreNavigation/NavigationService.swift @@ -305,7 +305,7 @@ public class MapboxNavigationService: NSObject, NavigationService { // Jump to the first coordinate on the route if the location source does // not yet have a fixed location. if router.location == nil, - let coordinate = route.coordinates?.first { + let coordinate = route.shape?.coordinates.first { let location = CLLocation(coordinate: coordinate, altitude: -1, horizontalAccuracy: -1, verticalAccuracy: -1, course: -1, speed: 0, timestamp: Date()) router.locationManager?(nativeLocationSource, didUpdateLocations: [location]) } diff --git a/MapboxCoreNavigation/OfflineDirections.swift b/MapboxCoreNavigation/OfflineDirections.swift index 8dc30a2f8fb..d7740afe3d0 100644 --- a/MapboxCoreNavigation/OfflineDirections.swift +++ b/MapboxCoreNavigation/OfflineDirections.swift @@ -7,10 +7,18 @@ import MapboxNavigationNative */ public typealias NavigationDirectionsCompletionHandler = (_ numberOfTiles: UInt64) -> Void -enum OfflineRoutingError: Error, LocalizedError { +public enum OfflineRoutingError: DirectionsError, LocalizedError { + public typealias RawValue = String + + var failureReason: String { + #warning("unimplemented") + return "Unimplemented" + } + case unexpectedRouteResult(String) case corruptRouteData(String) case responseError(String) + case unknown(underlying: Error) public var localizedDescription: String { switch self { @@ -20,12 +28,10 @@ enum OfflineRoutingError: Error, LocalizedError { return value case .responseError(let value): return value + case .unknown(let underlying): + return "Unknown Error: \(underlying.localizedDescription)" } } - - var errorDescription: String? { - return localizedDescription - } } struct NavigationDirectionsConstants { @@ -51,6 +57,19 @@ public typealias UnpackProgressHandler = (_ totalBytes: UInt64, _ remainingBytes */ public typealias UnpackCompletionHandler = (_ numberOfTiles: UInt64, _ error: Error?) -> () +/** + A closure (block) to be called when a directions request is complete. + + - parameter waypoints: An array of `Waypoint` objects. Each waypoint object corresponds to a `Waypoint` object in the original `RouteOptions` object. The locations and names of these waypoints are the result of conflating the original waypoints to known roads. The waypoints may include additional information that was not specified in the original waypoints. + + If the request was canceled or there was an error obtaining the routes, this argument may be `nil`. + - parameter routes: An array of `Route` objects. The preferred route is first; any alternative routes come next if the `RouteOptions` object’s `includesAlternativeRoutes` property was set to `true`. The preferred route depends on the route options object’s `profileIdentifier` property. + + If the request was canceled or there was an error obtaining the routes, this argument is `nil`. This is not to be confused with the situation in which no results were found, in which case the array is present but empty. + - parameter error: The error that occurred, or `nil` if the placemarks were obtained successfully. + */ +public typealias OfflineRouteCompletionHandler = ([MapboxDirections.Waypoint]?, [MapboxDirections.Route]?, OfflineRoutingError?) -> Void + /** A `NavigationDirections` object provides you with optimal directions between different locations, or waypoints. The directions object passes your request to a built-in routing engine and returns the requested information to a closure (block) that you provide. A directions object can handle multiple simultaneous requests. A `RouteOptions` object specifies criteria for the results, such as intermediate waypoints, a mode of transportation, or the level of detail to be returned. In addition to `Directions`, `NavigationDirections` provides support for offline routing. @@ -134,6 +153,9 @@ public class NavigationDirections: Directions { - parameter completionHandler: The closure (block) to call with the resulting routes. This closure is executed on the application’s main thread. */ public func calculate(_ options: RouteOptions, offline: Bool = true, completionHandler: @escaping Directions.RouteCompletionHandler) { + + let complete = completionHandler as OfflineRouteCompletionHandler + guard offline == true else { super.calculate(options, completionHandler: completionHandler) return @@ -145,13 +167,13 @@ public class NavigationDirections: Directions { guard let result = self?.navigator.getRouteForDirectionsUri(url.absoluteString) else { let message = NSLocalizedString("OFFLINE_NO_RESULT", bundle: .mapboxCoreNavigation, value: "Unable to calculate the requested route while offline.", comment: "Error description when an offline route request returns no result") let error = OfflineRoutingError.unexpectedRouteResult(message) - return completionHandler(nil, nil, error as NSError) + return complete(nil, nil, error) } guard let data = result.json.data(using: .utf8) else { let message = NSLocalizedString("OFFLINE_CORRUPT_DATA", bundle: .mapboxCoreNavigation, value: "Found an invalid route while offline.", comment: "Error message when an offline route request returns a response that can’t be deserialized") let error = OfflineRoutingError.corruptRouteData(message) - return completionHandler(nil, nil, error as NSError) + return complete(nil, nil, error) } do { @@ -159,17 +181,17 @@ public class NavigationDirections: Directions { if let errorValue = json["error"] as? String { DispatchQueue.main.async { let error = OfflineRoutingError.responseError(errorValue) - return completionHandler(nil, nil, error as NSError) + return complete(nil, nil, error) } } else { DispatchQueue.main.async { let response = options.response(from: json) - return completionHandler(response.0, response.1, nil) + return complete(response.0, response.1, nil) } } } catch { DispatchQueue.main.async { - return completionHandler(nil, nil, error as NSError) + return complete(nil, nil, .unknown(underlying: error)) } } } diff --git a/MapboxCoreNavigation/RouteController.swift b/MapboxCoreNavigation/RouteController.swift index 38eccadd06e..4fcc6378256 100644 --- a/MapboxCoreNavigation/RouteController.swift +++ b/MapboxCoreNavigation/RouteController.swift @@ -258,8 +258,9 @@ open class RouteController: NSObject { func updateRouteLegProgress(status: MBNavigationStatus) { let legProgress = routeProgress.currentLegProgress - let currentDestination = routeProgress.currentLeg.destination - guard let remainingVoiceInstructions = legProgress.currentStepProgress.remainingSpokenInstructions else { return } + + guard let currentDestination = legProgress.leg.destination, let remainingVoiceInstructions = legProgress.currentStepProgress.remainingSpokenInstructions else { return + } // We are at least at the "You will arrive" instruction if legProgress.remainingSteps.count <= 2 && remainingVoiceInstructions.count <= 2 { @@ -287,7 +288,7 @@ open class RouteController: NSObject { let step = stepProgress.step //Increment the progress model - let polyline = Polyline(step.coordinates!) + let polyline = Polyline(step.shape!.coordinates) if let closestCoordinate = polyline.closestCoordinate(to: rawLocation.coordinate) { let remainingDistance = polyline.distance(from: closestCoordinate.coordinate) let distanceTraveled = step.distance - remainingDistance @@ -355,9 +356,14 @@ open class RouteController: NSObject { extension RouteController: Router { public func userIsOnRoute(_ location: CLLocation) -> Bool { + + guard let destination = routeProgress.currentLeg.destination else { + return true + } + // If the user has arrived, do not continue monitor reroutes, step progress, etc if routeProgress.currentLegProgress.userHasArrivedAtWaypoint && - (delegate?.router(self, shouldPreventReroutesWhenArrivingAt: routeProgress.currentLeg.destination) ?? + (delegate?.router(self, shouldPreventReroutesWhenArrivingAt: destination) ?? DefaultBehavior.shouldPreventReroutesWhenArrivingAtWaypoint) { return true } diff --git a/MapboxCoreNavigation/RouteLeg.swift b/MapboxCoreNavigation/RouteLeg.swift index a09c89606ef..5d1340bcd5e 100644 --- a/MapboxCoreNavigation/RouteLeg.swift +++ b/MapboxCoreNavigation/RouteLeg.swift @@ -3,6 +3,6 @@ import Turf extension RouteLeg { var coordinates: [CLLocationCoordinate2D] { - return (steps.first?.coordinates ?? []) + steps.dropFirst().flatMap { ($0.coordinates ?? []).dropFirst() } + return (steps.first?.shape?.coordinates ?? []) + steps.dropFirst().flatMap { ($0.shape?.coordinates ?? []).dropFirst() } } } diff --git a/MapboxCoreNavigation/RouteOptions.swift b/MapboxCoreNavigation/RouteOptions.swift index 6daad5c8401..0a5ccdb18a5 100644 --- a/MapboxCoreNavigation/RouteOptions.swift +++ b/MapboxCoreNavigation/RouteOptions.swift @@ -24,6 +24,11 @@ extension RouteOptions { return copy } +// init(options: RouteOptions) { +// +// } + + /** Returns a tuple containing the waypoints along the leg at the given index and the waypoints that separate subsequent legs. diff --git a/MapboxCoreNavigation/RouteProgress.swift b/MapboxCoreNavigation/RouteProgress.swift index ab2a4a70920..8517f1acbdf 100644 --- a/MapboxCoreNavigation/RouteProgress.swift +++ b/MapboxCoreNavigation/RouteProgress.swift @@ -87,7 +87,7 @@ open class RouteProgress: NSObject { This property does not include waypoints whose `Waypoint.separatesLegs` property is set to `false`. */ public var remainingWaypoints: [Waypoint] { - return route.legs.suffix(from: legIndex).map { $0.destination } + return route.legs.suffix(from: legIndex).compactMap { $0.destination } } /** @@ -141,9 +141,9 @@ open class RouteProgress: NSObject { - important: The adjacent steps may be part of legs other than the current leg. */ public var nearbyCoordinates: [CLLocationCoordinate2D] { - let priorCoordinates = priorStep?.coordinates?.dropLast() ?? [] - let currentCoordinates = currentLegProgress.currentStep.coordinates ?? [] - let upcomingCoordinates = upcomingStep?.coordinates?.dropFirst() ?? [] + let priorCoordinates = priorStep?.shape?.coordinates.dropLast() ?? [] + let currentCoordinates = currentLegProgress.currentStep.shape?.coordinates ?? [] + let upcomingCoordinates = upcomingStep?.shape?.coordinates.dropFirst() ?? [] return priorCoordinates + currentCoordinates + upcomingCoordinates } @@ -184,8 +184,8 @@ open class RouteProgress: NSObject { if let segmentCongestionLevels = leg.segmentCongestionLevels, let expectedSegmentTravelTimes = leg.expectedSegmentTravelTimes { for step in leg.steps { - guard let coordinates = step.coordinates else { continue } - let stepCoordinateCount = step.maneuverType == .arrive ? Int(step.coordinateCount) : coordinates.dropLast().count + guard let coordinates = step.shape?.coordinates else { continue } + let stepCoordinateCount = step.maneuverType == .arrive ? Int(coordinates.count) : coordinates.dropLast().count let nextManeuverCoordinateIndex = maneuverCoordinateIndex + stepCoordinateCount - 1 guard nextManeuverCoordinateIndex < segmentCongestionLevels.count else { continue } @@ -211,7 +211,11 @@ open class RouteProgress: NSObject { } public var averageCongestionLevelRemainingOnLeg: CongestionLevel? { - let coordinatesLeftOnStepCount = Int(floor((Double(currentLegProgress.currentStepProgress.step.coordinateCount)) * currentLegProgress.currentStepProgress.fractionTraveled)) + guard let coordinates = currentLegProgress.currentStepProgress.step.shape?.coordinates else { + return .unknown + } + + let coordinatesLeftOnStepCount = Int(floor((Double(coordinates.count)) * currentLegProgress.currentStepProgress.fractionTraveled)) guard coordinatesLeftOnStepCount >= 0 else { return .unknown } @@ -421,9 +425,9 @@ open class RouteLegProgress: NSObject { */ @available(*, deprecated, message: "Use RouteProgress.nearbyCoordinates") public var nearbyCoordinates: [CLLocationCoordinate2D] { - let priorCoords = priorStep?.coordinates ?? [] - let upcomingCoords = upcomingStep?.coordinates ?? [] - let currentCoords = currentStep.coordinates ?? [] + let priorCoords = priorStep?.shape?.coordinates ?? [] + let upcomingCoords = upcomingStep?.shape?.coordinates ?? [] + let currentCoords = currentStep.shape?.coordinates ?? [] let nearby = priorCoords + currentCoords + upcomingCoords assert(!nearby.isEmpty, "Step must have coordinates") return nearby @@ -436,7 +440,7 @@ open class RouteLegProgress: NSObject { let remainingSteps = leg.steps.suffix(from: stepIndex) for (currentStepIndex, step) in remainingSteps.enumerated() { - guard let coords = step.coordinates else { continue } + guard let coords = step.shape?.coordinates else { continue } guard let closestCoordOnStep = Polyline(coords).closestCoordinate(to: coordinate) else { continue } let foundIndex = currentStepIndex + stepIndex diff --git a/MapboxCoreNavigation/SimulatedLocationManager.swift b/MapboxCoreNavigation/SimulatedLocationManager.swift index 85234850373..8d021a4da8e 100644 --- a/MapboxCoreNavigation/SimulatedLocationManager.swift +++ b/MapboxCoreNavigation/SimulatedLocationManager.swift @@ -107,7 +107,7 @@ open class SimulatedLocationManager: NavigationLocationManager { } private func reset() { - if let coordinates = route?.coordinates { + if let coordinates = route?.shape?.coordinates { routeLine = coordinates locations = coordinates.simulatedLocationsWithTurnPenalties() } @@ -163,8 +163,8 @@ open class SimulatedLocationManager: NavigationLocationManager { // Simulate speed based on expected segment travel time if let expectedSegmentTravelTimes = routeProgress?.currentLeg.expectedSegmentTravelTimes, - let coordinates = routeProgress?.route.coordinates, - let closestCoordinateOnRoute = Polyline(routeProgress!.route.coordinates!).closestCoordinate(to: newCoordinate), + let coordinates = routeProgress?.route.shape?.coordinates, + let closestCoordinateOnRoute = Polyline(coordinates).closestCoordinate(to: newCoordinate), let nextCoordinateOnRoute = coordinates.after(element: coordinates[closestCoordinateOnRoute.index]), let time = expectedSegmentTravelTimes.optional[closestCoordinateOnRoute.index] { let distance = coordinates[closestCoordinateOnRoute.index].distance(to: nextCoordinateOnRoute)