Files
MapLibreParticleLab/platform/ios/app-swift/Sources/POIAlongRouteExample.swift
2024-07-08 17:57:06 +03:00

162 lines
7.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import MapLibre
import SwiftUI
import UIKit
// #-example-code(POIAlongRouteExample)
class POIAlongRouteExample: UIViewController, MLNMapViewDelegate {
var mapView: MLNMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView = MLNMapView(frame: view.bounds, styleURL: AMERICANA_STYLE)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.setCenter(
CLLocationCoordinate2D(latitude: 45.52214, longitude: -122.63748),
zoomLevel: 18,
animated: false
)
view.addSubview(mapView)
mapView.delegate = self
}
// Wait until the map is loaded before adding to the map.
func mapView(_: MLNMapView, didFinishLoading _: MLNStyle) {
loadGeoJson()
restrictPOIVisibleShape()
setCamera()
}
func loadGeoJson() {
DispatchQueue.global().async {
// Get the path for example.geojson in the app’s bundle.
guard let jsonUrl = Bundle.main.url(forResource: "example", withExtension: "geojson") else {
preconditionFailure("Failed to load local GeoJSON file")
}
guard let jsonData = try? Data(contentsOf: jsonUrl) else {
preconditionFailure("Failed to parse GeoJSON file")
}
DispatchQueue.main.async {
self.drawPolyline(geoJson: jsonData)
}
}
}
func setCamera() {
let camera = mapView.camera
camera.heading = 249.37706203842038
camera.pitch = 60
camera.centerCoordinate.latitude = 45.52199780570582
camera.centerCoordinate.longitude = -122.6418837958432
mapView.setCamera(camera, animated: false)
mapView.setZoomLevel(15.062187320447523, animated: false)
}
func drawPolyline(geoJson: Data) {
// Add our GeoJSON data to the map as an MLNGeoJSONSource.
// We can then reference this data from an MLNStyleLayer.
// MLNMapView.style is optional, so you must guard against it not being set.
guard let style = mapView.style else { return }
guard let shapeFromGeoJSON = try? MLNShape(data: geoJson, encoding: String.Encoding.utf8.rawValue) else {
fatalError("Could not generate MLNShape")
}
let source = MLNShapeSource(identifier: "polyline", shape: shapeFromGeoJSON, options: nil)
style.addSource(source)
// Create new layer for the line.
let layer = MLNLineStyleLayer(identifier: "polyline", source: source)
// Set the line join and cap to a rounded end.
layer.lineJoin = NSExpression(forConstantValue: "round")
layer.lineCap = NSExpression(forConstantValue: "round")
// Set the line color to a constant blue color.
layer.lineColor = NSExpression(forConstantValue: UIColor(red: 59 / 255, green: 178 / 255, blue: 208 / 255, alpha: 1))
// Use expression to smoothly adjust the line width from 2pt to 20pt between zoom levels 14 and 18.
layer.lineWidth = NSExpression(mglJSONObject: ["interpolate", ["linear"], ["zoom"], 14, 2, 18, 20])
// We can also add a second layer that will draw a stroke around the original line.
let casingLayer = MLNLineStyleLayer(identifier: "polyline-case", source: source)
// Copy these attributes from the main line layer.
casingLayer.lineJoin = layer.lineJoin
casingLayer.lineCap = layer.lineCap
// Line gap width represents the space before the outline begins, so should match the main line’s line width exactly.
casingLayer.lineGapWidth = layer.lineWidth
// Stroke color slightly darker than the line color.
casingLayer.lineColor = NSExpression(forConstantValue: UIColor(red: 41 / 255, green: 145 / 255, blue: 171 / 255, alpha: 1))
// Use expression to gradually increase the stroke width between zoom levels 14 and 18.
casingLayer.lineWidth = NSExpression(mglJSONObject: ["interpolate", ["linear"], ["zoom"], 14, 1, 18, 4])
// Just for fun, let’s add another copy of the line with a dash pattern.
let dashedLayer = MLNLineStyleLayer(identifier: "polyline-dash", source: source)
dashedLayer.lineJoin = layer.lineJoin
dashedLayer.lineCap = layer.lineCap
dashedLayer.lineColor = NSExpression(forConstantValue: UIColor.white)
dashedLayer.lineOpacity = NSExpression(forConstantValue: 0.5)
dashedLayer.lineWidth = layer.lineWidth
// Dash pattern in the format [dash, gap, dash, gap, ...]. You’ll want to adjust these values based on the line cap style.
dashedLayer.lineDashPattern = NSExpression(forConstantValue: [0, 1.5])
guard let poiLayer = mapView.style?.layer(withIdentifier: "poi") as? MLNSymbolStyleLayer else {
print("Could not find poi layer")
return
}
style.insertLayer(layer, below: poiLayer)
style.insertLayer(dashedLayer, above: layer)
style.insertLayer(casingLayer, below: layer)
}
func restrictPOIVisibleShape() {
// find poi-label layer
guard let poiLayer = mapView.style?.layer(withIdentifier: "poi") as? MLNSymbolStyleLayer else {
print("Could not find poi layer")
return
}
// find road-label layer
guard let roadLabelLayer = mapView.style?.layer(withIdentifier: "road_label") as? MLNSymbolStyleLayer else {
print("Could not find road_label layer")
return
}
// show the POI and road that is within this polygon
let polygonShape = [
[-122.63730626171188, 45.52288837762333],
[-122.65455070022612, 45.52299746891552],
[-122.65747018755947, 45.52177017968134],
[-122.65992255691913, 45.51931552089448],
[-122.66015611590598, 45.513696676587045],
[-122.66696825301655, 45.51375123117057],
[-122.6672018120034, 45.51222368283956],
[-122.6571977020749, 45.51225096085216],
[-122.6570419960839, 45.51822452705878],
[-122.65392787626189, 45.52106106703124],
[-122.63567134880579, 45.52114288817623],
[-122.63657745074761, 45.52288036393409],
[-122.6373404839605, 45.52291377640398],
]
// create a polygon class
let coordinates = polygonShape.map { CLLocationCoordinate2D(latitude: $0[1], longitude: $0[0]) }
let bufferedRoutePolygon = MLNPolygon(coordinates: coordinates, count: UInt(coordinates.count), interiorPolygons: nil)
// apply predicates to these two layers
poiLayer.predicate = NSPredicate(format: "SELF IN %@", bufferedRoutePolygon)
roadLabelLayer.predicate = NSPredicate(format: "SELF IN %@", bufferedRoutePolygon)
}
}
// #-end-example-code
struct POIAlongRouteExampleUIViewControllerRepresentable: UIViewControllerRepresentable {
typealias UIViewControllerType = POIAlongRouteExample
func makeUIViewController(context _: Context) -> POIAlongRouteExample {
POIAlongRouteExample()
}
func updateUIViewController(_: POIAlongRouteExample, context _: Context) {}
}