Skip to content

Instantly share code, notes, and snippets.

@yllan
Created July 16, 2018 01:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yllan/df33b8b1b78f714dfd7d5048a9a6189b to your computer and use it in GitHub Desktop.
Save yllan/df33b8b1b78f714dfd7d5048a9a6189b to your computer and use it in GitHub Desktop.
import Cocoa
import MapKit
class MultilineCluster: NSObject, MKOverlay {
var coordinate: CLLocationCoordinate2D
var boundingMapRect: MKMapRect
var lines: [[MKMapPoint]] = []
var strokeColor: NSColor = .black
init(coords: [[CLLocationCoordinate2D]]) {
self.lines = coords.map{$0.map(MKMapPointForCoordinate)}
let xs = self.lines.flatMap({$0}).map({$0.x})
let ys = self.lines.flatMap({$0}).map({$0.y})
guard let xmin = xs.min(), let xmax = xs.max(),
let ymin = ys.min(), let ymax = ys.max()
else {
self.coordinate = CLLocationCoordinate2D(latitude: 0, longitude: 0)
self.boundingMapRect = MKMapRect(origin: MKMapPoint(x: 0, y: 0), size: MKMapSize(width: 0, height: 0))
return
}
self.boundingMapRect = MKMapRect(origin: MKMapPoint(x: xmin, y: ymin), size: MKMapSizeMake(xmax - xmin, ymax - ymin))
self.coordinate = MKCoordinateForMapPoint(MKMapPoint(x: xmin + (xmax - xmin) / 2, y: ymin + (ymax - ymin) / 2))
}
}
class MultilineClusterRenderer: MKOverlayPathRenderer {
override func createPath() {
guard let cluster = overlay as? MultilineCluster else { return }
let path = CGMutablePath()
for line in cluster.lines {
guard line.count > 1 else { continue }
path.move(to: point(for: line[0]))
for idx in 1..<line.count {
path.addLine(to: point(for: line[idx]))
}
}
self.path = path
}
}
extension Array {
func split(beginAt: [Int]) -> [ArraySlice<Element>] {
return (0..<beginAt.count).map { (idx) in
let from = beginAt[idx]
let to = (idx == beginAt.count - 1) ? self.count : beginAt[idx + 1]
return self[from..<to]
}
}
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, MKMapViewDelegate {
@IBOutlet weak var window: NSWindow!
@IBOutlet weak var mapView: MKMapView!
func applicationDidFinishLaunching(_ aNotification: Notification) {
mapView.delegate = self
mapView.region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 25.049972, longitude: 121.538350), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
var linesForType: [String: [[CLLocationCoordinate2D]]] = [:]
let filename = "noparkin_201806011722"
if let shpURL = Bundle.main.url(forResource: filename, withExtension: "shp", subdirectory: "Data"),
let shxURL = Bundle.main.url(forResource: filename, withExtension: "shx", subdirectory: "Data"),
let prjURL = Bundle.main.url(forResource: filename, withExtension: "prj", subdirectory: "Data"),
let sr = try? ShapefileReader(url: shpURL)
{
var count = 0
NSLog("reading shapes begin")
for (shape, r) in sr.shapeAndRecordGenerator() {
guard shape.shapeType == .polyLine else {
print("shape is not polyline! \(shape)")
continue
}
let type = r[5]
for line in shape.points.split(beginAt: shape.parts) {
let coords: [CLLocationCoordinate2D] = line.map { (point) in
let (lat, lng) = toLatitudeLongitude(x: Double(point.x), y: Double(point.y))
return CLLocationCoordinate2D(latitude: lat, longitude: lng)
}
linesForType[type, default: []].append(coords)
}
count += 1
}
}
NSLog("reading shapes end")
DispatchQueue.main.asyncAfter(deadline: .now() + 0) {
for (t, coords) in linesForType {
let cluster = MultilineCluster(coords: coords)
switch t {
case "02":
cluster.strokeColor = NSColor(named: NSColor.Name("YellowColor"))!
case "01":
cluster.strokeColor = .red
case "11":
cluster.strokeColor = .blue
default:
cluster.strokeColor = .green
}
self.mapView.add(cluster)
}
}
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
switch overlay {
case let cluster as MultilineCluster:
let r = MultilineClusterRenderer(overlay: cluster)
r.strokeColor = cluster.strokeColor
r.lineWidth = 1
return r
default:
return MKOverlayRenderer()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment