diff --git a/Cartfile b/Cartfile index b8852173c15..01c86bcd648 100644 --- a/Cartfile +++ b/Cartfile @@ -1,8 +1,8 @@ binary "https://www.mapbox.com/ios-sdk/MapboxAccounts.json" ~> 2.2 binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" ~> 5.6 binary "https://www.mapbox.com/ios-sdk/MapboxNavigationNative.json" == 9.0.4 -github "mapbox/mapbox-directions-swift" ~> 0.31 -github "mapbox/turf-swift" ~> 0.3 +github "mapbox/mapbox-directions-swift" ~> 0.32 +github "mapbox/turf-swift" ~> 0.5 github "mapbox/mapbox-events-ios" ~> 0.10 github "ceeK/Solar" ~> 2.1.0 github "mapbox/mapbox-speech-swift" ~> 0.3.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index a6f7acbe72b..a3b4a51da57 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -8,9 +8,9 @@ github "Udumft/SnappyShrimp" "66f3e3ba70370ad5e889ac8ed72a8730ca79958e" github "ceeK/Solar" "2.1.0" github "linksmt/OHHTTPStubs" "563f48d3fab84ef04639649c770b00f4fa502cca" github "mapbox/MapboxGeocoder.swift" "v0.10.2" -github "mapbox/mapbox-directions-swift" "v0.31.0" +github "mapbox/mapbox-directions-swift" "v0.32.0" github "mapbox/mapbox-events-ios" "v0.10.2" github "mapbox/mapbox-speech-swift" "v0.3.0" -github "mapbox/turf-swift" "v0.3.0" +github "mapbox/turf-swift" "v0.5.0" github "raphaelmor/Polyline" "v4.2.1" github "uber/ios-snapshot-test-case" "5.0.2" diff --git a/Example/OfflineViewController.swift b/Example/OfflineViewController.swift index 227d61202a6..cee6b5915a1 100644 --- a/Example/OfflineViewController.swift +++ b/Example/OfflineViewController.swift @@ -1,5 +1,6 @@ import UIKit import Mapbox +import Turf import MapboxDirections import MapboxCoreNavigation @@ -47,7 +48,7 @@ class OfflineViewController: UIViewController, MGLMapViewDelegate { @objc func downloadRegion() { let mapCoordinateBounds = mapView.convert(resizableView.frame, toCoordinateBoundsFrom: nil) - let coordinateBounds = CoordinateBounds(coordinates: [mapCoordinateBounds.sw, mapCoordinateBounds.ne]) + let coordinateBounds = BoundingBox(mapCoordinateBounds.sw, mapCoordinateBounds.ne) disableUserInterface() diff --git a/MapboxCoreNavigation.podspec b/MapboxCoreNavigation.podspec index 88ba2a1cd08..e49b3a5db84 100644 --- a/MapboxCoreNavigation.podspec +++ b/MapboxCoreNavigation.podspec @@ -42,9 +42,9 @@ Pod::Spec.new do |s| s.dependency "MapboxNavigationNative", "= 9.0.4" s.dependency "MapboxAccounts", "~> 2.2.0" - s.dependency "MapboxDirections", "~> 0.31.0" + s.dependency "MapboxDirections", "~> 0.32.0" s.dependency "MapboxMobileEvents", "~> 0.10.2" # Always pin to a patch release if pre-1.0 - s.dependency "Turf", "~> 0.3.0" # Always pin to a patch release if pre-1.0 + s.dependency "Turf", "~> 0.5.0" # Always pin to a patch release if pre-1.0 s.swift_version = "5.0" diff --git a/MapboxCoreNavigation/CLLocation.swift b/MapboxCoreNavigation/CLLocation.swift index 2dca5cba1e0..8cbe06368cd 100644 --- a/MapboxCoreNavigation/CLLocation.swift +++ b/MapboxCoreNavigation/CLLocation.swift @@ -43,7 +43,7 @@ extension CLLocation { guard let shape = routeStep.shape, let closestCoordinate = shape.closestCoordinate(to: coordinate) else { return false } - return closestCoordinate.distance < maximumDistance + return closestCoordinate.coordinate.distance(to: coordinate) < maximumDistance } //MARK: - Route Snapping @@ -67,7 +67,7 @@ extension CLLocation { /** Calculates the proper coordinates to use when calculating a snapped location. */ - func snappingPolyline(for routeProgress: RouteProgress) -> Polyline { + func snappingPolyline(for routeProgress: RouteProgress) -> LineString { let legProgress = routeProgress.currentLegProgress let nearbyPolyline = routeProgress.nearbyShape let stepPolyline = legProgress.currentStep.shape! @@ -97,12 +97,12 @@ extension CLLocation { /** Given a location and a series of coordinates, compute what the course should be for a the location. */ - func interpolatedCourse(along polyline: Polyline) -> CLLocationDirection? { + func interpolatedCourse(along polyline: LineString) -> CLLocationDirection? { guard let closest = polyline.closestCoordinate(to: coordinate) else { return nil } - let reversedPolyline = Polyline(polyline.coordinates.reversed()) - let slicedLineBehind = reversedPolyline.sliced(from: closest.coordinate, to: reversedPolyline.coordinates.last) - let slicedLineInFront = polyline.sliced(from: closest.coordinate, to: polyline.coordinates.last) + let reversedPolyline = LineString(polyline.coordinates.reversed()) + let slicedLineBehind = reversedPolyline.sliced(from: closest.coordinate, to: reversedPolyline.coordinates.last)! + let slicedLineInFront = polyline.sliced(from: closest.coordinate, to: polyline.coordinates.last)! let userDistanceBuffer: CLLocationDistance = max(speed * RouteControllerDeadReckoningTimeInterval / 2, RouteControllerUserLocationSnappingDistance / 2) guard let pointBehind = slicedLineBehind.coordinateFromStart(distance: userDistanceBuffer) else { return nil } @@ -119,12 +119,15 @@ extension CLLocation { let relativeAnglepointBehind = (wrappedPointBehind - wrappedCourse).wrap(min: -180, max: 180) let relativeAnglepointAhead = (wrappedPointAhead - wrappedCourse).wrap(min: -180, max: 180) + let distanceBehindClosest = pointBehindClosest.coordinate.distance(to: pointBehind) + let distanceAheadClosest = pointAheadClosest.coordinate.distance(to: pointAhead) + let averageRelativeAngle: Double // User is at the beginning of the route, there is no closest point behind the user. - if pointBehindClosest.distance <= 0 && pointAheadClosest.distance > 0 { + if distanceBehindClosest <= 0 && distanceAheadClosest > 0 { averageRelativeAngle = relativeAnglepointAhead // User is at the end of the route, there is no closest point in front of the user. - } else if pointAheadClosest.distance <= 0 && pointBehindClosest.distance > 0 { + } else if distanceAheadClosest <= 0 && distanceBehindClosest > 0 { averageRelativeAngle = relativeAnglepointBehind } else { averageRelativeAngle = (relativeAnglepointBehind + relativeAnglepointAhead) / 2 diff --git a/MapboxCoreNavigation/LegacyRouteController.swift b/MapboxCoreNavigation/LegacyRouteController.swift index 590ed08769b..a544909d0a7 100644 --- a/MapboxCoreNavigation/LegacyRouteController.swift +++ b/MapboxCoreNavigation/LegacyRouteController.swift @@ -289,7 +289,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa } if let closestCoordinate = polyline.closestCoordinate(to: rawLocation.coordinate) { - let remainingDistance = polyline.distance(from: closestCoordinate.coordinate) + let remainingDistance = polyline.distance(from: closestCoordinate.coordinate)! let distanceTraveled = step.distance - remainingDistance stepProgress.distanceTraveled = distanceTraveled @@ -529,7 +529,7 @@ open class LegacyRouteController: NSObject, Router, InternalRouter, CLLocationMa func updateIntersectionDistances() { if let shape = routeProgress.currentLegProgress.currentStep.shape, let intersections = routeProgress.currentLegProgress.currentStep.intersections { - let distances: [CLLocationDistance] = intersections.map { shape.distance(from: shape.coordinates.first, to: $0.location) } + let distances: [CLLocationDistance] = intersections.compactMap { shape.distance(from: shape.coordinates.first, to: $0.location) } routeProgress.currentLegProgress.currentStepProgress.intersectionDistances = distances } } diff --git a/MapboxCoreNavigation/RouteController.swift b/MapboxCoreNavigation/RouteController.swift index bdc67db1594..7101098518b 100644 --- a/MapboxCoreNavigation/RouteController.swift +++ b/MapboxCoreNavigation/RouteController.swift @@ -304,7 +304,7 @@ open class RouteController: NSObject { preconditionFailure("Route steps used for navigation must have shape data") } if let closestCoordinate = polyline.closestCoordinate(to: rawLocation.coordinate) { - let remainingDistance = polyline.distance(from: closestCoordinate.coordinate) + let remainingDistance = polyline.distance(from: closestCoordinate.coordinate)! let distanceTraveled = step.distance - remainingDistance stepProgress.distanceTraveled = distanceTraveled diff --git a/MapboxCoreNavigation/RouteProgress.swift b/MapboxCoreNavigation/RouteProgress.swift index 1d6ab08000e..304a53f5827 100644 --- a/MapboxCoreNavigation/RouteProgress.swift +++ b/MapboxCoreNavigation/RouteProgress.swift @@ -437,16 +437,17 @@ open class RouteLegProgress { for (currentStepIndex, step) in remainingSteps.enumerated() { guard let shape = step.shape else { continue } guard let closestCoordOnStep = shape.closestCoordinate(to: coordinate) else { continue } + let closesCoordOnStepDistance = closestCoordOnStep.coordinate.distance(to: coordinate) let foundIndex = currentStepIndex + stepIndex // First time around, currentClosest will be `nil`. guard let currentClosestDistance = currentClosest?.distance else { - currentClosest = (index: foundIndex, distance: closestCoordOnStep.distance) + currentClosest = (index: foundIndex, distance: closesCoordOnStepDistance) continue } - if closestCoordOnStep.distance < currentClosestDistance { - currentClosest = (index: foundIndex, distance: closestCoordOnStep.distance) + if closesCoordOnStepDistance < currentClosestDistance { + currentClosest = (index: foundIndex, distance: closesCoordOnStepDistance) } } @@ -469,11 +470,7 @@ open class RouteLegProgress { var slice = legPolyline var accumulatedCoordinates = 0 return Array(waypoints.drop { (waypoint) -> Bool in - var newSlice = slice.sliced(from: waypoint.coordinate) - // Work around . - if newSlice.coordinates.count > 2 && newSlice.coordinates.last == newSlice.coordinates.dropLast().last { - newSlice.coordinates.removeLast() - } + let newSlice = slice.sliced(from: waypoint.coordinate)! accumulatedCoordinates += slice.coordinates.count - newSlice.coordinates.count slice = newSlice return accumulatedCoordinates <= userCoordinateIndex diff --git a/MapboxCoreNavigation/SimulatedLocationManager.swift b/MapboxCoreNavigation/SimulatedLocationManager.swift index 8935ceed04d..2c0045cf106 100644 --- a/MapboxCoreNavigation/SimulatedLocationManager.swift +++ b/MapboxCoreNavigation/SimulatedLocationManager.swift @@ -35,7 +35,7 @@ open class SimulatedLocationManager: NavigationLocationManager { fileprivate var timer: DispatchTimer! fileprivate var locations: [SimulatedLocation]! - fileprivate var routeShape: Polyline! + fileprivate var routeShape: LineString! /** Specify the multiplier to use when calculating speed based on the RouteLeg’s `expectedSegmentTravelTimes`. @@ -157,7 +157,7 @@ open class SimulatedLocationManager: NavigationLocationManager { let distanceToClosest = closestLocation.distance(from: CLLocation(newCoordinate)) let distance = min(max(distanceToClosest, 10), safeDistance) - let coordinatesNearby = polyline.trimmed(from: newCoordinate, distance: 100).coordinates + let coordinatesNearby = polyline.trimmed(from: newCoordinate, distance: 100)!.coordinates // Simulate speed based on expected segment travel time if let expectedSegmentTravelTimes = routeProgress?.currentLeg.expectedSegmentTravelTimes, diff --git a/MapboxCoreNavigationTests/CocoaPodsTest/PodInstall/Podfile.lock b/MapboxCoreNavigationTests/CocoaPodsTest/PodInstall/Podfile.lock index fde9761d3fd..2059d01517e 100644 --- a/MapboxCoreNavigationTests/CocoaPodsTest/PodInstall/Podfile.lock +++ b/MapboxCoreNavigationTests/CocoaPodsTest/PodInstall/Podfile.lock @@ -4,13 +4,13 @@ PODS: - MapboxAccounts (2.2.0) - MapboxCoreNavigation (0.40.0): - MapboxAccounts (~> 2.2.0) - - MapboxDirections (~> 0.31.0) + - MapboxDirections (~> 0.32.0) - MapboxMobileEvents (~> 0.10.2) - MapboxNavigationNative (= 9.0.4) - - Turf (~> 0.3.0) - - MapboxDirections (0.31.0): + - Turf (~> 0.5.0) + - MapboxDirections (0.32.0): - Polyline (~> 4.2) - - Turf (~> 0.3) + - Turf (~> 0.5) - MapboxMobileEvents (0.10.2) - MapboxNavigation (0.40.0): - Mapbox-iOS-SDK (~> 5.6) @@ -22,14 +22,14 @@ PODS: - MapboxSpeech (0.3.0) - Polyline (4.2.1) - Solar (2.1.0) - - Turf (0.3.0) + - Turf (0.5.0) DEPENDENCIES: - MapboxCoreNavigation (from `../../../`) - MapboxNavigation (from `../../../`) SPEC REPOS: - https://github.com/cocoapods/specs.git: + https://github.com/cocoapods/specs.git: - Mapbox-iOS-SDK - MapboxAccounts - MapboxDirections @@ -49,16 +49,16 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Mapbox-iOS-SDK: a5915700ec84bc1a7f8b3e746d474789e35b7956 MapboxAccounts: 3c04a1df56c1ac4ff714619296fb47310cf70ad0 - MapboxCoreNavigation: 79d1b2e201be2aed7edd188f90de54c03a59606d - MapboxDirections: 0b97aa320d7cddbe72d6513becc07dd747935240 + MapboxCoreNavigation: e172e4407f69e4dbef19c20bce2045347ea6dc34 + MapboxDirections: 7f36b3e9ef6a53fc997c114a341ab4da721756bd MapboxMobileEvents: 2bc0ca2eedb627b73cf403258dce2b2fa98074a6 MapboxNavigation: 42bae50b0381dce317c85884ba0de38fc68a4814 MapboxNavigationNative: 50436c659f40d7f67ed8a60652c9d344f0e10e27 MapboxSpeech: 403415e932e084cf290b9d55c49ab7ea210b9595 Polyline: 0e9890790292741c8186201a536b6bb6a78d02dd Solar: 2dc6e7cc39186cb0c8228fa08df76fb50c7d8f24 - Turf: c6bdf62d6a70c647874f295dd1cf4eefc0c3e9e6 + Turf: bdcfefe60df3ca8dc5f742681c178e47f8c5a567 PODFILE CHECKSUM: d4084fe664fbacd0cffd88ab45eaed1ad907ad1d -COCOAPODS: 1.7.5 +COCOAPODS: 1.8.4 diff --git a/MapboxCoreNavigationTests/RouteProgressTests.swift b/MapboxCoreNavigationTests/RouteProgressTests.swift index ba088076b47..93505d95782 100644 --- a/MapboxCoreNavigationTests/RouteProgressTests.swift +++ b/MapboxCoreNavigationTests/RouteProgressTests.swift @@ -196,22 +196,22 @@ class RouteProgressTests: XCTestCase { XCTAssertEqual(remainingWaypoints.count, 4, "At the first via point before backtracking, all but the source and first via point should remain") - legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance() / 2.0 + legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance()! / 2.0 remainingWaypoints = legProgress.remainingWaypoints(among: Array(options.waypoints.dropLast())) XCTAssertEqual(remainingWaypoints.count, 2, "At the via point where the leg backtracks, only the via points after backtracking should remain") - legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance() / 2.0 + coordinates[3].distance(to: coordinates[4]) / 2.0 + legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance()! / 2.0 + coordinates[3].distance(to: coordinates[4]) / 2.0 remainingWaypoints = legProgress.remainingWaypoints(among: Array(options.waypoints.dropLast())) XCTAssertEqual(remainingWaypoints.count, 2, "Halfway to the via point where the leg backtracks, only the via points after backtracking should remain") - legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance() / 2.0 + coordinates[3].distance(to: coordinates[4]) + legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance()! / 2.0 + coordinates[3].distance(to: coordinates[4]) remainingWaypoints = legProgress.remainingWaypoints(among: Array(options.waypoints.dropLast())) XCTAssertEqual(remainingWaypoints.count, 1, "At the first via point after backtracking, all but one of the via points after backtracking should remain") - legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance() + legProgress.currentStepProgress.distanceTraveled = LineString(coordinates).distance()! remainingWaypoints = legProgress.remainingWaypoints(among: Array(options.waypoints.dropLast())) XCTAssertEqual(remainingWaypoints.count, 0, "At the last via point after backtracking, nothing should remain") @@ -243,32 +243,32 @@ class RouteProgressTests: XCTestCase { XCTAssertEqual(legProgress.distanceTraveled, 0) XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 10, unit: UnitSpeed.kilometersPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[1]) / 2.0 + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[1])! / 2.0 XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 10, unit: UnitSpeed.kilometersPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[1]) + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[1])! XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 20, unit: UnitSpeed.milesPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[1]) + lineString.distance(from: coordinates[1], to: coordinates[2]) / 2.0 + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[1])! + lineString.distance(from: coordinates[1], to: coordinates[2])! / 2.0 XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 20, unit: UnitSpeed.milesPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[2]) + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[2])! XCTAssertNil(legProgress.currentSpeedLimit) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[2]) + lineString.distance(from: coordinates[2], to: coordinates[3]) / 2.0 + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[2])! + lineString.distance(from: coordinates[2], to: coordinates[3])! / 2.0 XCTAssertNil(legProgress.currentSpeedLimit) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[3]) + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[3])! XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 40, unit: UnitSpeed.milesPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[3]) + lineString.distance(from: coordinates[3], to: coordinates[4]) / 2.0 + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[3])! + lineString.distance(from: coordinates[3], to: coordinates[4])! / 2.0 XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 40, unit: UnitSpeed.milesPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[4]) + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[4])! XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 50, unit: UnitSpeed.kilometersPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[4]) + lineString.distance(from: coordinates[4], to: coordinates[5]) / 2.0 + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[4])! + lineString.distance(from: coordinates[4], to: coordinates[5])! / 2.0 XCTAssertEqual(legProgress.currentSpeedLimit, Measurement(value: 50, unit: UnitSpeed.kilometersPerHour)) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[5]) + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[5])! XCTAssertTrue(legProgress.currentSpeedLimit?.value.isInfinite ?? false) - legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[5]) + (lineString.distance() - lineString.distance(to: coordinates[5])) / 2.0 + legProgress.currentStepProgress.distanceTraveled = lineString.distance(to: coordinates[5])! + (lineString.distance()! - lineString.distance(to: coordinates[5])!) / 2.0 XCTAssertTrue(legProgress.currentSpeedLimit?.value.isInfinite ?? false) } } diff --git a/MapboxNavigation-Documentation.podspec b/MapboxNavigation-Documentation.podspec index e9b1a04e8d5..2bcd9c6b2b3 100644 --- a/MapboxNavigation-Documentation.podspec +++ b/MapboxNavigation-Documentation.podspec @@ -46,13 +46,13 @@ Pod::Spec.new do |s| s.frameworks = ['CarPlay'] s.dependency "MapboxAccounts", "~> 2.2.0" - s.dependency "MapboxDirections", "~> 0.31.0" + s.dependency "MapboxDirections", "~> 0.32.0" s.dependency "MapboxGeocoder.swift", "~> 0.10.0" s.dependency "Mapbox-iOS-SDK", "~> 5.6" s.dependency "MapboxMobileEvents", "~> 0.10.2" s.dependency "MapboxNavigationNative", "= 9.0.4" s.dependency "Solar", "~> 2.1" - s.dependency "Turf", "~> 0.3.0" + s.dependency "Turf", "~> 0.5.0" s.dependency "MapboxSpeech", "~> 0.3.0" s.swift_version = "5.0" diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index 85144bf9f3a..b8d96b766f2 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -135,6 +135,8 @@ class InstructionPresenter { ?? NSAttributedString(string: text.text, attributes: defaultAttributes) case .lane(_, _): preconditionFailure("Lane component has no attributed string representation.") + case .guidanceView(_, let alternativeText): + return NSAttributedString(string: alternativeText.text, attributes: defaultAttributes) } } let separator = NSAttributedString(string: " ", attributes: defaultAttributes) diff --git a/MapboxNavigation/MGLShape.swift b/MapboxNavigation/MGLShape.swift index 96781248e39..eb66bce86b3 100644 --- a/MapboxNavigation/MGLShape.swift +++ b/MapboxNavigation/MGLShape.swift @@ -17,12 +17,17 @@ extension MGLPointFeature { /** Initializes a map point feature representation of the given Turf point feature. - - parameter pointFeature: The Turf point feature to convert to a map point feature. + - parameter pointFeature: The Turf `Point` feature to convert to a map point feature. If the Feature passed is not of type `Point` - initialization fails. */ - public convenience init(_ pointFeature: PointFeature) { - self.init(pointFeature.geometry) + public convenience init?(_ pointFeature: Feature) { + guard case let .point(pointGeometry) = pointFeature.geometry else { + return nil + } + self.init(pointGeometry) identifier = pointFeature.identifier - attributes = pointFeature.properties ?? [:] + attributes = pointFeature.properties?.compactMapValues { + return $0 + } ?? [:] } } @@ -41,12 +46,17 @@ extension MGLPolylineFeature { /** Initializes a map polyline feature representation of the given Turf linestring feature. - - parameter lineStringFeature: The Turf linestring feature to convert to a map polyline feature. + - parameter lineStringFeature: The Turf `LineString` feature to convert to a map polyline feature. If the Feature passed is not of type `LineString` - initialization fails. */ - public convenience init(_ lineStringFeature: LineStringFeature) { - self.init(lineStringFeature.geometry) + public convenience init?(_ lineStringFeature: Feature) { + guard case let .lineString(lineStringGeometry) = lineStringFeature.geometry else { + return nil + } + self.init(lineStringGeometry) identifier = lineStringFeature.identifier - attributes = lineStringFeature.properties ?? [:] + attributes = lineStringFeature.properties?.compactMapValues { + return $0 + } ?? [:] } } @@ -66,12 +76,17 @@ extension MGLMultiPolylineFeature { /** Initializes a map multipolyline feature representation of the given Turf multilinestring feature. - - parameter multiLineStringFeature: The Turf multilinestring feature to convert to a map multipolyline feature. + - parameter multiLineStringFeature: The Turf `MultiLineString` feature to convert to a map multipolyline feature. If the Feature passed is not of type `MultiLineString` - initialization fails. */ - public convenience init(_ multiLineStringFeature: MultiLineStringFeature) { - self.init(multiLineStringFeature.geometry) + public convenience init?(_ multiLineStringFeature: Feature) { + guard case let .multiLineString(multiLineStringGeometry) = multiLineStringFeature.geometry else { + return nil + } + self.init(multiLineStringGeometry) identifier = multiLineStringFeature.identifier - attributes = multiLineStringFeature.properties ?? [:] + attributes = multiLineStringFeature.properties?.compactMapValues { + return $0 + } ?? [:] } } @@ -92,7 +107,7 @@ extension MGLPolygon { */ public convenience init(_ polygon: Polygon) { let outerCoordinates = polygon.outerRing.coordinates - let interiorPolygons = polygon.innerRings?.map { MGLPolygon($0) } + let interiorPolygons = polygon.innerRings.map { MGLPolygon($0) } self.init(coordinates: outerCoordinates, count: UInt(outerCoordinates.count), interiorPolygons: interiorPolygons) } } @@ -101,12 +116,17 @@ extension MGLPolygonFeature { /** Initializes a map polygon feature representation of the given Turf polygon feature. - - parameter polygonFeature: The Turf polygon feature to convert to a map polygon feature. + - parameter polygonFeature: The Turf `Polygon` feature to convert to a map polygon feature. If the Feature passed is not of type `Polygon` - initialization fails. */ - public convenience init(_ polygonFeature: PolygonFeature) { - self.init(polygonFeature.geometry) + public convenience init?(_ polygonFeature: Feature) { + guard case let .polygon(polygonGeometry) = polygonFeature.geometry else { + return nil + } + self.init(polygonGeometry) identifier = polygonFeature.identifier - attributes = polygonFeature.properties ?? [:] + attributes = polygonFeature.properties?.compactMapValues { + return $0 + } ?? [:] } } @@ -121,11 +141,16 @@ extension MGLMultiPolygonFeature { /** Initializes a map multipolygon feature representation of the given Turf multipolygon feature. - - parameter multipolygonFeature: The Turf multipolygon feature to convert to a map multipolygon feature. + - parameter multipolygonFeature: The Turf `MultiPolygon` feature to convert to a map multipolygon feature. If the Feature passed is not of type `MultiPolygon` - initialization fails. */ - public convenience init(_ multiPolygonFeature: MultiPolygonFeature) { - self.init(multiPolygonFeature.geometry) + public convenience init?(_ multiPolygonFeature: Feature) { + guard case let .multiPolygon(multiPolygonGeometry) = multiPolygonFeature.geometry else { + return nil + } + self.init(multiPolygonGeometry) identifier = multiPolygonFeature.identifier - attributes = multiPolygonFeature.properties ?? [:] + attributes = multiPolygonFeature.properties?.compactMapValues { + return $0 + } ?? [:] } } diff --git a/MapboxNavigation/Match.swift b/MapboxNavigation/Match.swift index 982a763f3e9..55088bebddd 100644 --- a/MapboxNavigation/Match.swift +++ b/MapboxNavigation/Match.swift @@ -12,30 +12,33 @@ extension Match { - parameter distance: Distance by which the resulting polyline extends in either direction from the maneuver. - returns: A polyline whose length is twice `distance` and whose centroid is located at the maneuver. */ - func polylineAroundManeuver(legIndex: Int, stepIndex: Int, distance: CLLocationDistance) -> Polyline { + func polylineAroundManeuver(legIndex: Int, stepIndex: Int, distance: CLLocationDistance) -> LineString { let precedingLegs = legs.prefix(upTo: legIndex) let precedingLegCoordinates = precedingLegs.flatMap { $0.steps }.flatMap { $0.shape?.coordinates ?? [] } let precedingSteps = legs[legIndex].steps.prefix(upTo: stepIndex) let precedingStepCoordinates = precedingSteps.compactMap { $0.shape?.coordinates }.reduce([], +) - let precedingPolyline = Polyline((precedingLegCoordinates + precedingStepCoordinates).reversed()) + let precedingPolyline = LineString((precedingLegCoordinates + precedingStepCoordinates).reversed()) let followingLegs = legs.suffix(from: legIndex).dropFirst() let followingLegCoordinates = followingLegs.flatMap { $0.steps }.flatMap { $0.shape?.coordinates ?? [] } let followingSteps = legs[legIndex].steps.suffix(from: stepIndex) let followingStepCoordinates = followingSteps.compactMap { $0.shape?.coordinates }.reduce([], +) - let followingPolyline = Polyline(followingStepCoordinates + followingLegCoordinates) + let followingPolyline = LineString(followingStepCoordinates + followingLegCoordinates) // After trimming, reverse the array so that the resulting polyline proceeds in a forward direction throughout. let trimmedPrecedingCoordinates: [CLLocationCoordinate2D] if precedingPolyline.coordinates.isEmpty { trimmedPrecedingCoordinates = [] } else { - trimmedPrecedingCoordinates = precedingPolyline.trimmed(from: precedingPolyline.coordinates[0], distance: distance).coordinates.reversed() + trimmedPrecedingCoordinates = precedingPolyline.trimmed(from: precedingPolyline.coordinates[0], distance: distance)!.coordinates.reversed() } // Omit the first coordinate, which is already contained in trimmedPrecedingCoordinates. - let trimmedFollowingCoordinates = followingPolyline.trimmed(from: followingPolyline.coordinates[0], distance: distance).coordinates.suffix(from: 1) - return Polyline(trimmedPrecedingCoordinates + trimmedFollowingCoordinates) + if followingPolyline.coordinates.isEmpty { + return LineString(trimmedPrecedingCoordinates) + } else { + return LineString(trimmedPrecedingCoordinates + followingPolyline.trimmed(from: followingPolyline.coordinates[0], distance: distance)!.coordinates.suffix(from: 1)) + } } } diff --git a/MapboxNavigation/NavigationMapView.swift b/MapboxNavigation/NavigationMapView.swift index 4c4055f5525..95661fec619 100644 --- a/MapboxNavigation/NavigationMapView.swift +++ b/MapboxNavigation/NavigationMapView.swift @@ -750,8 +750,8 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate { //existance has been assured through use of filter. let leftLine = left.shape! let rightLine = right.shape! - let leftDistance = leftLine.closestCoordinate(to: tapCoordinate)!.distance - let rightDistance = rightLine.closestCoordinate(to: tapCoordinate)!.distance + let leftDistance = leftLine.closestCoordinate(to: tapCoordinate)!.coordinate.distance(to: tapCoordinate) + let rightDistance = rightLine.closestCoordinate(to: tapCoordinate)!.coordinate.distance(to: tapCoordinate) return leftDistance < rightDistance } @@ -1003,7 +1003,7 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate { for (stepIndex, step) in leg.steps.enumerated() { for instruction in step.instructionsSpokenAlongStep! { let feature = MGLPointFeature() - feature.coordinate = Polyline(route.legs[legIndex].steps[stepIndex].shape!.coordinates.reversed()).coordinateFromStart(distance: instruction.distanceAlongStep)! + feature.coordinate = LineString(route.legs[legIndex].steps[stepIndex].shape!.coordinates.reversed()).coordinateFromStart(distance: instruction.distanceAlongStep)! feature.attributes = [ "instruction": instruction.text ] features.append(feature) } diff --git a/MapboxNavigation/Route.swift b/MapboxNavigation/Route.swift index 2bb8e9b1b3a..c30e284c7f2 100644 --- a/MapboxNavigation/Route.swift +++ b/MapboxNavigation/Route.swift @@ -12,30 +12,33 @@ extension Route { - parameter distance: Distance by which the resulting polyline extends in either direction from the maneuver. - returns: A polyline whose length is twice `distance` and whose centroid is located at the maneuver. */ - func polylineAroundManeuver(legIndex: Int, stepIndex: Int, distance: CLLocationDistance) -> Polyline { + func polylineAroundManeuver(legIndex: Int, stepIndex: Int, distance: CLLocationDistance) -> LineString { let precedingLegs = legs.prefix(upTo: legIndex) let precedingLegCoordinates = precedingLegs.flatMap { $0.steps }.flatMap { $0.shape?.coordinates ?? [] } let precedingSteps = legs[legIndex].steps.prefix(upTo: stepIndex) let precedingStepCoordinates = precedingSteps.compactMap { $0.shape?.coordinates }.reduce([], +) - let precedingPolyline = Polyline((precedingLegCoordinates + precedingStepCoordinates).reversed()) + let precedingPolyline = LineString((precedingLegCoordinates + precedingStepCoordinates).reversed()) let followingLegs = legs.suffix(from: legIndex).dropFirst() let followingLegCoordinates = followingLegs.flatMap { $0.steps }.flatMap { $0.shape?.coordinates ?? [] } let followingSteps = legs[legIndex].steps.suffix(from: stepIndex) let followingStepCoordinates = followingSteps.compactMap { $0.shape?.coordinates }.reduce([], +) - let followingPolyline = Polyline(followingStepCoordinates + followingLegCoordinates) + let followingPolyline = LineString(followingStepCoordinates + followingLegCoordinates) // After trimming, reverse the array so that the resulting polyline proceeds in a forward direction throughout. let trimmedPrecedingCoordinates: [CLLocationCoordinate2D] if precedingPolyline.coordinates.isEmpty { trimmedPrecedingCoordinates = [] } else { - trimmedPrecedingCoordinates = precedingPolyline.trimmed(from: precedingPolyline.coordinates[0], distance: distance).coordinates.reversed() + trimmedPrecedingCoordinates = precedingPolyline.trimmed(from: precedingPolyline.coordinates[0], distance: distance)!.coordinates.reversed() } // Omit the first coordinate, which is already contained in trimmedPrecedingCoordinates. - let trimmedFollowingCoordinates = followingPolyline.trimmed(from: followingPolyline.coordinates[0], distance: distance).coordinates.suffix(from: 1) - return Polyline(trimmedPrecedingCoordinates + trimmedFollowingCoordinates) + if followingPolyline.coordinates.isEmpty { + return LineString(trimmedPrecedingCoordinates) + } else { + return LineString(trimmedPrecedingCoordinates + followingPolyline.trimmed(from: followingPolyline.coordinates[0], distance: distance)!.coordinates.suffix(from: 1)) + } } } diff --git a/MapboxNavigation/RouteMapViewController.swift b/MapboxNavigation/RouteMapViewController.swift index eb935286e85..25a8e53f2d7 100644 --- a/MapboxNavigation/RouteMapViewController.swift +++ b/MapboxNavigation/RouteMapViewController.swift @@ -414,8 +414,8 @@ class RouteMapViewController: UIViewController { guard let height = navigationView.endOfRouteHeightConstraint?.constant else { return } let insets = UIEdgeInsets(top: topBannerContainerView.bounds.height, left: 20, bottom: height + 20, right: 20) - if let shape = route.shape, let userLocation = navService.router.location?.coordinate { - let slicedLineString = shape.sliced(from: userLocation) + if let shape = route.shape, let userLocation = navService.router.location?.coordinate, !shape.coordinates.isEmpty { + let slicedLineString = shape.sliced(from: userLocation)! let line = MGLPolyline(slicedLineString) let camera = navigationView.mapView.cameraThatFitsShape(line, direction: navigationView.mapView.camera.heading, edgePadding: insets) @@ -619,7 +619,7 @@ extension RouteMapViewController: NavigationViewDelegate { } func labelCurrentRoadFeature(at location: CLLocation) { - guard let style = mapView.style, let stepShape = router.routeProgress.currentLegProgress.currentStep.shape else { + guard let style = mapView.style, let stepShape = router.routeProgress.currentLegProgress.currentStep.shape, !stepShape.coordinates.isEmpty else { return } @@ -663,14 +663,15 @@ extension RouteMapViewController: NavigationViewDelegate { } for line in allLines { + guard line.pointCount > 0 else { continue } let featureCoordinates = Array(UnsafeBufferPointer(start: line.coordinates, count: Int(line.pointCount))) - let featurePolyline = Polyline(featureCoordinates) - let slicedLine = stepShape.sliced(from: closestCoordinate) + let featurePolyline = LineString(featureCoordinates) + let slicedLine = stepShape.sliced(from: closestCoordinate)! let lookAheadDistance: CLLocationDistance = 10 - guard let pointAheadFeature = featurePolyline.sliced(from: closestCoordinate).coordinateFromStart(distance: lookAheadDistance) else { continue } + guard let pointAheadFeature = featurePolyline.sliced(from: closestCoordinate)!.coordinateFromStart(distance: lookAheadDistance) else { continue } guard let pointAheadUser = slicedLine.coordinateFromStart(distance: lookAheadDistance) else { continue } - guard let reversedPoint = Polyline(featureCoordinates.reversed()).sliced(from: closestCoordinate).coordinateFromStart(distance: lookAheadDistance) else { continue } + guard let reversedPoint = LineString(featureCoordinates.reversed()).sliced(from: closestCoordinate)!.coordinateFromStart(distance: lookAheadDistance) else { continue } let distanceBetweenPointsAhead = pointAheadFeature.distance(to: pointAheadUser) let distanceBetweenReversedPoint = reversedPoint.distance(to: pointAheadUser) diff --git a/MapboxNavigation/VisualInstructionComponent.swift b/MapboxNavigation/VisualInstructionComponent.swift index bf2eb18c617..5297cc20336 100644 --- a/MapboxNavigation/VisualInstructionComponent.swift +++ b/MapboxNavigation/VisualInstructionComponent.swift @@ -17,6 +17,9 @@ extension VisualInstruction.Component { return "\(imageURL.absoluteString)-\(VisualInstruction.Component.scale)" case .text, .delimiter, .lane: return nil + case .guidanceView(let guidanceViewRepresentation, _): + guard let imageURL = guidanceViewRepresentation.imageURL else { return nil } + return "guidance-" + imageURL.absoluteString } } } diff --git a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift index b92a04bc39a..9b72c80d487 100644 --- a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift @@ -18,7 +18,7 @@ func makeVisualInstruction(_ maneuverType: ManeuverType = .arrive, secondary = VisualInstruction(text: "Instruction", maneuverType: maneuverType, maneuverDirection: maneuverDirection, components: secondaryInstruction) } - return VisualInstructionBanner(distanceAlongStep: 482.803, primary: primary, secondary: secondary, tertiary: nil, drivingSide: .right) + return VisualInstructionBanner(distanceAlongStep: 482.803, primary: primary, secondary: secondary, tertiary: nil, quaternary: nil, drivingSide: .right) } class InstructionsBannerViewIntegrationTests: XCTestCase { diff --git a/MapboxNavigationTests/RouteTests.swift b/MapboxNavigationTests/RouteTests.swift index 88cfb69af3b..da9b1325c2c 100644 --- a/MapboxNavigationTests/RouteTests.swift +++ b/MapboxNavigationTests/RouteTests.swift @@ -68,14 +68,14 @@ class RouteTests: XCTestCase { let firstIndexedCoordinate = precedingStepPolyline.closestCoordinate(to: maneuverPolyline.coordinates[0]) XCTAssertNotNil(firstIndexedCoordinate) - XCTAssertLessThan(firstIndexedCoordinate?.distance ?? .greatestFiniteMagnitude, 1, "Start of maneuver polyline for step \(stepIndex) is \(firstIndexedCoordinate?.distance ?? -1) away from approach to intersection.") + XCTAssertLessThan(firstIndexedCoordinate!.coordinate.distance(to: maneuverPolyline.coordinates[0]), 1, "Start of maneuver polyline for step \(stepIndex) is \(firstIndexedCoordinate!.coordinate.distance(to: maneuverPolyline.coordinates[0])) away from approach to intersection.") let indexedManeuverLocation = stepPolyline.closestCoordinate(to: followingStep.maneuverLocation) XCTAssertLessThan(indexedManeuverLocation?.distance ?? .greatestFiniteMagnitude, 1, "Maneuver polyline for step \(stepIndex) turns \(indexedManeuverLocation?.distance ?? -1) away from intersection.") let lastIndexedCoordinate = stepPolyline.closestCoordinate(to: maneuverPolyline.coordinates.last!) XCTAssertNotNil(lastIndexedCoordinate) - XCTAssertLessThan(lastIndexedCoordinate?.distance ?? .greatestFiniteMagnitude, 1, "End of maneuver polyline for step \(stepIndex) is \(lastIndexedCoordinate?.distance ?? -1) away from outlet from intersection.") + XCTAssertLessThan(lastIndexedCoordinate!.coordinate.distance(to: maneuverPolyline.coordinates.last!), 1, "End of maneuver polyline for step \(stepIndex) is \(lastIndexedCoordinate!.coordinate.distance(to: maneuverPolyline.coordinates.last!)) away from outlet from intersection.") } } }