Skip to content

Commit a8e4e59

Browse files
committed
Show the traffic devices on current route step during active navigation only.
1 parent a87bd97 commit a8e4e59

10 files changed

+93
-69
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* Fixed an issue where tapping on a route duration annotation that overlaps a different route would cause the wrong route to be passed into `NavigationMapViewDelegate.navigationMapView(_:didSelect:)` or `NavigationMapViewDelegate.navigationMapView(_:didSelect:)`. ([#4133](https://github.com/mapbox/mapbox-navigation-ios/pull/4133))
2222
* Fixed an issue where the shields in the instruction are using the style from last navigation session with the `NavigationMapView` injection used in the new session. ([#4197](https://github.com/mapbox/mapbox-navigation-ios/pull/4197))
2323
* Fixed an issue where the `NavigationMapView.localizeLabels()` method only localized map labels according to the user’s Preferred Language Order setting if the application also had a localization in the preferred language. ([#4205](https://github.com/mapbox/mapbox-navigation-ios/pull/4205))
24-
* Added `NavigationMapView.showsIntersectionSignalsOnRoutes` to annotate traffic control devices along the current route line. ([#4185](https://github.com/mapbox/mapbox-navigation-ios/pull/4185))
24+
* Added `NavigationMapView.showsIntersectionSignals`, `NavigationMapView.showIntersectionSignals(with:)` and `NavigationMapView.removeIntersectionSignals()` to annotate traffic control devices on the current route step during active navigation. ([#4185](https://github.com/mapbox/mapbox-navigation-ios/pull/4185))
2525

2626
### Banners and guidance instructions
2727

Example/AppDelegate+CarPlay.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ extension AppDelegate: CarPlayManagerDelegate {
9292
// Render part of the route that has been traversed with full transparency, to give the illusion of a disappearing route.
9393
navigationViewController.routeLineTracksTraversal = true
9494
navigationViewController.navigationMapView?.showsRestrictedAreasOnRoute = true
95-
navigationViewController.navigationMapView?.showsIntersectionSignalsOnRoutes = true
95+
navigationViewController.navigationMapView?.showsIntersectionSignals = true
9696

9797
// Example of building highlighting in 3D.
9898
navigationViewController.waypointStyle = .extrudedBuilding

Example/CustomViewController.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class CustomViewController: UIViewController {
6767
// By setting the `NavigationMapView.routeLineTracksTraversal` to `true`, it would allow the main route shown with
6868
// traversed part disappearing effect in a standalone `NavigationMapView` during active navigation.
6969
self.navigationMapView.routeLineTracksTraversal = true
70+
self.navigationMapView.showsIntersectionSignals = true
7071
if self.navigationMapView.mapView.mapboxMap.style.layerExists(withId: "road-intersection") {
7172
// Provide the custom layer position for route line in active navigation.
7273
self.navigationMapView.show([self.navigationService.route], layerPosition: .below("road-intersection") ,legIndex: 0)
@@ -151,6 +152,9 @@ class CustomViewController: UIViewController {
151152
// without redrawing the main route.
152153
navigationMapView.updateRouteLine(routeProgress: routeProgress, coordinate: location.coordinate, shouldRedraw: routeProgress.legIndex != currentLegIndex)
153154
currentLegIndex = routeProgress.legIndex
155+
156+
// Add intersection signals
157+
navigationMapView.showIntersectionSignals(with: routeProgress)
154158
}
155159

156160
@objc func updateInstructionsBanner(notification: NSNotification) {
@@ -173,6 +177,8 @@ class CustomViewController: UIViewController {
173177
navigationMapView.updateRouteLine(routeProgress: navigationService.routeProgress,
174178
coordinate: navigationService.router.location?.coordinate,
175179
shouldRedraw: true)
180+
181+
navigationMapView.showIntersectionSignals(with: navigationService.routeProgress)
176182
}
177183

178184
@objc func refresh(_ notification: NSNotification) {

Example/ViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ class ViewController: UIViewController {
666666
self.navigationMapView = nil
667667
self.passiveLocationManager = nil
668668
navigationViewController.navigationMapView?.showsRestrictedAreasOnRoute = true
669-
navigationViewController.navigationMapView?.showsIntersectionSignalsOnRoutes = true
669+
navigationViewController.navigationMapView?.showsIntersectionSignals = true
670670

671671
// Animate top and bottom banner views presentation.
672672
navigationViewController.navigationView.bottomBannerContainerView.show(duration: 1.0,

Sources/MapboxNavigation/CarPlayNavigationViewController.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,8 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
779779

780780
navigationMapView?.updateRouteLine(routeProgress: routeProgress, coordinate: location.coordinate, shouldRedraw: legIndex != currentLegIndexMapped)
781781
currentLegIndexMapped = legIndex
782+
783+
navigationMapView?.showIntersectionSignals(with: routeProgress)
782784
}
783785

784786
private func checkTunnelState(at location: CLLocation, along progress: RouteProgress) {
@@ -872,6 +874,8 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
872874
navigationMapView?.removeArrow()
873875
}
874876
navigationMapView?.showWaypoints(on: progress.route, legIndex: legIndex)
877+
878+
navigationMapView?.showIntersectionSignals(with: progress)
875879
}
876880

877881
func updateManeuvers(_ routeProgress: RouteProgress) {

Sources/MapboxNavigation/NavigationMapView+Annotations.swift

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -395,35 +395,10 @@ extension NavigationMapView {
395395

396396
// MARK: Intersection Signals Annotations
397397

398-
/**
399-
Removes all intersection signals on current route.
400-
*/
401-
func removeIntersectionSignals() {
402-
let style = mapView.mapboxMap.style
403-
style.removeLayers([NavigationMapView.LayerIdentifier.intersectionSignalLayer])
404-
style.removeSources([NavigationMapView.SourceIdentifier.intersectionSignalSource])
405-
}
406-
407-
func updateIntersectionSignalsAlongRouteOnMap(styleType: StyleType = .day) {
408-
guard showsIntersectionSignalsOnRoutes, let route = routes?.first else {
409-
removeIntersectionSignals()
410-
return
411-
}
412-
413-
do {
414-
try updateIntersectionSymbolImages()
415-
} catch {
416-
Log.error("Error occured while updating intersection signal images: \(error.localizedDescription).",
417-
category: .navigationUI)
418-
}
419-
420-
updateIntersectionSignals(along: route, styleType: styleType)
421-
}
422-
423398
/**
424399
Updates the image assets in the map style for the route intersection signals.
425400
*/
426-
private func updateIntersectionSymbolImages() throws {
401+
func updateIntersectionSymbolImages() throws {
427402
let style = mapView.mapboxMap.style
428403

429404
if style.image(withId: ImageIdentifier.trafficSignalDay) == nil,
@@ -447,15 +422,20 @@ extension NavigationMapView {
447422
}
448423
}
449424

450-
private func updateIntersectionSignals(along route: Route, styleType: StyleType) {
425+
func updateIntersectionSignals(with routeProgress: RouteProgress) {
426+
guard !routeProgress.routeIsComplete else {
427+
removeIntersectionSignals()
428+
return
429+
}
451430
var featureCollection = FeatureCollection(features: [])
452-
for leg in route.legs {
453-
for step in leg.steps {
454-
guard let intersections = step.intersections else { continue }
455-
for intersection in intersections {
456-
guard let feature = signalFeature(from: intersection, styleType: styleType) else { continue }
457-
featureCollection.features.append(feature)
458-
}
431+
432+
let stepProgress = routeProgress.currentLegProgress.currentStepProgress
433+
let intersectionIndex = stepProgress.intersectionIndex
434+
let stepIntersections = stepProgress.intersectionsIncludingUpcomingManeuverIntersection
435+
436+
for intersection in stepIntersections?.suffix(from: intersectionIndex) ?? [] {
437+
if let feature = signalFeature(from: intersection, styleType: styleType) {
438+
featureCollection.features.append(feature)
459439
}
460440
}
461441

@@ -472,14 +452,9 @@ extension NavigationMapView {
472452
}
473453

474454
let layerIdentifier = NavigationMapView.LayerIdentifier.intersectionSignalLayer
475-
var shapeLayer: SymbolLayer
476-
if style.layerExists(withId: layerIdentifier),
477-
let symbolLayer = try style.layer(withId: layerIdentifier) as? SymbolLayer {
478-
shapeLayer = symbolLayer
479-
} else {
480-
shapeLayer = SymbolLayer(id: layerIdentifier)
481-
}
455+
guard !style.layerExists(withId: layerIdentifier) else { return }
482456

457+
var shapeLayer = SymbolLayer(id: layerIdentifier)
483458
shapeLayer.source = sourceIdentifier
484459
shapeLayer.iconAllowOverlap = .constant(false)
485460
shapeLayer.iconImage = .expression(Exp(.get) {

Sources/MapboxNavigation/NavigationMapView.swift

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ open class NavigationMapView: UIView {
264264
customRouteLineLayerPosition = layerPosition
265265

266266
applyRoutesDisplay(layerPosition: layerPosition)
267-
updateIntersectionSignalsAlongRouteOnMap(styleType: styleType)
268267
}
269268

270269
func applyRoutesDisplay(layerPosition: MapboxMaps.LayerPosition? = nil) {
@@ -352,7 +351,6 @@ open class NavigationMapView: UIView {
352351

353352
routes = nil
354353
removeLineGradientStops()
355-
removeIntersectionSignals()
356354
}
357355

358356
/**
@@ -1128,23 +1126,42 @@ open class NavigationMapView: UIView {
11281126
}
11291127

11301128
/**
1131-
Shows the intersection signals on current route.
1129+
Show the signals on the intersections.
1130+
1131+
- parameter routeProgress: The `RouteProgress` that the intersections will be displayed with.
11321132
*/
1133-
public var showsIntersectionSignalsOnRoutes: Bool = false {
1134-
didSet {
1135-
updateIntersectionSignalsAlongRouteOnMap(styleType: styleType)
1133+
public func showIntersectionSignals(with routeProgress: RouteProgress) {
1134+
guard showsIntersectionSignals else {
1135+
removeIntersectionSignals()
1136+
return
1137+
}
1138+
1139+
do {
1140+
try updateIntersectionSymbolImages()
1141+
} catch {
1142+
Log.error("Error occured while updating intersection signal images: \(error.localizedDescription).",
1143+
category: .navigationUI)
11361144
}
1145+
1146+
updateIntersectionSignals(with: routeProgress)
11371147
}
11381148

11391149
/**
1140-
The style type of `NavigationMapView` during active navigation.
1150+
Shows the intersection signals on current step of current route during active navigation.
11411151
*/
1142-
var styleType: StyleType = .day {
1152+
public var showsIntersectionSignals: Bool = false {
11431153
didSet {
1144-
updateIntersectionSignalsAlongRouteOnMap(styleType: styleType)
1154+
if !showsIntersectionSignals {
1155+
removeIntersectionSignals()
1156+
}
11451157
}
11461158
}
11471159

1160+
/**
1161+
The style type of `NavigationMapView` during active navigation.
1162+
*/
1163+
var styleType: StyleType = .day
1164+
11481165
let continuousAlternativeDurationAnnotationOffset: LocationDistance = 75
11491166

11501167
/**
@@ -1475,11 +1492,11 @@ open class NavigationMapView: UIView {
14751492
route?.identifier(.restrictedRouteAreaRoute)
14761493
].compactMap{ $0 }
14771494
let arrowLayers: [String] = [
1478-
LayerIdentifier.intersectionSignalLayer,
14791495
LayerIdentifier.arrowStrokeLayer,
14801496
LayerIdentifier.arrowLayer,
14811497
LayerIdentifier.arrowSymbolCasingLayer,
1482-
LayerIdentifier.arrowSymbolLayer
1498+
LayerIdentifier.arrowSymbolLayer,
1499+
LayerIdentifier.intersectionSignalLayer
14831500
]
14841501
let uppermostSymbolLayers: [String] = [
14851502
LayerIdentifier.waypointCircleLayer,

Sources/MapboxNavigation/RouteLineController.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ extension NavigationMapView {
5454
if annotatesSpokenInstructions {
5555
navigationMapView.showVoiceInstructionsOnMap(route: router.route)
5656
}
57+
58+
navigationMapView.showIntersectionSignals(with: router.routeProgress)
5759
}
5860

5961
func navigationViewDidAppear(_ animated: Bool) {
@@ -88,6 +90,8 @@ extension NavigationMapView {
8890
if annotatesSpokenInstructions {
8991
navigationMapView.showVoiceInstructionsOnMap(route: route)
9092
}
93+
94+
navigationMapView.showIntersectionSignals(with: router.routeProgress)
9195
}
9296

9397
func navigationService(_ service: NavigationService, didUpdate progress: RouteProgress, with location: CLLocation, rawLocation: CLLocation) {
@@ -111,6 +115,8 @@ extension NavigationMapView {
111115

112116
navigationMapView.updateRouteLine(routeProgress: progress, coordinate: location.coordinate, shouldRedraw: currentLegIndexMapped != legIndex)
113117
currentLegIndexMapped = legIndex
118+
119+
navigationMapView.showIntersectionSignals(with: router.routeProgress)
114120
}
115121

116122
private func updateMapOverlays(for routeProgress: RouteProgress) {

Tests/MapboxNavigationTests/NavigationMapViewTests.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ class NavigationMapViewTests: TestCase {
1313
]))
1414
var navigationMapView: NavigationMapView!
1515

16+
let options: NavigationRouteOptions = .init(coordinates: [
17+
CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926),
18+
CLLocationCoordinate2D(latitude: 29.99908, longitude: -102.828197)])
19+
1620
lazy var route: Route = {
1721
let route = response.routes!.first!
1822
return route
@@ -493,23 +497,27 @@ class NavigationMapViewTests: TestCase {
493497

494498
func testUpdateIntersectionSignalsAlongRouteOnMap() {
495499
let navigationMapView = NavigationMapView(frame: CGRect(origin: .zero, size: .iPhone6Plus))
500+
let style = navigationMapView.mapView.mapboxMap.style
496501
let imageIdentifier = NavigationMapView.ImageIdentifier.trafficSignalDay
497502
let layerIdentifier = NavigationMapView.LayerIdentifier.intersectionSignalLayer
498-
let style = navigationMapView.mapView.mapboxMap.style
503+
let sourceIdentifier = NavigationMapView.SourceIdentifier.intersectionSignalSource
499504

500-
XCTAssertFalse(navigationMapView.showsIntersectionSignalsOnRoutes)
501-
502-
let route = loadRoute(from: "route-with-mixed-road-classes")
503-
navigationMapView.show([route])
505+
XCTAssertFalse(navigationMapView.showsIntersectionSignals)
504506
XCTAssertFalse(style.imageExists(withId: imageIdentifier))
505507
XCTAssertFalse(style.layerExists(withId: layerIdentifier))
508+
XCTAssertFalse(style.sourceExists(withId: sourceIdentifier))
509+
510+
let routeProgress = RouteProgress(route: route, options: options, legIndex: 0, spokenInstructionIndex: 0)
511+
navigationMapView.showsIntersectionSignals = true
512+
navigationMapView.showIntersectionSignals(with: routeProgress)
506513

507-
navigationMapView.showsIntersectionSignalsOnRoutes = true
508514
XCTAssertTrue(style.imageExists(withId: imageIdentifier))
509515
XCTAssertTrue(style.layerExists(withId: layerIdentifier))
516+
XCTAssertTrue(style.sourceExists(withId: sourceIdentifier))
510517

511-
navigationMapView.removeRoutes()
518+
navigationMapView.removeIntersectionSignals()
512519
XCTAssertTrue(style.imageExists(withId: imageIdentifier))
513520
XCTAssertFalse(style.layerExists(withId: layerIdentifier))
521+
XCTAssertFalse(style.sourceExists(withId: sourceIdentifier))
514522
}
515523
}

Tests/MapboxNavigationTests/RouteLineLayerPositionTests.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ import MapboxMaps
66
@testable import MapboxCoreNavigation
77

88
class RouteLineLayerPositionTests: TestCase {
9+
let options: NavigationRouteOptions = NavigationRouteOptions(coordinates: [
10+
CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926),
11+
CLLocationCoordinate2D(latitude: 29.99908, longitude: -102.828197)])
912

1013
lazy var route: Route = {
11-
let response = Fixture.routeResponse(from: "route-with-instructions", options: NavigationRouteOptions(coordinates: [
12-
CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926),
13-
CLLocationCoordinate2D(latitude: 29.99908, longitude: -102.828197),
14-
]))
14+
let response = Fixture.routeResponse(from: "route-with-instructions", options: options)
1515
return response.routes!.first!
1616
}()
1717

18+
lazy var routeProgress: RouteProgress = {
19+
let routeProgress = RouteProgress(route: route, options: options, legIndex: 0, spokenInstructionIndex: 0)
20+
return routeProgress
21+
}()
22+
1823
func testRouteLineLayerPosition() {
1924

2025
let navigationMapView = NavigationMapView(frame: UIScreen.main.bounds)
@@ -239,7 +244,8 @@ class RouteLineLayerPositionTests: TestCase {
239244
navigationMapView.removeWaypoints()
240245
navigationMapView.showsRestrictedAreasOnRoute = false
241246
navigationMapView.routeLineTracksTraversal = true
242-
navigationMapView.showsIntersectionSignalsOnRoutes = true
247+
navigationMapView.showsIntersectionSignals = true
248+
navigationMapView.showIntersectionSignals(with: routeProgress)
243249

244250
expectedLayerSequence = [
245251
buildingLayer["id"]!,
@@ -248,11 +254,11 @@ class RouteLineLayerPositionTests: TestCase {
248254
multilegRoute.identifier(.route(isMainRoute: true)),
249255
roadTrafficLayer["id"]!,
250256
roadLabelLayer["id"]!,
251-
NavigationMapView.LayerIdentifier.intersectionSignalLayer,
252257
NavigationMapView.LayerIdentifier.arrowStrokeLayer,
253258
NavigationMapView.LayerIdentifier.arrowLayer,
254259
NavigationMapView.LayerIdentifier.arrowSymbolCasingLayer,
255260
NavigationMapView.LayerIdentifier.arrowSymbolLayer,
261+
NavigationMapView.LayerIdentifier.intersectionSignalLayer,
256262
roadExitLayer["id"]!,
257263
poiLabelLayer["id"]!,
258264
poiLabelCircleLayer["id"]!
@@ -278,6 +284,7 @@ class RouteLineLayerPositionTests: TestCase {
278284
layerPosition: .below(roadLabelLayer["id"]!))
279285
navigationMapView.removeRoutes()
280286
navigationMapView.removeArrow()
287+
navigationMapView.removeIntersectionSignals()
281288

282289
expectedLayerSequence = [
283290
buildingLayer["id"]!,
@@ -300,6 +307,7 @@ class RouteLineLayerPositionTests: TestCase {
300307
navigationMapView.show([multilegRoute])
301308
navigationMapView.showsRestrictedAreasOnRoute = true
302309
navigationMapView.routeLineTracksTraversal = false
310+
navigationMapView.showIntersectionSignals(with: routeProgress)
303311

304312
expectedLayerSequence = [
305313
buildingLayer["id"]!,
@@ -309,11 +317,11 @@ class RouteLineLayerPositionTests: TestCase {
309317
multilegRoute.identifier(.route(isMainRoute: true)),
310318
multilegRoute.identifier(.restrictedRouteAreaRoute),
311319
roadLabelLayer["id"]!,
312-
NavigationMapView.LayerIdentifier.intersectionSignalLayer,
313320
NavigationMapView.LayerIdentifier.arrowStrokeLayer,
314321
NavigationMapView.LayerIdentifier.arrowLayer,
315322
NavigationMapView.LayerIdentifier.arrowSymbolCasingLayer,
316323
NavigationMapView.LayerIdentifier.arrowSymbolLayer,
324+
NavigationMapView.LayerIdentifier.intersectionSignalLayer,
317325
roadExitLayer["id"]!,
318326
poiLabelLayer["id"]!,
319327
poiLabelCircleLayer["id"]!,

0 commit comments

Comments
 (0)