Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to override congestion levels for specific road classes. #2741

Merged
merged 18 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
### Other changes

* The user can now report feedback about an incorrect speed limit in the speed limit view. ([#2725](https://github.com/mapbox/mapbox-navigation-ios/pull/2725))
* Added the `RouteProgress.upcomingRouteAlerts` property to track upcoming points along the route experiencing conditions that may require the user’s attention. The `UpcomingRouteAlertInfo.alert` property contains one of the following types with more details about the alert: `Incident`, `TunnelInfo`, `BorderCrossingInfo`, `TollCollection`, and `RestStop`. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694)
* Added the `RouteProgress.upcomingRouteAlerts` property to track upcoming points along the route experiencing conditions that may require the user’s attention. The `UpcomingRouteAlertInfo.alert` property contains one of the following types with more details about the alert: `Incident`, `TunnelInfo`, `BorderCrossingInfo`, `TollCollection`, and `RestStop`. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694))
* Added a new `NavigationMapView.roadClassesWithOverriddenCongestionLevels` property. For any road class in it all route segments with an `CongestionLevel.unknown` traffic congestion level and a matching `Intersection.outletMapboxStreetsRoadClass` will be replaced with the `CongestionLevel.low` congestion level. ([#2741](https://github.com/mapbox/mapbox-navigation-ios/pull/2741))
* Added a new `RouteLeg.streetsRoadClasses` property, which allows to get a collection of `MapboxStreetsRoadClass` objects for specific `RouteLeg`. ([#2741](https://github.com/mapbox/mapbox-navigation-ios/pull/2741))

## v1.1.0

Expand Down
1 change: 0 additions & 1 deletion Example/ViewController.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ class ViewController: UIViewController {

// Example of building highlighting in 3D.
navigationViewController.waypointStyle = .extrudedBuilding
navigationViewController.detailedFeedbackEnabled = true

// Show second level of detail for feedback items.
navigationViewController.detailedFeedbackEnabled = true
Expand Down
21 changes: 21 additions & 0 deletions MapboxCoreNavigation/RouteLeg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,25 @@ extension RouteLeg {
result.coordinates += (step.shape?.coordinates ?? []).dropFirst()
}
}

/**
Returns an array of `MapboxStreetsRoadClass` objects for specific leg. `MapboxStreetsRoadClass` will be set to `nil` if it's not present in `Intersection`.
*/
public var streetsRoadClasses: [MapboxStreetsRoadClass?] {
MaximAlien marked this conversation as resolved.
Show resolved Hide resolved
// Pick only valid segment indices for specific `Intersection` in `RouteStep`.
// Array of segment indexes can look like this: [0, 3, 24, 28, 48, 50, 51, 53].
let segmentIndices = steps.compactMap({ $0.segmentIndicesByIntersection?.compactMap({ $0 }) }).reduce([], +)

// Pick `MapboxStreetsRoadClass` in specific `Intersection` of `RouteStep`.
// It is expected that number of `segmentIndices` will be equal to number of `streetsRoadClassesInLeg`.
// Array of `MapboxStreetsRoadClass` can look like this: [Optional(motorway), ... , Optional(motorway), nil]
let streetsRoadClassesInLeg = steps.compactMap({ $0.intersections?.map({ $0.outletMapboxStreetsRoadClass }) }).reduce([], +)

// Map each `MapboxStreetsRoadClass` to the amount of two adjacent `segmentIndices`.
// At the end amount of `MapboxStreetsRoadClass` should be equal to the last segment index.
let streetsRoadClasses = segmentIndices.enumerated().map({ segmentIndices.indices.contains($0.offset + 1) && streetsRoadClassesInLeg.indices.contains($0.offset) ?
Array(repeating: streetsRoadClassesInLeg[$0.offset], count: segmentIndices[$0.offset + 1] - segmentIndices[$0.offset]) : [] }).reduce([], +)
Comment on lines +26 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a glance, it seems like this calculation would be simplified by zipping segmentIndices, but it’s hard to be sure. I’m a bit wary of the manual index arithmetic, but I trust you’ve already tested the multi-leg route edge case. I can’t think of any other edge cases at the moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tried several approaches with zipping and striding, but seems that it doesn't help to make this code more elegant and simple. I propose to move on with landing this PR so that we can start testing and I can follow-up with any better solutions in future PRs.


return streetsRoadClasses
}
}
20 changes: 20 additions & 0 deletions MapboxNavigation.xcodeproj/project.pbxproj
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@
64847A041F04629D003F3A69 /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64847A031F04629D003F3A69 /* Feedback.swift */; };
7C12F2D8225B7C320010A931 /* DCA-Arboretum-dummy-faster-route.json in Resources */ = {isa = PBXBuildFile; fileRef = 7C12F2D7225B7C310010A931 /* DCA-Arboretum-dummy-faster-route.json */; };
8AA849E924E722410008EE59 /* WaypointStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AA849E824E722410008EE59 /* WaypointStyle.swift */; };
8AC6191025881F8D00430AA8 /* route-with-mixed-road-classes.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AC6190B25881F8D00430AA8 /* route-with-mixed-road-classes.json */; };
8AC6191125881F8D00430AA8 /* route-with-missing-road-classes.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AC6190C25881F8D00430AA8 /* route-with-missing-road-classes.json */; };
8AC6191225881F8D00430AA8 /* route-with-not-present-road-classes.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AC6190D25881F8D00430AA8 /* route-with-not-present-road-classes.json */; };
8AC6191325881F8D00430AA8 /* route-with-road-classes-single-congestion.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AC6190E25881F8D00430AA8 /* route-with-road-classes-single-congestion.json */; };
8AC6191425881F8D00430AA8 /* route-with-same-congestion-different-road-classes.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AC6190F25881F8D00430AA8 /* route-with-same-congestion-different-road-classes.json */; };
8D07C5A820B612310093D779 /* EmptyStyle.json in Resources */ = {isa = PBXBuildFile; fileRef = 8D07C5A720B612310093D779 /* EmptyStyle.json */; };
8D1A5CD2212DDFCD0059BA4A /* DispatchTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D1A5CD1212DDFCD0059BA4A /* DispatchTimer.swift */; };
8D24A2F62040960C0098CBF8 /* UIEdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24A2F52040960C0098CBF8 /* UIEdgeInsets.swift */; };
Expand Down Expand Up @@ -881,6 +886,11 @@
64847A031F04629D003F3A69 /* Feedback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Feedback.swift; sourceTree = "<group>"; };
7C12F2D7225B7C310010A931 /* DCA-Arboretum-dummy-faster-route.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "DCA-Arboretum-dummy-faster-route.json"; sourceTree = "<group>"; };
8AA849E824E722410008EE59 /* WaypointStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaypointStyle.swift; sourceTree = "<group>"; };
8AC6190B25881F8D00430AA8 /* route-with-mixed-road-classes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "route-with-mixed-road-classes.json"; sourceTree = "<group>"; };
8AC6190C25881F8D00430AA8 /* route-with-missing-road-classes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "route-with-missing-road-classes.json"; sourceTree = "<group>"; };
8AC6190D25881F8D00430AA8 /* route-with-not-present-road-classes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "route-with-not-present-road-classes.json"; sourceTree = "<group>"; };
8AC6190E25881F8D00430AA8 /* route-with-road-classes-single-congestion.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "route-with-road-classes-single-congestion.json"; sourceTree = "<group>"; };
8AC6190F25881F8D00430AA8 /* route-with-same-congestion-different-road-classes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "route-with-same-congestion-different-road-classes.json"; sourceTree = "<group>"; };
8B808F852487CFEC00EEE453 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Main.strings; sourceTree = "<group>"; };
8B808F862487CFEC00EEE453 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Navigation.strings; sourceTree = "<group>"; };
8B808F892487CFEC00EEE453 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1239,6 +1249,11 @@
165F91502204D50B0036CB9E /* Fixtures */ = {
isa = PBXGroup;
children = (
8AC6190C25881F8D00430AA8 /* route-with-missing-road-classes.json */,
8AC6190B25881F8D00430AA8 /* route-with-mixed-road-classes.json */,
8AC6190D25881F8D00430AA8 /* route-with-not-present-road-classes.json */,
8AC6190E25881F8D00430AA8 /* route-with-road-classes-single-congestion.json */,
8AC6190F25881F8D00430AA8 /* route-with-same-congestion-different-road-classes.json */,
439FFC222304BC23004C20AA /* route-with-tertiary.json */,
35CDA8862190F50C0072B675 /* DCA-Arboretum.json */,
35C8DC0E2191DE940053328C /* DCA-Arboretum.trace.json */,
Expand Down Expand Up @@ -2260,28 +2275,33 @@
buildActionMask = 2147483647;
files = (
3557506D21A827E800AEF9B6 /* li.tar in Resources */,
8AC6191425881F8D00430AA8 /* route-with-same-congestion-different-road-classes.json in Resources */,
35CDA88D2190F5210072B675 /* DCA-Arboretum.json in Resources */,
35CDA8912190F6980072B675 /* route-for-lane-testing.json in Resources */,
B48CEFC125796FD300696BB3 /* route-for-vanishing-route-line.json in Resources */,
3557506F21A8293E00AEF9B6 /* tiles in Resources */,
35CDA8902190F6980072B675 /* route-doubling-back.json in Resources */,
35CDA8952190F6980072B675 /* route-with-straight-roundabout.json in Resources */,
35F9BC2F2296FCD300364A10 /* 9-legged-route.json in Resources */,
8AC6191225881F8D00430AA8 /* route-with-not-present-road-classes.json in Resources */,
35CDA8982190F6980072B675 /* turn_left.data in Resources */,
35CDA8962190F6980072B675 /* sthlm-double-back-replay.json in Resources */,
35CDA8922190F6980072B675 /* route-with-banner-instructions.json in Resources */,
35C8DBF42191937A0053328C /* routeWithInstructions.json in Resources */,
355832AD2192F7E300141922 /* PipeFittersUnion-FourSeasonsBoston.trace.json in Resources */,
35CDA8942190F6980072B675 /* route-with-lanes.json in Resources */,
8D86AE8C21C31F210064A304 /* waypoint-after-turn.json in Resources */,
8AC6191125881F8D00430AA8 /* route-with-missing-road-classes.json in Resources */,
35CDA8972190F6980072B675 /* sthlm-double-back.json in Resources */,
35CDA88F2190F6980072B675 /* EmptyStyle.json in Resources */,
35CDA8992190F6980072B675 /* UnionSquare-to-GGPark.route in Resources */,
357DEC44221AEE150019BAEC /* multileg-route.json in Resources */,
35C8DBF6219194380053328C /* routeWithTunnels_9thStreetDC.json in Resources */,
8AC6191025881F8D00430AA8 /* route-with-mixed-road-classes.json in Resources */,
35C8DBF52191940C0053328C /* straight-line.json in Resources */,
7C12F2D8225B7C320010A931 /* DCA-Arboretum-dummy-faster-route.json in Resources */,
4341758223060A17004264A9 /* route-with-tertiary.json in Resources */,
8AC6191325881F8D00430AA8 /* route-with-road-classes-single-congestion.json in Resources */,
35C8DC0F2191DE940053328C /* DCA-Arboretum.trace.json in Resources */,
35CDA8932190F6980072B675 /* route-with-instructions.json in Resources */,
35C8DBF8219198320053328C /* route.json in Resources */,
Expand Down
1 change: 0 additions & 1 deletion MapboxNavigation/DayStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ extension UIColor {
class var trafficModerate: UIColor { get { return #colorLiteral(red: 1, green: 0.5843137255, blue: 0, alpha: 1) } }
class var trafficHeavy: UIColor { get { return #colorLiteral(red: 1, green: 0.3019607843, blue: 0.3019607843, alpha: 1) } }
class var trafficSevere: UIColor { get { return #colorLiteral(red: 0.5607843137, green: 0.1411764706, blue: 0.2784313725, alpha: 1) } }
class var trafficAlternateLow: UIColor { get { return #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1) } }
MaximAlien marked this conversation as resolved.
Show resolved Hide resolved

class var defaultBuildingColor: UIColor { get { return #colorLiteral(red: 0.9833194452, green: 0.9843137255, blue: 0.9331936657, alpha: 0.8019049658) } }
class var defaultBuildingHighlightColor: UIColor { get { return #colorLiteral(red: 0.337254902, green: 0.6588235294, blue: 0.9843137255, alpha: 0.949406036) } }
Expand Down
50 changes: 43 additions & 7 deletions MapboxNavigation/NavigationMapView.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
*/
public var tapGestureDistanceThreshold: CGFloat = 50

/**
A collection of street road classes for which a congestion level substitution should occur.

For any street road class included in the `roadClassesWithOverriddenCongestionLevels`, all route segments with an `CongestionLevel.unknown` traffic congestion level and a matching `MapboxDirections.MapboxStreetsRoadClass`
will be replaced with the `CongestionLevel.low` congestion level.
*/
public var roadClassesWithOverriddenCongestionLevels: Set<MapboxStreetsRoadClass>? = nil

/**
The object that acts as the navigation delegate of the map view.
*/
Expand Down Expand Up @@ -1051,8 +1059,11 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {

return index == 0 ? stepCoordinates : allCoordinates + stepCoordinates.suffix(from: 1)
}

let mergedCongestionSegments = combine(legCoordinates, with: legCongestion)

let mergedCongestionSegments = combine(legCoordinates,
with: legCongestion,
streetsRoadClasses: leg.streetsRoadClasses,
roadClassesWithOverriddenCongestionLevels: roadClassesWithOverriddenCongestionLevels)

lines = mergedCongestionSegments.map { (congestionSegment: CongestionSegment) -> MGLPolylineFeature in
let polyline = MGLPolylineFeature(coordinates: congestionSegment.0, count: UInt(congestionSegment.0.count))
Expand Down Expand Up @@ -1084,20 +1095,45 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {

This method coalesces consecutive line segments that have the same congestion level.

- coordinates: The coordinates of a leg.
- congestions: The congestion levels along a leg. There should be one fewer congestion levels than coordinates.
For each item in the`CongestionSegment` collection a `CongestionLevel` substitution will take place that has a streets road class contained in the `roadClassesWithOverriddenCongestionLevels` collection.
For each of these items the `CongestionLevel` for `.unknown` traffic congestion will be replaced with the `.low` traffic congestion.

- parameter coordinates: The coordinates of a leg.
- parameter congestions: The congestion levels along a leg. There should be one fewer congestion levels than coordinates.
- parameter streetsRoadClasses: A collection of streets road classes for each geometry index in `Intersection`. There should be the same amount of `streetsRoadClasses` and `congestions`.
- parameter roadClassesWithOverriddenCongestionLevels: Streets road classes for which a `CongestionLevel` substitution should occur.
- returns: A list of `CongestionSegment` tuples with coordinate and congestion level.
*/
func combine(_ coordinates: [CLLocationCoordinate2D], with congestions: [CongestionLevel]) -> [CongestionSegment] {
func combine(_ coordinates: [CLLocationCoordinate2D],
with congestions: [CongestionLevel],
streetsRoadClasses: [MapboxStreetsRoadClass?]? = nil,
roadClassesWithOverriddenCongestionLevels: Set<MapboxStreetsRoadClass>? = nil) -> [CongestionSegment] {
var segments: [CongestionSegment] = []
segments.reserveCapacity(congestions.count)

var index = 0
for (firstSegment, congestionLevel) in zip(zip(coordinates, coordinates.suffix(from: 1)), congestions) {
let coordinates = [firstSegment.0, firstSegment.1]
if segments.last?.1 == congestionLevel {

var overriddenCongestionLevel = congestionLevel
if let streetsRoadClasses = streetsRoadClasses,
let roadClassesWithOverriddenCongestionLevels = roadClassesWithOverriddenCongestionLevels,
streetsRoadClasses.indices.contains(index),
let streetsRoadClass = streetsRoadClasses[index],
congestionLevel == .unknown,
roadClassesWithOverriddenCongestionLevels.contains(streetsRoadClass) {
overriddenCongestionLevel = .low
}

if segments.last?.1 == overriddenCongestionLevel {
segments[segments.count - 1].0 += coordinates
} else {
segments.append((coordinates, congestionLevel))
segments.append((coordinates, overriddenCongestionLevel))
}

index += 1
}

return segments
}

Expand Down
1 change: 0 additions & 1 deletion MapboxNavigation/RouteMapViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ class RouteMapViewController: UIViewController {
bottomContainer.backgroundColor = .clear

view.bringSubviewToFront(topBannerContainerView)

}

override func loadView() {
Expand Down
Loading