Skip to content

Commit 4e085fa

Browse files
authored
Add example of vanishing route line feature for eHorizon. (#175)
1 parent 03141bc commit 4e085fa

File tree

1 file changed

+66
-6
lines changed

1 file changed

+66
-6
lines changed

Navigation-Examples/Examples/Upcoming-Intersection.swift

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ class ElectronicHorizonEventsViewController: UIViewController {
1818
private let upcomingIntersectionLabel = UILabel()
1919
private let passiveLocationManager = PassiveLocationManager()
2020
private lazy var passiveLocationProvider = PassiveLocationProvider(locationManager: passiveLocationManager)
21+
private let routeLineColor: UIColor = .green.withAlphaComponent(0.9)
22+
private let traversedRouteColor: UIColor = .clear
23+
private var totalDistance: CLLocationDistance = 0.0
2124

2225
override func viewDidLoad() {
2326
super.viewDidLoad()
2427

2528
setupNavigationMapView()
2629
setupUpcomingIntersectionLabel()
27-
subscribeToElectronicHorizonUpdates()
30+
setupElectronicHorizonUpdates()
2831
}
2932

3033
func setupNavigationMapView() {
@@ -37,6 +40,13 @@ class ElectronicHorizonEventsViewController: UIViewController {
3740

3841
view.addSubview(navigationMapView)
3942
}
43+
44+
func setupElectronicHorizonUpdates() {
45+
// Customize the `ElectronicHorizonOptions` for `PassiveLocationManager` to start Electronic Horizon updates.
46+
let options = ElectronicHorizonOptions(length: 500, expansionLevel: 1, branchLength: 50, minTimeDeltaBetweenUpdates: nil)
47+
passiveLocationManager.startUpdatingElectronicHorizon(with: options)
48+
subscribeToElectronicHorizonUpdates()
49+
}
4050

4151
private func setupUpcomingIntersectionLabel() {
4252
upcomingIntersectionLabel.translatesAutoresizingMaskIntoConstraints = false
@@ -62,17 +72,27 @@ class ElectronicHorizonEventsViewController: UIViewController {
6272

6373
@objc private func didUpdateElectronicHorizonPosition(_ notification: Notification) {
6474
let horizonTreeKey = RoadGraph.NotificationUserInfoKey.treeKey
65-
guard let horizonTree = notification.userInfo?[horizonTreeKey] as? RoadGraph.Edge else {
75+
guard let horizonTree = notification.userInfo?[horizonTreeKey] as? RoadGraph.Edge,
76+
let position = notification.userInfo?[RoadGraph.NotificationUserInfoKey.positionKey] as? RoadGraph.Position,
77+
let updatesMostProbablePath = notification.userInfo?[RoadGraph.NotificationUserInfoKey.updatesMostProbablePathKey] as? Bool else {
6678
return
6779
}
6880

6981
let currentStreetName = streetName(for: horizonTree)
7082
let upcomingCrossStreet = nearestCrossStreetName(from: horizonTree)
7183
updateLabel(currentStreetName: currentStreetName, predictedCrossStreet: upcomingCrossStreet)
7284

73-
// Drawing the most probable path
74-
let mostProbablePath = routeLine(from: horizonTree, roadGraph: passiveLocationManager.roadGraph)
75-
updateMostProbablePath(with: mostProbablePath)
85+
// Update the most probable path when the position update indicates a new most probable path (MPP).
86+
if updatesMostProbablePath {
87+
let mostProbablePath = routeLine(from: horizonTree, roadGraph: passiveLocationManager.roadGraph)
88+
updateMostProbablePath(with: mostProbablePath)
89+
}
90+
91+
// Update the most probable path layer when the position update indicates
92+
// a change of the fraction of the point traveled distance to the current edge’s length.
93+
updateMostProbablePathLayer(fractionFromStart: position.fractionFromStart,
94+
roadGraph: passiveLocationManager.roadGraph,
95+
currentEdge: horizonTree.identifier)
7696
}
7797

7898
private func streetName(for edge: RoadGraph.Edge) -> String? {
@@ -123,10 +143,16 @@ class ElectronicHorizonEventsViewController: UIViewController {
123143
private func routeLine(from edge: RoadGraph.Edge, roadGraph: RoadGraph) -> [LocationCoordinate2D] {
124144
var coordinates = [LocationCoordinate2D]()
125145
var edge: RoadGraph.Edge? = edge
146+
totalDistance = 0.0
147+
148+
// Update the route line shape and total distance of the most propable path.
126149
while let currentEdge = edge {
127150
if let shape = roadGraph.edgeShape(edgeIdentifier: currentEdge.identifier) {
128151
coordinates.append(contentsOf: shape.coordinates.dropFirst(coordinates.isEmpty ? 0 : 1))
129152
}
153+
if let distance = roadGraph.edgeMetadata(edgeIdentifier: currentEdge.identifier)?.length {
154+
totalDistance += distance
155+
}
130156
edge = currentEdge.outletEdges.max(by: { $0.probability < $1.probability })
131157
}
132158
return coordinates
@@ -138,9 +164,22 @@ class ElectronicHorizonEventsViewController: UIViewController {
138164
geoJSON: .feature(feature))
139165
}
140166

167+
private func updateMostProbablePathLayer(fractionFromStart: Double,
168+
roadGraph: RoadGraph,
169+
currentEdge: RoadGraph.Edge.Identifier) {
170+
// Based on the length of current edge and the total distance of the most propable path (MPP),
171+
// calculate the fraction of the point traveled distance to the whole most propable path (MPP).
172+
if totalDistance > 0.0,
173+
let currentLength = roadGraph.edgeMetadata(edgeIdentifier: currentEdge)?.length {
174+
let fraction = fractionFromStart * currentLength / totalDistance
175+
updateMostProbablePathLayerFraction(fraction)
176+
}
177+
}
178+
141179
private func setupMostProbablePathStyle() {
142180
var source = GeoJSONSource()
143181
source.data = .geometry(Geometry.lineString(LineString([])))
182+
source.lineMetrics = true
144183
try? navigationMapView.mapView.mapboxMap.style.addSource(source, id: sourceIdentifier)
145184

146185
var layer = LineLayer(id: layerIdentifier)
@@ -152,10 +191,31 @@ class ElectronicHorizonEventsViewController: UIViewController {
152191
RouteLineWidthByZoomLevel.mapValues { $0 * 0.5 }
153192
}
154193
)
155-
layer.lineColor = .constant(.init(UIColor.green.withAlphaComponent(0.9)))
194+
layer.lineColor = .constant(.init(routeLineColor))
156195
layer.lineCap = .constant(.round)
157196
layer.lineJoin = .constant(.miter)
158197
layer.minZoom = 9
159198
try? navigationMapView.mapView.mapboxMap.style.addLayer(layer)
160199
}
200+
201+
// Update the line gradient property of the most probable path line layer,
202+
// so the part of the most probable path that has been traversed will be rendered with full transparency.
203+
private func updateMostProbablePathLayerFraction(_ fraction: Double) {
204+
let nextDown = max(fraction.nextDown, 0.0)
205+
let exp = Exp(.step) {
206+
Exp(.lineProgress)
207+
traversedRouteColor
208+
nextDown
209+
traversedRouteColor
210+
fraction
211+
routeLineColor
212+
}
213+
214+
if let data = try? JSONEncoder().encode(exp.self),
215+
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) {
216+
try? navigationMapView.mapView.mapboxMap.style.setLayerProperty(for: layerIdentifier,
217+
property: "line-gradient",
218+
value: jsonObject)
219+
}
220+
}
161221
}

0 commit comments

Comments
 (0)