MapKit Draw poly line from coordinates Swift 5
Asked Answered
E

2

5

I have an array of CLLocationCoordinate2D, and need to draw a line connecting from the first index to the last index in the array.

I have seen the answers here and elsewhere, but they are mostly for older versions of swift, or for an array of strings that you first convert to doubles or whatever or for only a single location.

I have tried creating an MKPolyline, viewForOverlay, etc, but I am unable to get the line to show up. What am I missing?

let locationManager = CLLocationManager()
let regionRadius: CLLocationDistance = 3000
var locations: [CLLocationCoordinate2D] = []
var latitude: [CLLocationDegrees] = []
var longitude: [CLLocationDegrees] = []

override func viewDidLoad() {
        super.viewDidLoad()
        mapView.delegate = self
        mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
        createAnnotations()
        centerMapOnLocation(location: initialLocation)
        var polyline = MKPolyline(coordinates: &locations, count: locations.count)
        mapView.addOverlay(polyline)
    }
    // MARK: - Create Annotaions
    func createAnnotations() {
        locations = zip(latitude, longitude).map(CLLocationCoordinate2D.init)
        AppLogger.logInfo("\(locations)")
        for location in locations {
            let annotation = MKPointAnnotation()
            annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
            mapView.addAnnotation(annotation)
        }
    }
    // MARK: - Region Zoom
    func centerMapOnLocation(location: CLLocation) {
        let coordinateRegion = MKCoordinateRegion(center: location.coordinate,
                                                  latitudinalMeters: regionRadius,
                                                  longitudinalMeters: regionRadius)
      mapView.setRegion(coordinateRegion, animated: true)
    }
    // MARK: - Draw Polylines
    func mapView(mapView: MKMapView!, viewForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
        if (overlay is MKPolyline) {
            let pr = MKPolylineRenderer(overlay: overlay)
            pr.strokeColor = UIColor.blue.withAlphaComponent(0.5)
            pr.lineWidth = 5
            return pr
        }
        return nil
    }

Expected output: From the array of locations we essentially draw the route driven. It's not a get directions method as the drive was already taken.

Executor answered 19/9, 2019 at 15:2 Comment(0)
G
11

Using Swift 5

First you would need to declare a MKPolyline with your array of CLLocationCoordinate2D:

let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)

Then on your MKMapViewDelegate you would need to add color to your polyline like in this example:

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {

    if let routePolyline = overlay as? MKPolyline {
        let renderer = MKPolylineRenderer(polyline: routePolyline)
        renderer.strokeColor = UIColor.mySpecialBlue().withAlphaComponent(0.9)
        renderer.lineWidth = 7
        return renderer
    } 

    return MKOverlayRenderer()
}

With this approach you will be able to recreate something like this: Urbvan App

Goldshell answered 4/9, 2020 at 15:34 Comment(0)
L
0

First, confirm whether your locations was empty array or not.

Second, the viewForOverlay is an old method that isn’t used any more (and even then, the method signature is incorrect).

Instead, put your code that creates the renderer in rendererFor:

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    ...
}
Lishalishe answered 19/9, 2019 at 15:18 Comment(5)
Hey Rob! I can confirm through debugger the array isn't empty. It starts out as doubles but I cast those to an array of CLLocationCoordinate2D. I get an error in the return nil. And if I return an MKOverlayRenderer, it gives me an error as well, expression of type MKOverlayRenderer.TypeExecutor
Weird!!....I got the overlay but its drawing the route wrong. It seems to be from the location rather than the index of location. Meaning it seems to be drawing to the closest point..wich might not be the next actual point from the array. The array is the locations from start to finish of a drive. I'll do some investigating.Executor
Re your debugging info, that’s great. I actually assumed as much, given your last question, but had to mention it for the sake of future readers who hadn’t seen that. When you supply “expected output”, it is always nice if you can also share what the “actual output” was. ;)Lishalishe
Got it! Hey any idea why it might be drawing the "route" wrong? I understand an overlay is not a representation of an actual route, but , it seems to connect the closest annotations rather than annotation by index. Imagine driving through a neighborhood with one way streets and the poly line is telling you you drove the wrong way... LOL!!Executor
Re order not what you expected, I’ll wager that the order in the array is the order that it was rendered in the polyline. It’s pretty robust mechanism and it’s not going to reorder stuff on you. I’m wondering if perhaps you have some interim unordered structure (e.g. with a dictionary or set, it doesn’t matter the order that you added data, the resulting collection is unordered, i.e., may come out in any order). If you don’t find it, please share a minimal yet reproducible example.Lishalishe

© 2022 - 2024 — McMap. All rights reserved.