@@ -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