Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
762 views
in Technique[技术] by (71.8m points)

ios - How to streamline multiple coordinate poly line entries in MKMapKit

I am trying to add multiple poly lines onto a map using mkmapkit. These poly lines indicate walking zones in my area. The problem is that my code is too bulky for a large amount of walking zones.

At the moment my code only indicates 2 walking routes but for instance if I want to add 100 or 1000 walking routes the code would be massive. I'm sure there is a way I could stream line this code so I could add in multiple walking zones with a lot less code but in not too sure the best way to go about it.

import UIKit
import MapKit

class customPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?

init(pinTitle:String, pinSubTitle:String, location:CLLocationCoordinate2D) {
    self.title = pinTitle
    self.subtitle = pinSubTitle
    self.coordinate = location
}
}

class ViewController: UIViewController, MKMapViewDelegate {

@IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    //co-ordinates
    let zone1S = CLLocationCoordinate2D(latitude: 52.100525, longitude: -9.623071)
    let zone1E = CLLocationCoordinate2D(latitude: 52.07241, longitude: -9.575299)

    let zone2S = CLLocationCoordinate2D(latitude: 52.054161, longitude: -9.385031)
    let zone2E = CLLocationCoordinate2D(latitude: 52.081185, longitude: -9.247033)


    //pins
    let zone1PinS = customPin(pinTitle: "Zone 1 Start", pinSubTitle: "", location: zone1S)
    let zone1PinE = customPin(pinTitle: "Zone 1 End", pinSubTitle: "", location: zone1E)
    self.mapView.addAnnotation(zone1PinS)
    self.mapView.addAnnotation(zone1PinE)

    let zone2PinS = customPin(pinTitle: "Zone 2 Start", pinSubTitle: "", location: zone2S)
    let zone2PinE = customPin(pinTitle: "Zone 2 End", pinSubTitle: "", location: zone2E)
    self.mapView.addAnnotation(zone2PinS)
    self.mapView.addAnnotation(zone2PinE)


    let zone1PlacemarkS = MKPlacemark(coordinate: zone1S)
    let zone1PlacemarkE = MKPlacemark(coordinate: zone1E)

    let zone2PlacemarkS = MKPlacemark(coordinate: zone2S)
    let zone2PlacemarkE = MKPlacemark(coordinate: zone2E)


    //add polyline to map
    let directionRequestZone1 = MKDirections.Request()
    directionRequestZone1.source = MKMapItem(placemark: zone1PlacemarkS)
    directionRequestZone1.destination = MKMapItem(placemark: zone1PlacemarkE)

    let directionRequestZone2 = MKDirections.Request()
    directionRequestZone2.source = MKMapItem(placemark: zone2PlacemarkS)
    directionRequestZone2.destination = MKMapItem(placemark: zone2PlacemarkE)


    //type of commute
    directionRequestZone1.transportType = .automobile
     directionRequestZone2.transportType = .automobile


    let directions1 = MKDirections(request: directionRequestZone1)
    directions1.calculate { (response, error) in
        guard let directionResonse = response else {
            if let error = error {
                print("we have error getting directions==(error.localizedDescription)")
            }
            return
        }

        let route = directionResonse.routes[0]
        self.mapView.addOverlay(route.polyline, level: .aboveRoads)


        let rect = route.polyline.boundingMapRect
        //zooming in on location
       // self.mapView.setRegion(MKCoordinateRegion(rect), animated: true)
    }


    let directions2 = MKDirections(request: directionRequestZone2)
    directions2.calculate { (response, error) in
        guard let directionResonse = response else {
            if let error = error {
                print("we have error getting directions==(error.localizedDescription)")
            }
            return
        }

        let route2 = directionResonse.routes[0]
        self.mapView.addOverlay(route2.polyline, level: .aboveRoads)


        let rect = route2.polyline.boundingMapRect
        //zooming in on location
       // self.mapView.setRegion(MKCoordinateRegion(rect), animated: true)
    }


    //set delegate for mapview
    self.mapView.delegate = self
}


func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    let renderer = MKPolylineRenderer(overlay: overlay)
    renderer.strokeColor = UIColor.red
    renderer.lineWidth = 5.0
    return renderer
}
}

This is how it looks:

coordinate

UPDATE: My attempt to use loops hasn't worked. I seem to have a loop working for dropping the start and end zone pins however it doesn't seem to work for drawing the poly lines.

        struct Location {
        let title: String
        let latitude: Double
        let longitude: Double
    }

    let locationsStart = [
        Location(title: "Start",    latitude: 52.100525, longitude: -9.623071)
    ]

    let locationsEnd = [
        Location(title: "End",    latitude: 52.07241, longitude: -9.575299)
    ]

    for location in locationsStart {
        let annotation = MKPointAnnotation()
        annotation.title = location.title
        annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
        mapView.addAnnotation(annotation)

        let directionRequestZone1 = MKDirections.Request()
        let zonePlacemarkS = MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude))
        let directionRequest = MKDirections.Request()
        directionRequest.source = MKMapItem(placemark: zonePlacemarkS)
        directionRequestZone1.transportType = .automobile
    }

    for location in locationsEnd {
        let annotation = MKPointAnnotation()
        annotation.title = location.title
        annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
        mapView.addAnnotation(annotation)

        let directionRequestZone1 = MKDirections.Request()
        let zonePlacemarkE = MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude))
        let directionRequest = MKDirections.Request()
        directionRequest.destination = MKMapItem(placemark: zonePlacemarkE)
        directionRequestZone1.transportType = .automobile

        let directions1 = MKDirections(request: directionRequestZone1)
        directions1.calculate { (response, error) in
            guard let directionResonse = response else {
                if let error = error {
                    print("we have error getting directions==(error.localizedDescription)")
                }
                return
            }

            let route = directionResonse.routes[0]
            self.mapView.addOverlay(route.polyline, level: .aboveRoads)


            let rect = route.polyline.boundingMapRect
        }
    }
           //set delegate for mapview
           self.mapView.delegate = self
}


func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    let renderer = MKPolylineRenderer(overlay: overlay)
    renderer.strokeColor = UIColor.red
    renderer.lineWidth = 5.0
    return renderer
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I adapted your code as follows:

let zone1S = CLLocationCoordinate2D(latitude: 52.100525, longitude: -9.623071)
let zone1E = CLLocationCoordinate2D(latitude: 52.07241, longitude: -9.575299)
let zone2S = CLLocationCoordinate2D(latitude: 52.054161, longitude: -9.385031)
let zone2E = CLLocationCoordinate2D(latitude: 52.081185, longitude: -9.247033)

let zones = [(start:zone1S, end:zone1E), (start:zone2S, end:zone2E)]
for (i, zone) in zones.enumerated() {
    let pinS = customPin(pinTitle: "Zone (i+1) Start", pinSubTitle: "", location: zone.start)
    let pinE = customPin(pinTitle: "Zone (i+1) End", pinSubTitle: "", location: zone.end)
    self.mapView.addAnnotation(pinS)
    self.mapView.addAnnotation(pinE)
    let placeS = MKPlacemark(coordinate: zone.start)
    let placeE = MKPlacemark(coordinate: zone.end)
    let req = MKDirections.Request()
    req.source = MKMapItem(placemark: placeS)
    req.destination = MKMapItem(placemark: placeE)
    req.transportType = .automobile
    let dir = MKDirections(request: req)
    dir.calculate { (response, error) in
        guard let directionResponse = response else {
            if let error = error {
                print("we have error getting directions==(error.localizedDescription)")
            }
            return
        }
        DispatchQueue.main.async {
            let route = directionResponse.routes[0]
            self.mapView.addOverlay(route.polyline, level: .aboveRoads)
        }
    }
}

Clearly this can be trivially extended to any number of zones. (It may be that we should be using something like a DispatchGroup to prevent the networking calculate calls from piling up too quickly, but the goal was to solve it for two pairs of coordinates and this seems to work fine.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...