Skip to content

Commit

Permalink
Merge pull request #656 from mapbox/pad-via-waypoints
Browse files Browse the repository at this point in the history
Add support for `via_waypoints`
  • Loading branch information
chezzdev committed Feb 23, 2022
2 parents 84ce228 + 0727dab commit 78f5e76
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v2.3.0

* Added `VisualInstruction.Component.ShieldRepresentation` struct for displaying a highway shield. Added `VisualInstruction.Component.ImageRepresentation.shield` property. ([#644](https://github.com/mapbox/mapbox-directions-swift/pull/644), [#647](https://github.com/mapbox/mapbox-directions-swift/pull/647))
* Added `RouteLeg.viaWaypoints` property and `SilentWaypoint` struct for describing silent waypoints along `RouteLeg`. ([#656](https://github.com/mapbox/mapbox-directions-swift/pull/656))

## v2.2.0

Expand Down
10 changes: 10 additions & 0 deletions MapboxDirections.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
2BF398C627620CD7000C9A72 /* RouteRefreshSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BF398C427620CD7000C9A72 /* RouteRefreshSource.swift */; };
2BF398C727620CD7000C9A72 /* RouteRefreshSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BF398C427620CD7000C9A72 /* RouteRefreshSource.swift */; };
2BF398C827620CD7000C9A72 /* RouteRefreshSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BF398C427620CD7000C9A72 /* RouteRefreshSource.swift */; };
2E44711727C4C80B0041CB84 /* SilentWaypoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E44711627C4C80B0041CB84 /* SilentWaypoint.swift */; };
2E44711827C4C80B0041CB84 /* SilentWaypoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E44711627C4C80B0041CB84 /* SilentWaypoint.swift */; };
2E44711927C4C80B0041CB84 /* SilentWaypoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E44711627C4C80B0041CB84 /* SilentWaypoint.swift */; };
2E44711A27C4C80B0041CB84 /* SilentWaypoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E44711627C4C80B0041CB84 /* SilentWaypoint.swift */; };
35828C9E217A003F00ED546E /* OfflineDirections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35828C9D217A003F00ED546E /* OfflineDirections.swift */; };
35828C9F217A003F00ED546E /* OfflineDirections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35828C9D217A003F00ED546E /* OfflineDirections.swift */; };
35828CA0217A003F00ED546E /* OfflineDirections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35828C9D217A003F00ED546E /* OfflineDirections.swift */; };
Expand Down Expand Up @@ -494,6 +498,7 @@
2BBBD05D257E61ED004EB3D6 /* MapboxStreetsRoadClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapboxStreetsRoadClass.swift; sourceTree = "<group>"; };
2BBBD08C257FA1CD004EB3D6 /* BlockedLanes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedLanes.swift; sourceTree = "<group>"; };
2BF398C427620CD7000C9A72 /* RouteRefreshSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteRefreshSource.swift; sourceTree = "<group>"; };
2E44711627C4C80B0041CB84 /* SilentWaypoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilentWaypoint.swift; sourceTree = "<group>"; };
3556CE9922649CF2009397B5 /* MapboxDirectionsTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "MapboxDirectionsTests-Bridging-Header.h"; path = "../objc/MapboxDirectionsTests-Bridging-Header.h"; sourceTree = "<group>"; };
35828C9D217A003F00ED546E /* OfflineDirections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfflineDirections.swift; sourceTree = "<group>"; };
35CC310A2285739700EA1966 /* WalkingOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalkingOptionsTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -834,6 +839,7 @@
2BF398C427620CD7000C9A72 /* RouteRefreshSource.swift */,
43538E3623ED3B1600E010D4 /* ResponseDisposition.swift */,
DA2E03E81CB0E0B000D1269A /* RouteStep.swift */,
2E44711627C4C80B0041CB84 /* SilentWaypoint.swift */,
C55FB44A1F6AEBF6006BD1E9 /* SpokenInstruction.swift */,
35EFD00A207DFACA00BF3873 /* VisualInstruction.swift */,
C52552B81FA15D5900B1545C /* VisualInstructionBanner.swift */,
Expand Down Expand Up @@ -1411,6 +1417,7 @@
35828C9F217A003F00ED546E /* OfflineDirections.swift in Sources */,
2B5F0E01273BEB3600CC2C1A /* RoadClassExclusionViolation.swift in Sources */,
DAE7EA95230B5FD10003B211 /* Measurement.swift in Sources */,
2E44711827C4C80B0041CB84 /* SilentWaypoint.swift in Sources */,
C5DAAC9F20195AAE001F9261 /* Tracepoint.swift in Sources */,
2B9F3882272AE23A001DBA12 /* ProfileIdentifier.swift in Sources */,
431E93CC23466C2500A71B44 /* RouteResponse.swift in Sources */,
Expand Down Expand Up @@ -1505,6 +1512,7 @@
35828CA0217A003F00ED546E /* OfflineDirections.swift in Sources */,
2B5F0E02273BEB3600CC2C1A /* RoadClassExclusionViolation.swift in Sources */,
DAE7EA96230B5FD10003B211 /* Measurement.swift in Sources */,
2E44711927C4C80B0041CB84 /* SilentWaypoint.swift in Sources */,
C5DAACA020195AAF001F9261 /* Tracepoint.swift in Sources */,
2B9F3883272AE23A001DBA12 /* ProfileIdentifier.swift in Sources */,
431E93CD23466C2700A71B44 /* RouteResponse.swift in Sources */,
Expand Down Expand Up @@ -1599,6 +1607,7 @@
35828CA1217A003F00ED546E /* OfflineDirections.swift in Sources */,
2B5F0E03273BEB3600CC2C1A /* RoadClassExclusionViolation.swift in Sources */,
DAE7EA97230B5FD10003B211 /* Measurement.swift in Sources */,
2E44711A27C4C80B0041CB84 /* SilentWaypoint.swift in Sources */,
C5DAACA120195AAF001F9261 /* Tracepoint.swift in Sources */,
2B9F3884272AE23A001DBA12 /* ProfileIdentifier.swift in Sources */,
431E93CE23466C2800A71B44 /* RouteResponse.swift in Sources */,
Expand Down Expand Up @@ -1659,6 +1668,7 @@
35828C9E217A003F00ED546E /* OfflineDirections.swift in Sources */,
2B5F0E00273BEB3600CC2C1A /* RoadClassExclusionViolation.swift in Sources */,
DAE7EA94230B5FD10003B211 /* Measurement.swift in Sources */,
2E44711727C4C80B0041CB84 /* SilentWaypoint.swift in Sources */,
C59426071F1EA6C400C8E59C /* RoadClasses.swift in Sources */,
2B9F3881272AE23A001DBA12 /* ProfileIdentifier.swift in Sources */,
431E93CB23466C2400A71B44 /* RouteResponse.swift in Sources */,
Expand Down
19 changes: 19 additions & 0 deletions Sources/MapboxDirections/RouteLeg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ open class RouteLeg: Codable {
case annotation
case administrativeRegions = "admins"
case incidents
case viaWaypoints = "via_waypoints"
}

// MARK: Creating a Leg
Expand Down Expand Up @@ -85,6 +86,10 @@ open class RouteLeg: Codable {
if let incidents = try container.decodeIfPresent([Incident].self, forKey: .incidents) {
self.incidents = incidents
}

if let viaWaypoints = try container.decodeIfPresent([SilentWaypoint].self, forKey: .viaWaypoints) {
self.viaWaypoints = viaWaypoints
}
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -110,6 +115,10 @@ open class RouteLeg: Codable {
if let incidents = incidents {
try container.encode(incidents, forKey: .incidents)
}

if let viaWaypoints = viaWaypoints {
try container.encode(viaWaypoints, forKey: .viaWaypoints)
}
}

// MARK: Getting the Endpoints of the Leg
Expand Down Expand Up @@ -309,6 +318,13 @@ open class RouteLeg: Codable {
This property is set to `nil` if incidents data is not available.
*/
open var incidents: [Incident]?

/**
Describes where a particular `Waypoint` passed to `RouteOptions` matches to the route along a `RouteLeg`.
The property is non-nil when for one or several `Waypoint` objects passed to `RouteOptions` have `separatesLegs` property set to `false`.
*/
open var viaWaypoints: [SilentWaypoint]?

/**
The route leg’s typical travel time, measured in seconds.
Expand Down Expand Up @@ -343,6 +359,9 @@ extension RouteLeg: Equatable {
lhs.name == rhs.name &&
lhs.distance == rhs.distance &&
lhs.expectedTravelTime == rhs.expectedTravelTime &&
lhs.administrativeRegions == rhs.administrativeRegions &&
lhs.incidents == rhs.incidents &&
lhs.viaWaypoints == rhs.viaWaypoints &&
lhs.typicalTravelTime == rhs.typicalTravelTime &&
lhs.profileIdentifier == rhs.profileIdentifier
}
Expand Down
36 changes: 36 additions & 0 deletions Sources/MapboxDirections/SilentWaypoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Foundation

/**
Represents a silent waypoint along the `RouteLeg`.
See `RouteLeg.viaWaypoints` for more details.
*/
public struct SilentWaypoint: Codable, Equatable {
public enum CodingKeys: String, CodingKey {
case waypointIndex = "waypoint_index"
case distanceFromStart = "distance_from_start"
case shapeCoordinateIndex = "geometry_index"
}

/// The associated waypoint index in `RouteResponse.waypoints`, excluding the origin (index 0) and destination.
public var waypointIndex: Int

/// The calculated distance, in meters, from the leg origin.
public var distanceFromStart: Double

/// The associated `Route` shape index of the silent waypoint location.
public var shapeCoordinateIndex: Int

public init(waypointIndex: Int, distanceFromStart: Double, shapeCoordinateIndex: Int) {
self.waypointIndex = waypointIndex
self.distanceFromStart = distanceFromStart
self.shapeCoordinateIndex = shapeCoordinateIndex
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
waypointIndex = try container.decode(Int.self, forKey: .waypointIndex)
distanceFromStart = try container.decode(Double.self, forKey: .distanceFromStart)
shapeCoordinateIndex = try container.decode(Int.self, forKey: .shapeCoordinateIndex)
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"routes":[{"geometry":"ahboF~y`gOeA?k@?_@?O@I?S?c@?S?sC@K@S?wABaC?k@@QA?IA{D?iAAkDAQbB?fAAt@?h@AJ??O?oAAmB?K?kAAmDCaKA[AMCG?EIMMEo@@kBBsA@K??F@|@","legs":[{"summary":"Perlen Strasse, Haupt Strasse","weight":238.9,"duration":122.1,"steps":[{"intersections":[{"out":0,"entry":[true],"bearings":[0],"location":[-85.206241,39.33841]},{"out":0,"in":1,"entry":[true,false,true],"bearings":[0,180,240],"location":[-85.206241,39.338979]},{"out":0,"in":2,"entry":[true,true,false,true],"bearings":[0,90,180,270],"location":[-85.206244,39.339143]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[0,90,180],"location":[-85.206273,39.340549]}],"driving_side":"right","geometry":"ahboF~y`gOeA?k@?_@?O@I?S?c@?S?sC@K@S?wABaC?k@@QA","mode":"driving","maneuver":{"bearing_after":0,"bearing_before":0,"location":[-85.206241,39.33841],"type":"depart","instruction":"Fahren Sie Richtung Norden auf Maulbeerfeigen Strasse (SR 229)"},"ref":"SR 229","weight":38.1,"duration":25.6,"name":"Maulbeerfeigen Strasse (SR 229)","distance":393.3},{"intersections":[{"out":1,"in":2,"entry":[true,true,false,true],"bearings":[0,90,180,270],"location":[-85.206293,39.341945]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[90,180,270],"location":[-85.204929,39.341962]}],"driving_side":"right","geometry":"e~boFhz`gO?IA{D?iAAkDAQ","mode":"driving","maneuver":{"bearing_after":88,"bearing_before":358,"location":[-85.206293,39.341945],"modifier":"right","type":"turn","instruction":"Rechts abbiegen auf Weinstock Strasse"},"weight":32.9,"duration":19.9,"name":"Weinstock Strasse","distance":198.8},{"intersections":[{"out":2,"in":3,"entry":[true,true,true,false],"bearings":[0,90,180,270],"location":[-85.203982,39.341975]}],"driving_side":"right","geometry":"k~boFzk`gObB?fAAt@?h@AJ?","mode":"driving","maneuver":{"bearing_after":178,"bearing_before":88,"location":[-85.203982,39.341975],"modifier":"right","type":"turn","instruction":"Rechts abbiegen auf Perlen Strasse"},"weight":94.7,"duration":35.8,"name":"Perlen Strasse","distance":155.5},{"intersections":[{"out":1,"in":0,"entry":[false,true,true,true],"bearings":[0,90,180,270],"location":[-85.203962,39.340577]},{"out":1,"in":3,"entry":[true,true,true,false],"bearings":[0,90,180,270],"location":[-85.201616,39.3406]},{"out":0,"in":1,"entry":[true,false],"bearings":[75,255],"location":[-85.199436,39.340656]}],"driving_side":"right","geometry":"suboFvk`gO?O?oAAmB?K?kAAmDCaKA[AMCG?EIMMEo@@kBBsA@K?","mode":"driving","maneuver":{"bearing_after":88,"bearing_before":178,"location":[-85.203962,39.340577],"modifier":"left","type":"turn","instruction":"Links abbiegen auf Haupt Strasse (SR 229)"},"ref":"SR 229","weight":71.2,"duration":38.8,"name":"Haupt Strasse (SR 229)","distance":548.2},{"intersections":[{"out":2,"in":1,"entry":[true,false,true],"bearings":[0,180,270],"location":[-85.199353,39.342038]}],"driving_side":"right","geometry":"w~boF|n_gO?F@|@","mode":"driving","maneuver":{"bearing_after":268,"bearing_before":357,"location":[-85.199353,39.342038],"modifier":"left","type":"turn","instruction":"Links abbiegen auf Weinstock Strasse"},"weight":2,"duration":2,"name":"Weinstock Strasse","distance":29.6},{"intersections":[{"in":0,"entry":[true],"bearings":[89],"location":[-85.199697,39.342033]}],"driving_side":"right","geometry":"u~boFbq_gO","mode":"driving","maneuver":{"bearing_after":0,"bearing_before":269,"location":[-85.199697,39.342033],"type":"arrive","instruction":"Sie haben Ihr To"},"weight":0,"duration":0,"name":"Weinstock Strasse","distance":0}],"distance":1325.4}],"weight_name":"routability","weight":238.9,"duration":122.1,"distance":1325.4}],"waypoints":[{"distance":0.7760785081050579,"name":"Maulbeerfeigen Strasse","location":[-85.206241,39.33841]},{"distance":0.9485403982504417,"name":"Perlen Strasse","location":[-85.20398,39.34181]},{"distance":1.665293749024342,"name":"Weinstock Strasse","location":[-85.199697,39.342033]}],"code":"Ok","uuid":"cjslj6r7403r34jo289thx5ax"}
{"routes":[{"geometry":"ahboF~y`gOeA?k@?_@?O@I?S?c@?S?sC@K@S?wABaC?k@@QA?IA{D?iAAkDAQbB?fAAt@?h@AJ??O?oAAmB?K?kAAmDCaKA[AMCG?EIMMEo@@kBBsA@K??F@|@","legs":[{"summary":"Perlen Strasse, Haupt Strasse","weight":238.9,"duration":122.1,"via_waypoints":[{"waypoint_index":1,"distance_from_start":610.733,"geometry_index":21}],"steps":[{"intersections":[{"out":0,"entry":[true],"bearings":[0],"location":[-85.206241,39.33841]},{"out":0,"in":1,"entry":[true,false,true],"bearings":[0,180,240],"location":[-85.206241,39.338979]},{"out":0,"in":2,"entry":[true,true,false,true],"bearings":[0,90,180,270],"location":[-85.206244,39.339143]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[0,90,180],"location":[-85.206273,39.340549]}],"driving_side":"right","geometry":"ahboF~y`gOeA?k@?_@?O@I?S?c@?S?sC@K@S?wABaC?k@@QA","mode":"driving","maneuver":{"bearing_after":0,"bearing_before":0,"location":[-85.206241,39.33841],"type":"depart","instruction":"Fahren Sie Richtung Norden auf Maulbeerfeigen Strasse (SR 229)"},"ref":"SR 229","weight":38.1,"duration":25.6,"name":"Maulbeerfeigen Strasse (SR 229)","distance":393.3},{"intersections":[{"out":1,"in":2,"entry":[true,true,false,true],"bearings":[0,90,180,270],"location":[-85.206293,39.341945]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[90,180,270],"location":[-85.204929,39.341962]}],"driving_side":"right","geometry":"e~boFhz`gO?IA{D?iAAkDAQ","mode":"driving","maneuver":{"bearing_after":88,"bearing_before":358,"location":[-85.206293,39.341945],"modifier":"right","type":"turn","instruction":"Rechts abbiegen auf Weinstock Strasse"},"weight":32.9,"duration":19.9,"name":"Weinstock Strasse","distance":198.8},{"intersections":[{"out":2,"in":3,"entry":[true,true,true,false],"bearings":[0,90,180,270],"location":[-85.203982,39.341975]}],"driving_side":"right","geometry":"k~boFzk`gObB?fAAt@?h@AJ?","mode":"driving","maneuver":{"bearing_after":178,"bearing_before":88,"location":[-85.203982,39.341975],"modifier":"right","type":"turn","instruction":"Rechts abbiegen auf Perlen Strasse"},"weight":94.7,"duration":35.8,"name":"Perlen Strasse","distance":155.5},{"intersections":[{"out":1,"in":0,"entry":[false,true,true,true],"bearings":[0,90,180,270],"location":[-85.203962,39.340577]},{"out":1,"in":3,"entry":[true,true,true,false],"bearings":[0,90,180,270],"location":[-85.201616,39.3406]},{"out":0,"in":1,"entry":[true,false],"bearings":[75,255],"location":[-85.199436,39.340656]}],"driving_side":"right","geometry":"suboFvk`gO?O?oAAmB?K?kAAmDCaKA[AMCG?EIMMEo@@kBBsA@K?","mode":"driving","maneuver":{"bearing_after":88,"bearing_before":178,"location":[-85.203962,39.340577],"modifier":"left","type":"turn","instruction":"Links abbiegen auf Haupt Strasse (SR 229)"},"ref":"SR 229","weight":71.2,"duration":38.8,"name":"Haupt Strasse (SR 229)","distance":548.2},{"intersections":[{"out":2,"in":1,"entry":[true,false,true],"bearings":[0,180,270],"location":[-85.199353,39.342038]}],"driving_side":"right","geometry":"w~boF|n_gO?F@|@","mode":"driving","maneuver":{"bearing_after":268,"bearing_before":357,"location":[-85.199353,39.342038],"modifier":"left","type":"turn","instruction":"Links abbiegen auf Weinstock Strasse"},"weight":2,"duration":2,"name":"Weinstock Strasse","distance":29.6},{"intersections":[{"in":0,"entry":[true],"bearings":[89],"location":[-85.199697,39.342033]}],"driving_side":"right","geometry":"u~boFbq_gO","mode":"driving","maneuver":{"bearing_after":0,"bearing_before":269,"location":[-85.199697,39.342033],"type":"arrive","instruction":"Sie haben Ihr To"},"weight":0,"duration":0,"name":"Weinstock Strasse","distance":0}],"distance":1325.4}],"weight_name":"routability","weight":238.9,"duration":122.1,"distance":1325.4}],"waypoints":[{"distance":0.7760785081050579,"name":"Maulbeerfeigen Strasse","location":[-85.206241,39.33841]},{"distance":0.9485403982504417,"name":"Perlen Strasse","location":[-85.20398,39.34181]},{"distance":1.665293749024342,"name":"Weinstock Strasse","location":[-85.199697,39.342033]}],"code":"Ok","uuid":"cjslj6r7403r34jo289thx5ax"}
7 changes: 6 additions & 1 deletion Tests/MapboxDirectionsTests/V5Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class V5Tests: XCTestCase {
XCTAssertEqual(RouteShapeFormat.geoJSON.rawValue, "geojson")
test(shapeFormat: .geoJSON)
}

func testPolyline() {
XCTAssertEqual(RouteShapeFormat.polyline.rawValue, "polyline")
test(shapeFormat: .polyline)
Expand Down Expand Up @@ -279,6 +279,11 @@ class V5Tests: XCTestCase {
XCTAssertEqual(leg?.destination?.coordinate.latitude ?? 0, waypoints[2].coordinate.latitude, accuracy: 1e-4)
XCTAssertEqual(leg?.destination?.coordinate.longitude ?? 0, waypoints[2].coordinate.longitude, accuracy: 1e-4)
XCTAssertEqual(leg?.name, "Perlen Strasse, Haupt Strasse")
XCTAssertEqual(leg?.viaWaypoints!.count, 1)
let silentWaypoint = leg?.viaWaypoints?.first!
XCTAssertEqual(silentWaypoint?.waypointIndex, 1)
XCTAssertEqual(silentWaypoint?.distanceFromStart, 610.733)
XCTAssertEqual(silentWaypoint?.shapeCoordinateIndex, 21)
}

func testCoding() {
Expand Down

0 comments on commit 78f5e76

Please sign in to comment.