2016-05-28 9 views
1

Ich brauche vor allem eine MKPolyline in einem UIImage ohne die Verwendung eines MKMapView, wenn möglich (für Leistungen Gründen zu machen, möchte ich so schnell wie möglich den Weg anzuzeigen, während die Karte screenshotter asynchron die liefert Karte, wie die App Strava).Render eine MKPolyline in einem UIImage

kam ich mit diesem Stück Code oben:

func pathImageForSize(size: CGSize) -> UIImage { 
    let region = regionForPath() // MKCoordinateRegion 
    let coordinates = locations.map { $0.coordinate } 
    UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.mainScreen().scale) 

    let context = UIGraphicsGetCurrentContext() 

    CGContextSetStrokeColorWithColor(context, UIColor.palette_mainColor().CGColor) 
    CGContextSetLineWidth(context, 4.0) 
    CGContextBeginPath(context) 

    let origin = CGPoint(x: region.center.latitude - region.span.latitudeDelta/2, y: region.center.longitude - region.span.longitudeDelta/2) 

    for (index, coordinate) in coordinates.enumerate() { 
     let point = CGPoint(x: ((CGFloat(coordinate.latitude) - origin.x)/CGFloat(region.span.latitudeDelta)) * size.width, 
          y: ((CGFloat(coordinate.longitude) - origin.y)/CGFloat(region.span.longitudeDelta)) * size.height) 

     if index == 0 { 
      CGContextMoveToPoint(context, point.x, point.y) 
     } else { 
      CGContextAddLineToPoint(context, point.x, point.y) 
     } 
    } 

    CGContextStrokePath(context) 

    let image = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
    return image 
} 

Der Code neu skaliert im Grunde die Koordinaten und zieht sie mit Core Graphics. Der Weg ist gezeichnet, aber es wird auch um 90 Grad gedreht, wie Sie hier sehen können:

Linienzug von MapKit gemacht: MapKit polyline

Linienzug durch meinen Code gemacht: CoreGraphics polyline

Jede Idee, was mache ich falsch?

+0

Für glatte Kurven Sie bei der so genannten 'miterLimit' aussehen wollen könnte, die Sie über' CGContextSetMiterLimit' offenbar einstellen. – luk2302

Antwort

1

Ok, herausgefunden, meine Prämisse war falsch, mit: Die Region, die ich berechnete, verkapselt die Koordinaten des Pfades, aber diese Region wird von der Mapview angepasst, wenn es Zeit zum Rendern ist. Die Lösung war, die Region zu skalieren, um die mapview Rahmen passen:

let map = MKMapView(frame: CGRect(origin: CGPoint.zero, size: size)) 
let region = map.regionThatFits(regionForPath()) 

auch wie vorgeschlagen, durch BrentM wurden die Koordinaten gespiegelt. Der resultierende Code ist dies:

func pathImageForSize(size: CGSize) -> UIImage { 
    let map = MKMapView(frame: CGRect(origin: CGPoint.zero, size: size)) 
    let region = map.regionThatFits(regionForPath()) 
    let coordinates = locations.map { $0.coordinate } 
    UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.mainScreen().scale) 

    let context = UIGraphicsGetCurrentContext() 
    CGContextSetLineJoin(context, .Round) 
    CGContextSetLineCap(context, .Round) 
    CGContextSetStrokeColorWithColor(context, UIColor.palette_mainColor().CGColor) 
    CGContextSetLineWidth(context, 4.0) 
    CGContextBeginPath(context) 

    let origin = CGPoint(x: region.center.longitude - region.span.longitudeDelta/2, y: region.center.latitude - region.span.latitudeDelta/2) 

    for (index, coordinate) in coordinates.enumerate() { 
    let point = CGPoint(x: ((CGFloat(coordinate.longitude) - origin.x)/CGFloat(region.span.longitudeDelta)) * size.width, 
         y: ((CGFloat(coordinate.latitude) - origin.y)/CGFloat(region.span.latitudeDelta)) * size.height) 

    if index == 0 { 
     CGContextMoveToPoint(context, point.x, size.height - point.y) 
    } else { 
     CGContextAddLineToPoint(context, point.x, size.height - point.y) 
    } 
    } 

    CGContextStrokePath(context) 

    let image = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
    return image 
} 
2

Ich vermute, dies liegt daran, dass Sie den Breitengrad als 'x' und den Längengrad als 'y' verwenden. Breite ist die vertikale Dimension (auf einer Karte mit Norden an der Spitze) und Länge ist die horizontale Dimension.

+0

In meiner ursprünglichen Implementierung hatte ich lat und lng geschaltet, aber das Ergebnis ist noch weiter von der Mapkit-Rendering, wie Sie hier sehen können: http://d.pr/i/st03 – andreamazz

+1

Dieses Bild ist falsch, weil es auf dem Kopf steht und horizontal gestreckt. Die Upside-Down-Funktion ist wahrscheinlich darauf zurückzuführen, dass Sie ein gewendetes Koordinatensystem verwenden (Ursprung oben links), während das lat/lon-Gitter positiv nach Norden und Osten vom Ursprung verläuft. Ich denke, was Sie tun sollten, ist mit 'MKMapPointForCoordinate()', von lat/lon zu projizierten Kartenkoordinaten zu konvertieren und dann diese Punkte zu manipulieren, um sie zu rendern – BrentM

+0

Sie haben Recht, ich habe das nicht bemerkt. Ich habe das Bild umgedreht, aber ich kann nicht herausfinden, wie man die Punkte richtig skaliert, sogar wenn man sie in MapPoints konvertiert, ergibt sich das gleiche Ergebnis. – andreamazz