Skip to content

Instantly share code, notes, and snippets.

@abin0992
Created April 6, 2018 08:33
Show Gist options
  • Save abin0992/343f90833434bf8ece6e3c16bfd46bc2 to your computer and use it in GitHub Desktop.
Save abin0992/343f90833434bf8ece6e3c16bfd46bc2 to your computer and use it in GitHub Desktop.
Map playground
//: A MapKit based Playground
import MapKit
import PlaygroundSupport
var points: [Any] = []
class MapDelegate: NSObject, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let myAnnotation = annotation as? MKPointAnnotation else {
fatalError("Not a MyAnnotation")
}
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "myannotation") ?? MKPinAnnotationView(annotation: myAnnotation, reuseIdentifier: "myannotation")
annotationView.canShowCallout = true
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
let calloutView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
calloutView.backgroundColor = .red
calloutView.addConstraint(NSLayoutConstraint(item: calloutView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: calloutView.frame.width))
calloutView.addConstraint(NSLayoutConstraint(item: calloutView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: calloutView.frame.height))
view.detailCalloutAccessoryView = calloutView
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
guard let polyline = overlay as? MKPolyline else {
fatalError("Not a MKPolyline")
}
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.strokeColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
renderer.lineWidth = 8
// renderer.lineDashPattern = [0, 10]
return renderer
}
func mapView(_ mapView: MKMapView, didAdd renderers: [MKOverlayRenderer]) {
// Animate a 'fade'
for overlayRenderer: MKOverlayRenderer? in renderers {
// MKPolylineRenderer
// Animate a 'fade'
if (overlayRenderer is MKPolylineRenderer) {
// Get MKPolylineRenderer
let polylineRenderer = overlayRenderer as? MKPolylineRenderer
// Let's manually set alpha to 0
polylineRenderer?.alpha = 0.0
// Animate it back to 1
DispatchQueue.main.async(execute: {() -> Void in
UIView.animate(withDuration: 0.4, animations: {() -> Void in
polylineRenderer?.alpha = 1.0
})
})
}
}
}
}
class MyRenderer: MKOverlayRenderer {
}
class MyAnnotation: NSObject, MKAnnotation {
var title: String?
var subtitle: String?
var coordinate: CLLocationCoordinate2D
init(title: String, coordinate: CLLocationCoordinate2D) {
self.title = title
self.coordinate = coordinate
}
}
func getPointsOnRoute(from: CLLocation?, to: CLLocation?, on mapView: MKMapView?) -> [Any]? {
let NUMBER_OF_PIXELS_TO_SKIP: Int = 20
//lower number will give a more smooth animation, but will result in more layers
var ret = [Any]()
var fromPoint: CGPoint? = nil
if let aCoordinate = from?.coordinate {
fromPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
}
var toPoint: CGPoint? = nil
if let aCoordinate = to?.coordinate {
toPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
}
let allPixels = getAllPoints(from: fromPoint!, to: toPoint!)
var i = 0
while i < (allPixels?.count)! {
let pointVal = allPixels![i] as? NSValue
ret.append(point(toLocation: mapView, from: (pointVal?.cgPointValue)!)!)
i += NUMBER_OF_PIXELS_TO_SKIP
}
ret.append(point(toLocation: mapView, from: toPoint!)!)
return ret
}
/**convert a CGPoint to a CLLocation according to a mapView*/
func point(toLocation mapView: MKMapView?, from fromPoint: CGPoint) -> CLLocation? {
let coord: CLLocationCoordinate2D? = mapView?.convert(fromPoint, toCoordinateFrom: mapView)
return CLLocation(latitude: coord?.latitude ?? 0, longitude: coord?.longitude ?? 0)
}
func getAllPoints(from fPoint: CGPoint, to tPoint: CGPoint) -> [Any]? {
/*Simplyfied implementation of Bresenham's line algoritme */
var ret = [AnyHashable]()
let deltaX: Float = fabsf(Float(tPoint.x - fPoint.x))
let deltaY: Float = fabsf(Float(tPoint.y - fPoint.y))
var x: Float = Float(fPoint.x)
var y: Float = Float(fPoint.y)
var err: Float = deltaX - deltaY
var sx: Float = -0.5
var sy: Float = -0.5
if fPoint.x < tPoint.x {
sx = 0.5
}
if fPoint.y < tPoint.y {
sy = 0.5
}
repeat {
ret.append(NSValue(cgPoint: CGPoint(x: CGFloat(x), y: CGFloat(y))))
let e: Float = 2 * err
if e > -deltaY {
err -= deltaY
x += sx
}
if e < deltaX {
err += deltaX
y += sy
}
} while round(Float(x)) != round(Float(tPoint.x)) && round(Float(y)) != round(Float(tPoint.y))
ret.append(NSValue(cgPoint: tPoint))
//add final point
return ret
}
func addOverlaysFromPointsWithStart(from end: NSNumber?) {
// let intEnd = Int(truncating: end ?? 0)
// //construct polyline view from start
// let locations: CLLocationCoordinate2D? = malloc(MemoryLayout<CLLocationCoordinate2D>.size * 2)
// let loc1 = points[0] as? CLLocation
// let loc2 = points[intEnd] as? CLLocation
// if let aCoordinate = loc1?.coordinate {
// locations![0] = aCoordinate
// }
// if let aCoordinate = loc2?.coordinate {
// locations![1] = aCoordinate
// }
// let line = MKPolyline(coordinates: locations, count: 2)
// mapView?.add(line)
// if (intEnd + 1) < points.count {
// perform(Selector("addOverlaysFromPointsWithStartFrom:"), with: intEnd + 1, afterDelay: 0.01)
// }
}
let mapDelegate = MapDelegate()
let frame = CGRect(x: 0, y: 0, width: 400, height: 600)
let mapView = MKMapView(frame: frame)
mapView.centerCoordinate = CLLocationCoordinate2DMake(51.107, 17.0385)
let span = MKCoordinateSpanMake(18.075, 18.075)
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.107, longitude: 17.0385), span: span)
mapView.setRegion(region, animated: true)
mapView.delegate = mapDelegate
//let myAnnotation = MyAnnotation(title: "Foo", coordinate: CLLocationCoordinate2DMake(35, -100))
//mapView.addAnnotation(myAnnotation)
let pointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = CLLocationCoordinate2DMake(51.107, 17.0385)
pointAnnotation.title = "Point Annotation"
mapView.addAnnotation(pointAnnotation)
var coordinates = [
CLLocationCoordinate2DMake(50.41880, 20.49000),
CLLocationCoordinate2DMake(55.76105, 10.14051)
]
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
print(polyline.pointCount)
mapView.addOverlays([polyline])
var from = coordinates.first
var fLat: CLLocationDegrees = from!.latitude
var fLon: CLLocationDegrees = from!.longitude
var froml: CLLocation = CLLocation(latitude: fLat, longitude: fLon)
var to = coordinates.last
var tLat: CLLocationDegrees = to!.latitude
var tLon: CLLocationDegrees = to!.longitude
var tol: CLLocation = CLLocation(latitude: tLat, longitude: tLon)
points = getPointsOnRoute(from: froml, to: tol, on: mapView)!
print("Coordinates on route are \(points)")
PlaygroundPage.current.liveView = mapView
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment