3
import NbmapCoreNavigation
6
class RouteLinesStylingViewController: UIViewController {
8
typealias ActionHandler = (UIAlertAction) -> Void
10
var trafficUnknownColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
11
var trafficLowColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
12
var trafficModerateColor: UIColor = #colorLiteral(red: 1, green: 0.5843137255, blue: 0, alpha: 1)
13
var trafficHeavyColor: UIColor = #colorLiteral(red: 1, green: 0.3019607843, blue: 0.3019607843, alpha: 1)
14
var trafficSevereColor: UIColor = #colorLiteral(red: 0.5607843137, green: 0.1411764706, blue: 0.2784313725, alpha: 1)
15
var routeCasingColor: UIColor = #colorLiteral(red: 0.28, green: 0.36, blue: 0.8, alpha: 1)
16
var routeAlternateColor: UIColor = #colorLiteral(red: 1, green: 0.65, blue: 0, alpha: 1)
17
var routeAlternateCasingColor: UIColor = #colorLiteral(red: 1.0, green: 0.9, blue: 0.4, alpha: 1)
18
var traversedRouteColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
20
var navigationMapView: NavigationMapView!
22
var currentRouteIndex = 0 {
28
var currentRoute: Route? {
29
return routes?[currentRouteIndex]
32
var routes: [Route]? {
35
guard let routes = routes,
36
let current = routes.first
38
navigationMapView?.removeRoutes()
39
navigationMapView?.removeRouteDurationSymbol()
40
if let annotation = navigationMapView?.annotations?.last {
41
navigationMapView?.removeAnnotation(annotation)
47
navigationMapView?.showRoutes(routes)
48
navigationMapView?.showWaypoints(current)
49
navigationMapView?.showRouteDurationSymbol(routes)
53
func showCurrentRoute() {
54
guard let currentRoute = currentRoute else { return }
56
var routes = [currentRoute]
57
routes.append(contentsOf: self.routes!.filter {
60
navigationMapView.showRoutes(routes)
61
navigationMapView.showWaypoints(currentRoute)
65
override func viewDidLoad() {
68
setupNavigationMapView()
69
setupPerformActionBarButtonItem()
70
setupGestureRecognizers()
74
func setupNavigationMapView() {
75
navigationMapView = NavigationMapView(frame: view.bounds)
76
navigationMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
77
navigationMapView.navigationMapDelegate = self
78
navigationMapView.userTrackingMode = .follow
80
view.addSubview(navigationMapView)
83
func setupPerformActionBarButtonItem() {
84
let settingsBarButtonItem = UIBarButtonItem(title: NSString(string: "\u{2699}\u{0000FE0E}") as String,
87
action: #selector(performAction))
88
settingsBarButtonItem.setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 30)], for: .normal)
89
settingsBarButtonItem.setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 30)], for: .highlighted)
90
navigationItem.rightBarButtonItem = settingsBarButtonItem
93
@objc func performAction(_ sender: Any) {
94
let alertController = UIAlertController(title: "Perform action",
95
message: "Select specific action to perform it", preferredStyle: .actionSheet)
97
let startNavigation: ActionHandler = { _ in self.startNavigation() }
98
let removeRoutes: ActionHandler = { _ in self.routes = nil }
100
let actions: [(String, UIAlertAction.Style, ActionHandler?)] = [
101
("Start Navigation", .default, startNavigation),
102
("Remove Routes", .default, removeRoutes),
103
("Cancel", .cancel, nil)
107
.map({ payload in UIAlertAction(title: payload.0, style: payload.1, handler: payload.2) })
108
.forEach(alertController.addAction(_:))
110
if let popoverController = alertController.popoverPresentationController {
111
popoverController.barButtonItem = navigationItem.rightBarButtonItem
114
present(alertController, animated: true, completion: nil)
117
func setupGestureRecognizers() {
118
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
119
navigationMapView.addGestureRecognizer(longPressGestureRecognizer)
122
@objc func startNavigation() {
123
guard let routes = routes else {
124
print("Please select at least one destination coordinate to start navigation.")
128
let navigationService = NBNavigationService(routes: routes, routeIndex: currentRouteIndex)
130
let navigationOptions = NavigationOptions(navigationService: navigationService)
131
let navigationViewController = NavigationViewController(for: routes,navigationOptions: navigationOptions)
132
navigationViewController.delegate = self
133
navigationViewController.modalPresentationStyle = .fullScreen
134
navigationViewController.routeLineTracksTraversal = true
135
present(navigationViewController, animated: true, completion: nil)
138
@objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
139
guard let navigationMapView = navigationMapView, gesture.state == .began else {
142
let coordinates = navigationMapView.convert(gesture.location(in: navigationMapView), toCoordinateFrom: navigationMapView)
143
let destination = Waypoint(coordinate: coordinates, name: "\(coordinates.latitude),\(coordinates.longitude)")
145
addNewDestinationcon(coordinates: coordinates)
147
guard let currentLocation = navigationMapView.userLocation?.coordinate else { return}
148
let currentWayPoint = Waypoint.init(coordinate: currentLocation, name: "My Location")
150
requestRoutes(origin: currentWayPoint, destination: destination)
153
func addNewDestinationcon(coordinates: CLLocationCoordinate2D){
154
guard let mapView = navigationMapView else {
158
if let annotation = mapView.annotations?.last {
159
mapView.removeAnnotation(annotation)
162
let annotation = NGLPointAnnotation()
163
annotation.coordinate = coordinates
164
mapView.addAnnotation(annotation)
167
func requestRoutes(origin: Waypoint, destination: Waypoint){
169
let options = NavigationRouteOptions(origin: origin, destination: destination)
171
Directions.shared.calculate(options) { [weak self] routes, error in
172
guard let weakSelf = self else {
175
guard error == nil else {
180
guard let routes = routes else { return }
182
weakSelf.routes = routes
186
func routeStyleLayer(identifier: String,source: NGLSource) -> NGLStyleLayer {
187
let line = NGLLineStyleLayer(identifier: identifier, source: source)
188
line.lineWidth = NSExpression(format: "ngl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", NBRouteLineWidthByZoomLevel)
189
line.lineColor = NSExpression(format: "TERNARY(isAlternateRoute == true, %@, NGL_MATCH(congestion, 'low' , %@, 'moderate', %@, 'heavy', %@, 'severe', %@, %@))", routeAlternateColor, trafficLowColor, trafficModerateColor, trafficHeavyColor, trafficSevereColor, trafficUnknownColor)
190
line.lineOpacity = NSExpression(forConstantValue: 1)
191
line.lineCap = NSExpression(forConstantValue: "round")
192
line.lineJoin = NSExpression(forConstantValue: "round")
197
func routeCasingStyleLayer(identifier: String,source: NGLSource) -> NGLStyleLayer {
198
let lineCasing = NGLLineStyleLayer(identifier: identifier, source: source)
201
lineCasing.lineWidth = NSExpression(format: "ngl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", NBRouteLineWidthByZoomLevel.multiplied(by: 1.3))
203
lineCasing.lineColor = NSExpression(forConstantValue: routeCasingColor)
205
lineCasing.lineCap = NSExpression(forConstantValue: "round")
206
lineCasing.lineJoin = NSExpression(forConstantValue: "round")
208
lineCasing.lineOpacity = NSExpression(forConditional: NSPredicate(format: "isAlternateRoute == true"),
209
trueExpression: NSExpression(forConstantValue: 1),
210
falseExpression: NSExpression(forConditional: NSPredicate(format: "isCurrentLeg == true"), trueExpression: NSExpression(forConstantValue: 1), falseExpression: NSExpression(forConstantValue: 0.85)))
217
extension RouteLinesStylingViewController: NavigationMapViewDelegate {
219
func navigationMapView(_ mapView: NavigationMapView, routeStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
221
return routeStyleLayer(identifier: identifier,source: source)
224
func navigationMapView(_ mapView: NavigationMapView, routeCasingStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
225
return routeCasingStyleLayer(identifier: identifier,source: source)
230
extension RouteLinesStylingViewController: NavigationViewControllerDelegate {
233
func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) {
234
dismiss(animated: true, completion: nil)
237
func navigationViewController(_ navigationViewController: NavigationViewController, routeStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
238
return routeStyleLayer(identifier: identifier,source: source)
241
func navigationViewController(_ navigationViewController: NavigationViewController, routeCasingStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
242
return routeCasingStyleLayer(identifier: identifier,source: source)