3
import NbmapCoreNavigation
5
class RouteLinesStylingViewController: UIViewController {
7
typealias ActionHandler = (UIAlertAction) -> Void
9
var trafficUnknownColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
10
var trafficLowColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
11
var trafficModerateColor: UIColor = #colorLiteral(red: 1, green: 0.5843137255, blue: 0, alpha: 1)
12
var trafficHeavyColor: UIColor = #colorLiteral(red: 1, green: 0.3019607843, blue: 0.3019607843, alpha: 1)
13
var trafficSevereColor: UIColor = #colorLiteral(red: 0.5607843137, green: 0.1411764706, blue: 0.2784313725, alpha: 1)
14
var routeCasingColor: UIColor = #colorLiteral(red: 0.28, green: 0.36, blue: 0.8, alpha: 1)
15
var routeAlternateColor: UIColor = #colorLiteral(red: 1, green: 0.65, blue: 0, alpha: 1)
16
var routeAlternateCasingColor: UIColor = #colorLiteral(red: 1.0, green: 0.9, blue: 0.4, alpha: 1)
17
var traversedRouteColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
19
var navigationMapView: NavigationMapView!
21
var currentRouteIndex = 0 {
27
var currentRoute: Route? {
28
return routes?[currentRouteIndex]
31
var routes: [Route]? {
34
guard let routes = routes,
35
let current = routes.first
37
navigationMapView?.removeRoutes()
38
navigationMapView?.removeRouteDurationSymbol()
39
if let annotation = navigationMapView?.annotations?.last {
40
navigationMapView?.removeAnnotation(annotation)
46
navigationMapView?.showRoutes(routes)
47
navigationMapView?.showWaypoints(current)
48
navigationMapView?.showRouteDurationSymbol(routes)
52
func showCurrentRoute() {
53
guard let currentRoute = currentRoute else { return }
55
var routes = [currentRoute]
56
routes.append(contentsOf: self.routes!.filter {
59
navigationMapView.showRoutes(routes)
60
navigationMapView.showWaypoints(currentRoute)
64
override func viewDidLoad() {
67
setupNavigationMapView()
68
setupPerformActionBarButtonItem()
69
setupGestureRecognizers()
73
func setupNavigationMapView() {
74
navigationMapView = NavigationMapView(frame: view.bounds)
75
navigationMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
76
navigationMapView.navigationMapDelegate = self
77
navigationMapView.userTrackingMode = .follow
79
view.addSubview(navigationMapView)
82
func setupPerformActionBarButtonItem() {
83
let settingsBarButtonItem = UIBarButtonItem(title: NSString(string: "\u{2699}\u{0000FE0E}") as String,
86
action: #selector(performAction))
87
settingsBarButtonItem.setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 30)], for: .normal)
88
settingsBarButtonItem.setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 30)], for: .highlighted)
89
navigationItem.rightBarButtonItem = settingsBarButtonItem
92
@objc func performAction(_ sender: Any) {
93
let alertController = UIAlertController(title: "Perform action",
94
message: "Select specific action to perform it", preferredStyle: .actionSheet)
96
let startNavigation: ActionHandler = { _ in self.startNavigation() }
97
let removeRoutes: ActionHandler = { _ in self.routes = nil }
99
let actions: [(String, UIAlertAction.Style, ActionHandler?)] = [
100
("Start Navigation", .default, startNavigation),
101
("Remove Routes", .default, removeRoutes),
102
("Cancel", .cancel, nil)
106
.map({ payload in UIAlertAction(title: payload.0, style: payload.1, handler: payload.2) })
107
.forEach(alertController.addAction(_:))
109
if let popoverController = alertController.popoverPresentationController {
110
popoverController.barButtonItem = navigationItem.rightBarButtonItem
113
present(alertController, animated: true, completion: nil)
116
func setupGestureRecognizers() {
117
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
118
navigationMapView.addGestureRecognizer(longPressGestureRecognizer)
121
@objc func startNavigation() {
122
guard let routes = routes else {
123
print("Please select at least one destination coordinate to start navigation.")
127
let navigationService = NBNavigationService(routes: routes, routeIndex: currentRouteIndex)
129
let navigationOptions = NavigationOptions(navigationService: navigationService)
130
let navigationViewController = NavigationViewController(for: routes,navigationOptions: navigationOptions)
131
navigationViewController.delegate = self
132
navigationViewController.modalPresentationStyle = .fullScreen
133
navigationViewController.routeLineTracksTraversal = true
134
present(navigationViewController, animated: true, completion: nil)
137
@objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
138
guard let navigationMapView = navigationMapView, gesture.state == .began else {
141
let coordinates = navigationMapView.convert(gesture.location(in: navigationMapView), toCoordinateFrom: navigationMapView)
142
let destination = Waypoint(coordinate: coordinates, name: "\(coordinates.latitude),\(coordinates.longitude)")
144
addNewDestinationcon(coordinates: coordinates)
146
guard let currentLocation = navigationMapView.userLocation?.coordinate else { return}
147
let currentWayPoint = Waypoint.init(coordinate: currentLocation, name: "My Location")
149
requestRoutes(origin: currentWayPoint, destination: destination)
152
func addNewDestinationcon(coordinates: CLLocationCoordinate2D){
153
guard let mapView = navigationMapView else {
157
if let annotation = mapView.annotations?.last {
158
mapView.removeAnnotation(annotation)
161
let annotation = NGLPointAnnotation()
162
annotation.coordinate = coordinates
163
mapView.addAnnotation(annotation)
166
func requestRoutes(origin: Waypoint, destination: Waypoint){
168
let options = NavigationRouteOptions(origin: origin, destination: destination)
170
Directions.shared.calculate(options) { [weak self] routes, error in
171
guard let weakSelf = self else {
174
guard error == nil else {
179
guard let routes = routes else { return }
181
weakSelf.routes = routes
185
func routeStyleLayer(identifier: String,source: NGLSource) -> NGLStyleLayer {
186
let line = NGLLineStyleLayer(identifier: identifier, source: source)
187
line.lineWidth = NSExpression(format: "ngl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", NBRouteLineWidthByZoomLevel)
188
line.lineColor = NSExpression(format: "TERNARY(isAlternateRoute == true, %@, NGL_MATCH(congestion, 'low' , %@, 'moderate', %@, 'heavy', %@, 'severe', %@, %@))", routeAlternateColor, trafficLowColor, trafficModerateColor, trafficHeavyColor, trafficSevereColor, trafficUnknownColor)
189
line.lineOpacity = NSExpression(forConstantValue: 1)
190
line.lineCap = NSExpression(forConstantValue: "round")
191
line.lineJoin = NSExpression(forConstantValue: "round")
196
func routeCasingStyleLayer(identifier: String,source: NGLSource) -> NGLStyleLayer {
197
let lineCasing = NGLLineStyleLayer(identifier: identifier, source: source)
200
lineCasing.lineWidth = NSExpression(format: "ngl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", NBRouteLineWidthByZoomLevel.multiplied(by: 1.3))
202
lineCasing.lineColor = NSExpression(forConstantValue: routeCasingColor)
204
lineCasing.lineCap = NSExpression(forConstantValue: "round")
205
lineCasing.lineJoin = NSExpression(forConstantValue: "round")
207
lineCasing.lineOpacity = NSExpression(forConditional: NSPredicate(format: "isAlternateRoute == true"),
208
trueExpression: NSExpression(forConstantValue: 1),
209
falseExpression: NSExpression(forConditional: NSPredicate(format: "isCurrentLeg == true"), trueExpression: NSExpression(forConstantValue: 1), falseExpression: NSExpression(forConstantValue: 0.85)))
216
extension RouteLinesStylingViewController: NavigationMapViewDelegate {
218
func navigationMapView(_ mapView: NavigationMapView, routeStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
220
return routeStyleLayer(identifier: identifier,source: source)
223
func navigationMapView(_ mapView: NavigationMapView, routeCasingStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
224
return routeCasingStyleLayer(identifier: identifier,source: source)
229
extension RouteLinesStylingViewController: NavigationViewControllerDelegate {
232
func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) {
233
dismiss(animated: true, completion: nil)
236
func navigationViewController(_ navigationViewController: NavigationViewController, routeStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
237
return routeStyleLayer(identifier: identifier,source: source)
240
func navigationViewController(_ navigationViewController: NavigationViewController, routeCasingStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
241
return routeCasingStyleLayer(identifier: identifier,source: source)