Skip to content
This repository has been archived by the owner on Mar 26, 2021. It is now read-only.

Commit

Permalink
Merge pull request mapbox#250 from mapbox/maxspeeds
Browse files Browse the repository at this point in the history
Serialize speed limit annotations
  • Loading branch information
1ec5 authored Dec 26, 2019
2 parents 4d91bb2 + 87ee659 commit 93a790a
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
* The `Intersection.approachIndex` and `Intersection.outletIndex` properties are now optional, not −1, in the case of a departure or arrival maneuver. ([#393](https://github.com/mapbox/MapboxDirections.swift/pull/393))
* Added initializers for `Route`, `Match`, `RouteLeg`, and `RouteStep`. ([#393](https://github.com/mapbox/MapboxDirections.swift/pull/393))
* Various properties of `Route`, `RouteLeg`, and `RouteStep` are now writable. ([#393](https://github.com/mapbox/MapboxDirections.swift/pull/393))
* Added `AttributeOptions.maximumSpeedLimit` for getting maximum posted speed limits in the `RouteLeg.segmentMaximumSpeedLimits` property. ([#367](https://github.com/mapbox/MapboxDirections.swift/pull/367))
* Added the `RouteLeg.segmentRangesByStep` property for more easily associating `RouteStep`s with the values in segment-based arrays such as `RouteLeg.segmentCongestionLevels`. ([#367](https://github.com/mapbox/MapboxDirections.swift/pull/367))

## v0.30.0

Expand Down
2 changes: 2 additions & 0 deletions Directions Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class ViewController: UIViewController, MBDrawingViewDelegate {
let wp2 = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House")
let options = RouteOptions(waypoints: [wp1, wp2])
options.includesSteps = true
options.routeShapeResolution = .full
options.attributeOptions = [.congestionLevel, .maximumSpeedLimit]

Directions.shared.calculate(options) { (waypoints, routes, error) in
if let error = error {
Expand Down
20 changes: 20 additions & 0 deletions MapboxDirections.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@
DA737EE41D05F91E005BDA16 /* v5_driving_dc_geojson.json in Resources */ = {isa = PBXBuildFile; fileRef = DA737EE31D05F91E005BDA16 /* v5_driving_dc_geojson.json */; };
DA737EE51D05F91E005BDA16 /* v5_driving_dc_geojson.json in Resources */ = {isa = PBXBuildFile; fileRef = DA737EE31D05F91E005BDA16 /* v5_driving_dc_geojson.json */; };
DA737EE61D05F91E005BDA16 /* v5_driving_dc_geojson.json in Resources */ = {isa = PBXBuildFile; fileRef = DA737EE31D05F91E005BDA16 /* v5_driving_dc_geojson.json */; };
DA8F3A7223B56D3B00B56786 /* RouteLegTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F3A7123B56D3B00B56786 /* RouteLegTests.swift */; };
DA8F3A7323B56D3B00B56786 /* RouteLegTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F3A7123B56D3B00B56786 /* RouteLegTests.swift */; };
DA8F3A7423B56D3B00B56786 /* RouteLegTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F3A7123B56D3B00B56786 /* RouteLegTests.swift */; };
DA9E1B131E5A675F0081EDC7 /* Polyline.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9E1B121E5A675F0081EDC7 /* Polyline.framework */; };
DAA76D681DD127CB0015EC78 /* LaneIndication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA76D671DD127CB0015EC78 /* LaneIndication.swift */; };
DAA76D691DD127CB0015EC78 /* LaneIndication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA76D671DD127CB0015EC78 /* LaneIndication.swift */; };
Expand Down Expand Up @@ -260,6 +263,10 @@
DAE33A1B1F215DF600C06039 /* IntersectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE33A1A1F215DF600C06039 /* IntersectionTests.swift */; };
DAE33A1C1F215DF600C06039 /* IntersectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE33A1A1F215DF600C06039 /* IntersectionTests.swift */; };
DAE33A1D1F215DF600C06039 /* IntersectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE33A1A1F215DF600C06039 /* IntersectionTests.swift */; };
DAE7EA94230B5FD10003B211 /* Measurement.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE7EA93230B5FD10003B211 /* Measurement.swift */; };
DAE7EA95230B5FD10003B211 /* Measurement.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE7EA93230B5FD10003B211 /* Measurement.swift */; };
DAE7EA96230B5FD10003B211 /* Measurement.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE7EA93230B5FD10003B211 /* Measurement.swift */; };
DAE7EA97230B5FD10003B211 /* Measurement.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE7EA93230B5FD10003B211 /* Measurement.swift */; };
DAE9E0F41EB7DE2E001E8E8B /* RouteOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE9E0F31EB7DE2E001E8E8B /* RouteOptionsTests.swift */; };
DAE9E0F51EB7DE2E001E8E8B /* RouteOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE9E0F31EB7DE2E001E8E8B /* RouteOptionsTests.swift */; };
DAE9E0F61EB7DE2E001E8E8B /* RouteOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE9E0F31EB7DE2E001E8E8B /* RouteOptionsTests.swift */; };
Expand All @@ -271,6 +278,7 @@
F448F8401DDCC709000BC343 /* Polyline.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F448F83C1DDCC6F3000BC343 /* Polyline.framework */; };
F448F8411DDCC70C000BC343 /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F448F83B1DDCC6F3000BC343 /* OHHTTPStubs.framework */; };
F448F8421DDCC70D000BC343 /* Polyline.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F448F83C1DDCC6F3000BC343 /* Polyline.framework */; };
F4B0022A22650A9F00CF44FF /* MapboxDirections.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA6C9D881CAE442B00094FBC /* MapboxDirections.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
F4D785EF1DDD82C100FF4665 /* RouteStepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D785EE1DDD82C100FF4665 /* RouteStepTests.swift */; };
F4D785F01DDD82C100FF4665 /* RouteStepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D785EE1DDD82C100FF4665 /* RouteStepTests.swift */; };
F4D785F11DDD82C100FF4665 /* RouteStepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D785EE1DDD82C100FF4665 /* RouteStepTests.swift */; };
Expand Down Expand Up @@ -314,6 +322,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
F4B0022A22650A9F00CF44FF /* MapboxDirections.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -389,6 +398,7 @@
DA6C9DAB1CAEC72800094FBC /* V5Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = V5Tests.swift; sourceTree = "<group>"; };
DA6C9DB11CAECA0E00094FBC /* Fixture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixture.swift; sourceTree = "<group>"; };
DA737EE31D05F91E005BDA16 /* v5_driving_dc_geojson.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = v5_driving_dc_geojson.json; sourceTree = "<group>"; };
DA8F3A7123B56D3B00B56786 /* RouteLegTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteLegTests.swift; sourceTree = "<group>"; };
DA9E1B121E5A675F0081EDC7 /* Polyline.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Polyline.framework; path = Carthage/Build/watchOS/Polyline.framework; sourceTree = "<group>"; };
DAA76D671DD127CB0015EC78 /* LaneIndication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaneIndication.swift; sourceTree = "<group>"; };
DAABF78D2395ABA900CEEB61 /* SpokenInstructionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpokenInstructionTests.swift; sourceTree = "<group>"; };
Expand All @@ -411,6 +421,7 @@
DAE2DF6723AECB120065057A /* QuickLookTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickLookTests.swift; sourceTree = "<group>"; };
DAE2DF6B23AED2280065057A /* RouteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteTests.swift; sourceTree = "<group>"; };
DAE33A1A1F215DF600C06039 /* IntersectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntersectionTests.swift; sourceTree = "<group>"; };
DAE7EA93230B5FD10003B211 /* Measurement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Measurement.swift; sourceTree = "<group>"; };
DAE9E0F31EB7DE2E001E8E8B /* RouteOptionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RouteOptionsTests.swift; path = Tests/MapboxDirectionsTests/RouteOptionsTests.swift; sourceTree = SOURCE_ROOT; };
DD6254731AE70CB700017857 /* Directions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Directions.swift; sourceTree = "<group>"; };
F448F82A1DDCC5B6000BC343 /* Polyline.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Polyline.framework; path = Carthage/Build/iOS/Polyline.framework; sourceTree = "<group>"; };
Expand Down Expand Up @@ -540,6 +551,7 @@
8D434678219E1167008B7BF3 /* Double.swift */,
43208BAA2343F81900D8BD89 /* GeoJSON.swift */,
35DBF00E217E17A30009D2AE /* HTTPURLResponse.swift */,
DAE7EA93230B5FD10003B211 /* Measurement.swift */,
8D381B691FDB101F008D5A58 /* String.swift */,
);
path = Extensions;
Expand Down Expand Up @@ -646,6 +658,7 @@
DAE2DF6723AECB120065057A /* QuickLookTests.swift */,
C59666382048A20E00C45CE5 /* RoutableMatchTests.swift */,
DAE2DF6B23AED2280065057A /* RouteTests.swift */,
DA8F3A7123B56D3B00B56786 /* RouteLegTests.swift */,
DAE9E0F31EB7DE2E001E8E8B /* RouteOptionsTests.swift */,
F4D785EE1DDD82C100FF4665 /* RouteStepTests.swift */,
DAABF78D2395ABA900CEEB61 /* SpokenInstructionTests.swift */,
Expand Down Expand Up @@ -1170,6 +1183,7 @@
DA1A10C91D00F969009F82FA /* RouteLeg.swift in Sources */,
C52552BA1FA15D5E00B1545C /* VisualInstructionBanner.swift in Sources */,
35828C9F217A003F00ED546E /* OfflineDirections.swift in Sources */,
DAE7EA95230B5FD10003B211 /* Measurement.swift in Sources */,
C5DAAC9F20195AAE001F9261 /* Tracepoint.swift in Sources */,
431E93CC23466C2500A71B44 /* RouteResponse.swift in Sources */,
431E93C423466B0F00A71B44 /* GeoJSON.swift in Sources */,
Expand Down Expand Up @@ -1212,6 +1226,7 @@
DA688B3F21B89ECD00C9BB25 /* VisualInstructionComponentTests.swift in Sources */,
DAD06E36239F0B19001A917D /* DirectionsErrorTests.swift in Sources */,
C596663A2048AECD00C45CE5 /* RoutableMatchTests.swift in Sources */,
DA8F3A7323B56D3B00B56786 /* RouteLegTests.swift in Sources */,
DA1A10CD1D00F972009F82FA /* V5Tests.swift in Sources */,
DAE33A1C1F215DF600C06039 /* IntersectionTests.swift in Sources */,
C5DAACB0201AA92B001F9261 /* MatchTests.swift in Sources */,
Expand Down Expand Up @@ -1241,6 +1256,7 @@
DA1A10EF1D010247009F82FA /* RouteLeg.swift in Sources */,
C52552BB1FA15D5F00B1545C /* VisualInstructionBanner.swift in Sources */,
35828CA0217A003F00ED546E /* OfflineDirections.swift in Sources */,
DAE7EA96230B5FD10003B211 /* Measurement.swift in Sources */,
C5DAACA020195AAF001F9261 /* Tracepoint.swift in Sources */,
431E93CD23466C2700A71B44 /* RouteResponse.swift in Sources */,
431E93C523466B1000A71B44 /* GeoJSON.swift in Sources */,
Expand Down Expand Up @@ -1283,6 +1299,7 @@
DA688B4021B89ECD00C9BB25 /* VisualInstructionComponentTests.swift in Sources */,
DAD06E37239F0B19001A917D /* DirectionsErrorTests.swift in Sources */,
C596663B2048AECE00C45CE5 /* RoutableMatchTests.swift in Sources */,
DA8F3A7423B56D3B00B56786 /* RouteLegTests.swift in Sources */,
DA1A10F41D010251009F82FA /* V5Tests.swift in Sources */,
DAE33A1D1F215DF600C06039 /* IntersectionTests.swift in Sources */,
C5DAACB1201AA92B001F9261 /* MatchTests.swift in Sources */,
Expand Down Expand Up @@ -1312,6 +1329,7 @@
DA1A11061D0103A3009F82FA /* RouteLeg.swift in Sources */,
C52552BC1FA15D6000B1545C /* VisualInstructionBanner.swift in Sources */,
35828CA1217A003F00ED546E /* OfflineDirections.swift in Sources */,
DAE7EA97230B5FD10003B211 /* Measurement.swift in Sources */,
C5DAACA120195AAF001F9261 /* Tracepoint.swift in Sources */,
431E93CE23466C2800A71B44 /* RouteResponse.swift in Sources */,
431E93C623466B1100A71B44 /* GeoJSON.swift in Sources */,
Expand Down Expand Up @@ -1356,6 +1374,7 @@
43F89F98235778DE007B591E /* MapMatchingResponse.swift in Sources */,
C52552B91FA15D5900B1545C /* VisualInstructionBanner.swift in Sources */,
35828C9E217A003F00ED546E /* OfflineDirections.swift in Sources */,
DAE7EA94230B5FD10003B211 /* Measurement.swift in Sources */,
C59426071F1EA6C400C8E59C /* RoadClasses.swift in Sources */,
431E93CB23466C2400A71B44 /* RouteResponse.swift in Sources */,
431E93C323466B0E00A71B44 /* GeoJSON.swift in Sources */,
Expand Down Expand Up @@ -1398,6 +1417,7 @@
DA688B3E21B89ECD00C9BB25 /* VisualInstructionComponentTests.swift in Sources */,
DAD06E35239F0B19001A917D /* DirectionsErrorTests.swift in Sources */,
C59666392048A20E00C45CE5 /* RoutableMatchTests.swift in Sources */,
DA8F3A7223B56D3B00B56786 /* RouteLegTests.swift in Sources */,
DA6C9DAC1CAEC72800094FBC /* V5Tests.swift in Sources */,
DAE33A1B1F215DF600C06039 /* IntersectionTests.swift in Sources */,
C5DAACAF201AA92B001F9261 /* MatchTests.swift in Sources */,
Expand Down
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import PackageDescription

let package = Package(
name: "MapboxDirections",
platforms: [
.macOS(.v10_12), .iOS(.v10), .watchOS(.v4), .tvOS(.v12)
],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
Expand Down
12 changes: 12 additions & 0 deletions Sources/MapboxDirections/AttributeOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ public struct AttributeOptions: OptionSet, CustomStringConvertible {
*/
public static let congestionLevel = AttributeOptions(rawValue: 1 << 4)

/**
The maximum speed limit along the segment.
When this attribute is specified, the `RouteLeg.segmentMaximumSpeedLimits` property contains one value for each segment in the leg’s full geometry.
*/
public static let maximumSpeedLimit = AttributeOptions(rawValue: 1 << 5)

/**
Creates an AttributeOptions from the given description strings.
*/
Expand All @@ -57,6 +64,8 @@ public struct AttributeOptions: OptionSet, CustomStringConvertible {
attributeOptions.update(with: .speed)
case "congestion":
attributeOptions.update(with: .congestionLevel)
case "maxspeed":
attributeOptions.update(with: .maximumSpeedLimit)
case "":
continue
default:
Expand All @@ -80,6 +89,9 @@ public struct AttributeOptions: OptionSet, CustomStringConvertible {
if contains(.congestionLevel) {
descriptions.append("congestion")
}
if contains(.maximumSpeedLimit) {
descriptions.append("maxspeed")
}
return descriptions.joined(separator: ",")
}
}
Expand Down
100 changes: 100 additions & 0 deletions Sources/MapboxDirections/Extensions/Measurement.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Foundation

enum SpeedLimitDescriptor: Equatable {
enum UnitDescriptor: String, Codable {
case milesPerHour = "mph"
case kilometersPerHour = "km/h"

init?(unit: UnitSpeed) {
switch unit {
case .milesPerHour:
self = .milesPerHour
case .kilometersPerHour:
self = .kilometersPerHour
default:
return nil
}
}

var describedUnit: UnitSpeed {
switch self {
case .milesPerHour:
return .milesPerHour
case .kilometersPerHour:
return .kilometersPerHour
}
}
}

enum CodingKeys: String, CodingKey {
case none
case speed
case unknown
case unit
}

case none
case some(speed: Measurement<UnitSpeed>)
case unknown

init(speed: Measurement<UnitSpeed>?) {
guard let speed = speed else {
self = .unknown
return
}

if speed.value.isInfinite {
self = .none
} else {
self = .some(speed: speed)
}
}
}

extension SpeedLimitDescriptor: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

if (try container.decodeIfPresent(Bool.self, forKey: .none)) ?? false {
self = .none
} else if (try container.decodeIfPresent(Bool.self, forKey: .unknown)) ?? false {
self = .unknown
} else {
let unitDescriptor = try container.decode(UnitDescriptor.self, forKey: .unit)
let unit = unitDescriptor.describedUnit
let value = try container.decode(Double.self, forKey: .speed)
self = .some(speed: .init(value: value, unit: unit))
}
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

switch self {
case .none:
try container.encode(true, forKey: .none)
case .some(var speed):
let unitDescriptor = UnitDescriptor(unit: speed.unit) ?? {
speed = speed.converted(to: .kilometersPerHour)
return .kilometersPerHour
}()
try container.encode(unitDescriptor, forKey: .unit)
try container.encode(speed.value, forKey: .speed)
case .unknown:
try container.encode(true, forKey: .unknown)
}
}
}

extension Measurement where UnitType == UnitSpeed {
init?(speedLimitDescriptor: SpeedLimitDescriptor) {
switch speedLimitDescriptor {
case .none:
self = .init(value: .infinity, unit: .kilometersPerHour)
case .some(let speed):
self = speed
case .unknown:
return nil
}
}
}
Loading

0 comments on commit 93a790a

Please sign in to comment.