Draw polyline using Swift - ios

I'm trying to get an understanding of how to draw polylines using Swift. I've looked at the documentation, referenced some tutorials, and checked out some other SO posts, but I still can't get the thing to draw a line on my map. Here's my code. Anyone tell me what I'm doing wrong here?
import UIKit
import MapKit
class FirstViewController: UIViewController {
#IBOutlet weak var map: MKMapView!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let location = CLLocationCoordinate2D(
latitude: -73.761105,
longitude: 41.017791
)
let span = MKCoordinateSpanMake(0.07, 0.07)
let region = MKCoordinateRegion(center: location, span: span)
map.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.setCoordinate(location)
annotation.title = "White Plains"
annotation.subtitle = "Westchester County"
map.addAnnotation(annotation)
var locations = [CLLocation(latitude: -73.761105, longitude: 41.017791), CLLocation(latitude: -73.760701,longitude: 41.019348), CLLocation(latitude: -73.757201, longitude: 41.019267), CLLocation(latitude: -73.757482, longitude: 41.016375), CLLocation(latitude: -73.761105, longitude: 41.017791)]
var coordinates = locations.map({(location: CLLocation!) -> CLLocationCoordinate2D in return location.coordinate})
var polyline = MKPolyline(coordinates: &coordinates, count: locations.count)
self.map.addOverlay(polyline)
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if overlay is MKPolyline {
var polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 5
return polylineRenderer
}
return nil
}
}
Thanks!

Here MKGeodesicPolyline will solve your problem. Add object of MKGeodesicPolyline instead of MKPolyline.
In your code remove below two lines:
let polyline = MKPolyline(coordinates: &coordinates, count: locations.count)
map.add(polyline)
And add these lines:
let geodesic = MKGeodesicPolyline(coordinates: coordinates, count: 2)
map.addOverlay(geodesic)
Swift 5.0:
func createPolyline(mapView: MKMapView) {
let point1 = CLLocationCoordinate2DMake(-73.761105, 41.017791);
let point2 = CLLocationCoordinate2DMake(-73.760701, 41.019348);
let point3 = CLLocationCoordinate2DMake(-73.757201, 41.019267);
let point4 = CLLocationCoordinate2DMake(-73.757482, 41.016375);
let point5 = CLLocationCoordinate2DMake(-73.761105, 41.017791);
let points: [CLLocationCoordinate2D]
points = [point1, point2, point3, point4, point5]
let geodesic = MKGeodesicPolyline(coordinates: points, count: 5)
map.addOverlay(geodesic)
UIView.animate(withDuration: 1.5, animations: { () -> Void in
let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
let region1 = MKCoordinateRegion(center: point1, span: span)
self.map.setRegion(region1, animated: true)
})
}
Objective C code:
- (void) createGeoPolyline {
CLLocationCoordinate2D point1 = { -73.761105, 41.017791 };
CLLocationCoordinate2D point2 = { -73.760701, 41.019348 };
CLLocationCoordinate2D point3 = { -73.757201, 41.019267 };
CLLocationCoordinate2D point4 = { -73.757482, 41.016375 };
CLLocationCoordinate2D point5 = { -73.761105, 41.017791 };
CLLocationCoordinate2D points[] = {point1, point2, point3, point4, point5};
MKGeodesicPolyline *geodesic = [MKGeodesicPolyline polylineWithCoordinates:&points[0] count:5];
[self.mapView addOverlay:geodesic];
[UIView animateWithDuration:1.5 animations:^{
MKCoordinateRegion region;
region.center = point1;
MKCoordinateSpan span;
span.latitudeDelta = 0.01;
span.longitudeDelta = 0.01;
region.span = span;
[self.mapView setRegion:region animated:YES];
}];
}
Above Objective C code works perfect and it will show overlay below:
But if you try Swift code it will not. I tried as much as I can to solve it out but It won't change. May be it is bug from MapKit framework.

UPDATE: This seems to be fixed on Swift 3+. See accepted answer.
On this line:
var polyline = MKPolyline(coordinates: &coordinates, count: locations.count)
You're casting a Swift array reference as an UnsafePointer<CLLocationCoordinate2D>.
That's pretty dangerous and I'm not sure why Swift allows it to compile. Best case scenario you get the line drawn, worse case (which seems to be your case) you get nothing.
The MKPolyline constructors wants an UsafePointer<CLLocationCoordinate2D> and that's what you should pass.
I usually add a private category to MKPolyline to create a convenience init method that accepts a normal Swift array:
private extension MKPolyline {
convenience init(coordinates coords: Array<CLLocationCoordinate2D>) {
let unsafeCoordinates = UnsafeMutablePointer<CLLocationCoordinate2D>.alloc(coords.count)
unsafeCoordinates.initializeFrom(coords)
self.init(coordinates: unsafeCoordinates, count: coords.count)
unsafeCoordinates.dealloc(coords.count)
}
}

Create polyline on apple map :
import MapKit
import CoreLocation
<CLLocationManagerDelegate,MKMapViewDelegate>
Code
self.mapView.delegate = self
var coordinateArray: [CLLocationCoordinate2D] = []
let destination1 = CLLocationCoordinate2DMake(22.3039, 70.8022)
let destination2 = CLLocationCoordinate2DMake(23.0225, 72.5714)
coordinateArray.append(destination1)
coordinateArray.append(destination2)
let polygon = MKPolyline(coordinates: coordinateArray, count: coordinateArray.count)
self.mapView.addOverlay(polygon)
Delegate Method
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay.isKind(of: MKPolyline.self){
let polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.fillColor = UIColor.blue
polylineRenderer.strokeColor = UIColor.blue
polylineRenderer.lineWidth = 2
return polylineRenderer
}
return MKOverlayRenderer(overlay: overlay)
}

Related

MapKit: Route not being displayed between two annotations

Im trying to display a route between two annotations.
The annotations and the region work fine but the route won't show up and I have no idea why
It looks like the route is not being rendered at all.
I'm sure that the route exists because I tried to print it and it is in the directionResponse.routes
Any suggestions?
I'm using SwiftUI
Then this is included in a parent view.
import SwiftUI
import MapKit
import FirebaseFirestore
struct MapView: UIViewRepresentable {
var packageLocation: GeoPoint
var destination: GeoPoint
var driverLocation = CLLocationCoordinate2D()
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
MKMapView()
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolygonRenderer(overlay: overlay)
renderer.strokeColor = .blue
renderer.lineWidth = 2.0
return renderer
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
let requestLocation: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: packageLocation.latitude, longitude: packageLocation.longitude)
let destinationLocation: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: destination.latitude, longitude: destination.longitude)
//let span = MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1)
//let region = MKCoordinateRegion(center: requestLocation, span: span)
//uiView.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = requestLocation
annotation.title = "Package Title"
uiView.addAnnotation(annotation)
let annotation2 = MKPointAnnotation()
annotation2.coordinate = destinationLocation
annotation2.title = "Destiantion"
uiView.addAnnotation(annotation2)
let sourcePlacemark = MKPlacemark(coordinate: requestLocation)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { (response, error) in
guard let directionResponse = response else {
if let error = error {
print(error.localizedDescription)
}
return
}
print(directionResponse)
let route = directionResponse.routes[0]
uiView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
uiView.setRegion(MKCoordinateRegion(rect), animated: true)
}
}
}
You've almost got it.
The one issue that you need to resolve is the use of the MKMapView delegate functions.
The easiest way to do that is to subclass MKMapView and make your own map view that has conforms to MKMapViewDelegate.
Firstly, create your own map view, subclassing MKMapView and conforming to MKMapViewDelegate. At the moment you're only really using the rendererFor overlay delegate method so I'll just implement that, but you can add other methods if you require them.
class WrappableMapView: MKMapView, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .red
renderer.lineWidth = 4.0
return renderer
}
}
Then you need to update your UIViewRepresentable to use the new WrappableMapView that you just created. I have gone for making a functional example, so here I am passing in the request and destination locations. You can handle this how you want but at least this will give you something that works.
struct MyMapView: UIViewRepresentable {
#Binding var requestLocation: CLLocationCoordinate2D
#Binding var destinationLocation: CLLocationCoordinate2D
private let mapView = WrappableMapView()
func makeUIView(context: UIViewRepresentableContext<MyMapView>) -> WrappableMapView {
mapView.delegate = mapView // make sure we set our delegate to be the mapView we just created
return mapView
}
func updateUIView(_ uiView: WrappableMapView, context: UIViewRepresentableContext<MyMapView>) {
let requestAnnotation = MKPointAnnotation()
requestAnnotation.coordinate = requestLocation
requestAnnotation.title = "Package Title"
uiView.addAnnotation(requestAnnotation)
let destinationAnnotation = MKPointAnnotation()
destinationAnnotation.coordinate = destinationLocation
destinationAnnotation.title = "Destination"
uiView.addAnnotation(destinationAnnotation)
let requestPlacemark = MKPlacemark(coordinate: requestLocation)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: requestPlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { response, error in
guard let response = response else { return }
let route = response.routes[0]
uiView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
uiView.setRegion(MKCoordinateRegion(rect), animated: true)
// if you want insets use this instead of setRegion
// uiView.setVisibleMapRect(rect, edgePadding: .init(top: 50.0, left: 50.0, bottom: 50.0, right: 50.0), animated: true)
}
}
}
Finally we can put it all together with a ContentView that shows it works:
struct ContentView: View {
#State var requestLocation = CLLocationCoordinate2D(latitude: 51.509865, longitude: -0.118092)
#State var destinationLocation = CLLocationCoordinate2D(latitude: 51.501266, longitude: -0.093210)
var body: some View {
MyMapView(requestLocation: $requestLocation, destinationLocation: $destinationLocation)
}
}
This is what it should look like:
One thing to note, using the rendererFor overlay delegate function in the simulator causes an error. This only happens in the simulator and not on device, so don't be surprised if you see an error message like this in the console.
2019-11-08 18:50:30.034066+0000 StackOverflow[80354:9526181] Compiler error: Invalid library file

MKMapView - Show Customizable Gridlines

I want these lines to be visible on a regular map in such a way where each square represents 1x1m.
I looked into MKTileOverlay but didn't find too much about it. Is it possible to show the gridline on the map as well as change the color?
I've done something very similar for an app I've been playing around with. Mine is for putting a coloured grid over a map so that there are 15 columns and rows in a square mile around a home location, so you'll need to adjust the calculations for your distances but the same general approach should work. The app is only a prototype at the moment, and hasnt been optimised (could refactor code out of viewDidLoad for a start!), but the code should be good enough to get you started.
var homeLocation: CLLocationCoordinate2D!
let metresPerMile = 1609.344
var degPerHorizEdge: Double!
var degPerVertEdge: Double!
override func viewDidLoad() {
homeLocation = CLLocationCoordinate2D(latitude: 53.7011, longitude: -2.1071)
let hd = CLLocation(latitude: homeLocation.latitude, longitude: homeLocation.longitude).distance(from: CLLocation(latitude: homeLocation.latitude + 1, longitude: homeLocation.longitude))
let vd = CLLocation(latitude: homeLocation.latitude, longitude: homeLocation.longitude).distance(from: CLLocation(latitude: homeLocation.latitude, longitude: homeLocation.longitude + 1))
let degPerHMile = 1 / (hd / metresPerMile)
let degPerVMile = 1 / (vd / metresPerMile)
degPerHorizEdge = degPerHMile / 15
degPerVertEdge = degPerVMile / 15
super.viewDidLoad()
let gridController = GridController(for: gameID!)
gridController.delegate = self
let mapSize = CLLocationDistance(1.2 * metresPerMile)
let region = MKCoordinateRegion(center: homeLocation, latitudinalMeters: mapSize, longitudinalMeters: mapSize)
mapView.delegate = self
mapView.showsUserLocation = true
mapView.showsBuildings = true
mapView.mapType = .standard
mapView.setRegion(region, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let overlays = prepareOverlays() {
mapView.addOverlays(overlays)
}
}
func prepareOverlays() -> [MKPolygon]? {
let topLeft = CLLocationCoordinate2D(latitude: homeLocation.latitude - 7.5 * degPerHorizEdge, longitude: homeLocation.longitude - degPerVertEdge * 7.5)
var overlays = [MKPolygon]()
var locations = [CLLocationCoordinate2D]()
for y in 0...14 {
for x in 0...14 {
locations.append(CLLocationCoordinate2D(latitude: topLeft.latitude + Double(x) * degPerHorizEdge, longitude: topLeft.longitude + Double(y) * degPerVertEdge))
}
}
for coord in locations.enumerated() {
let location = coord.element
var corners = [location, //has to be a var due to using pointer in next line
CLLocationCoordinate2D(latitude: location.latitude + degPerHorizEdge, longitude: location.longitude),
CLLocationCoordinate2D(latitude: location.latitude + degPerHorizEdge, longitude: location.longitude + degPerVertEdge),
CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude + degPerVertEdge)]
let overlay = MKPolygon(coordinates: &corners, count: 4)
overlay.title = "\(coord.offset)"
overlays.append(overlay)
}
return overlays.count > 0 ? overlays : ni
}
//MARK:- MKMapViewDelegate
extension MapViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
// overlay is a WSW zone
if let polygon = overlay as? MKPolygon {
let renderer = MKPolygonRenderer(polygon: polygon)
renderer.strokeColor = UIColor.gray.withAlphaComponent(0.4)
renderer.fillColor = UIColor.orange.withAlphaComponent(0.5)
renderer.lineWidth = 2
return renderer
}
// overlay is a line segment from the run (only remaining overlay type)
else {
let renderer = MKPolylineRenderer(polyline: overlay as! MKPolyline)
renderer.strokeColor = UIColor.blue.withAlphaComponent(0.8)
renderer.lineWidth = 3
return renderer
}
}
}

How to plot satellite ground track on to a map projection in Swift

I'm trying to plot the ground-track of a satellite in a given orbit in mapview. I already have the data sets that contain the x, y, z position of the satellite as well as the longitude and latitude data. I only have a problem with plotting it.
You can use MKGeodesicPolyline for that. More info here
//Replace this with whatever you have for a source of locations
var satellitePathLocations = [
CLLocation(latitude: -73.761105, longitude: 41.017791),
CLLocation(latitude: -73.760701, longitude: 41.019348),
CLLocation(latitude: -73.757201, longitude: 41.019267),
CLLocation(latitude: -73.757482, longitude: 41.016375),
CLLocation(latitude: -73.761105, longitude: 41.017791)
]
var coordinates = satellitePathLocations.map({(location: CLLocation!) -> CLLocationCoordinate2D in return location.coordinate})
let polyline = MKGeodesicPolyline(coordinates: coordinates, count: coordinates.count)
mapView.add(polyline)
// On your MKMapView delegate
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if overlay is MKGeodesicPolyline {
var polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 2
return polylineRenderer
}
return nil
}

How to draw line between two annotations in map view swift ios?

let latitude = NSUserDefaults.standardUserDefaults().doubleForKey(klat)
let longitude = NSUserDefaults.standardUserDefaults().doubleForKey(klong)
let location = CLLocationCoordinate2DMake(latitude, longitude)
// Second Location lat and long
let latitudeSec: CLLocationDegrees = 10.0100
let longitudeSec: CLLocationDegrees = 76.3620
let locationSec = CLLocationCoordinate2DMake(latitudeSec, longitudeSec)
let span = MKCoordinateSpanMake(1, 1)
let region = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: true)
I have two locations(lat and long) with two annotations. I need to know how to draw the line between these two annonations on MKMap?
Create an array of [CLLocationCoordinate2D], convert to MKPolyline and add to map.
If you have a CLLocation could get CLLocationCoordinate2D from CLLocation.coordinate
In your case...
let pointArry = [location, locationSec]
let myPolyline = MKPolyline(coordinates: pointArray, count: pointArray.count)
mapView.addOverlay(myPolyline)
//MARK: MKMapViewDelegate Method (make sure class has been set as delegate)
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay.isKind(of: MKPolyline.self) {
// draw the track
let polyLine = overlay
let polyLineRenderer = MKPolylineRenderer(overlay: polyLine)
polyLineRenderer.strokeColor = UIColor.blue
polyLineRenderer.lineWidth = 2.0
return polyLineRenderer
}
return MKPolylineRenderer()
}

Rendering multiple polylines on MapView

I have two sets of coordinates and trying to draw polylines on map view. I'm able to draw a polyline with one set of coordinates but I couldn't able to draw two polylines.
Below is the code...
func drawRouteOnMap()
{
var centerCoordinate : CLLocationCoordinate2D = CLLocationCoordinate2DMake(icRouteLat[0], icRouteLong[0])
let span = MKCoordinateSpanMake(0.001, 0.001)
var centerPosition = MKCoordinateRegionMake(centerCoordinate, span)
mapView.setRegion(centerPosition,animated:true)
self.mapView.mapType = MKMapType.Hybrid
routePointer = "one";
// first route line
//----------able to draw polyline with this set of coordinates
for i in 0..<routeLat.count-1
{
var fromCoordinate :CLLocation = CLLocation(latitude: routeLat[i], longitude: routeLong[i])
var toCoordinate :CLLocation = CLLocation(latitude: routeLat[i+1], longitude: routeLong[i+1])
var locations = [fromCoordinate, toCoordinate];
var coordinates = locations.map({(location: CLLocation) -> CLLocationCoordinate2D in return location.coordinate});
var polyLine = MKPolyline(coordinates: &coordinates, count: locations.count);
mapView.addOverlay(polyLine);
}
routePointer = "second";
// IC route line
//------Polyline for this set of coordinates doesn't appear on map view
for j in 0..<icRouteLat.count-1
{
var fromCoordinateIC :CLLocation = CLLocation(latitude: icRouteLat[j], longitude: icRouteLat[j])
var toCoordinateIC :CLLocation = CLLocation(latitude: icRouteLong[j+1], longitude: icRouteLong[j+1])
var locationsIC = [fromCoordinateIC, toCoordinateIC];
var coordinatesIC = locationsIC.map({(location: CLLocation) -> CLLocationCoordinate2D in return location.coordinate});
var polyLineIC = MKPolyline(coordinates: &coordinatesIC, count: locationsIC.count);
mapView.addOverlay(polyLineIC);
}
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
let route: MKPolyline = overlay as MKPolyline
let routeRenderer = MKPolylineRenderer(polyline:route)
routeRenderer.lineWidth = 3.0
if routePointer == "one"
{
routeRenderer.strokeColor = UIColor(red: 240.0/255.0, green: 68.0/255.0, blue: 0.0/255.0, alpha: 1);
}
else if routePointer == "second"
{
routeRenderer.strokeColor = UIColor(red: 45.0/255.0, green: 200.0/255.0, blue: 0.0/255.0, alpha: 1);
}
return routeRenderer
}
The arrays routeLat[], routeLong[] and icRouteLat[] and icRouteLong[] are two set of coordinates.
Is there anything I'm missing out here? Or is this the right way to implement?
EDIT
Updated code based on the suggestions...
func drawRouteOnMap()
{
var centerCoordinate : CLLocationCoordinate2D = CLLocationCoordinate2DMake(icRouteLat[0], icRouteLong[0])
let span = MKCoordinateSpanMake(0.001, 0.001)
var centerPosition = MKCoordinateRegionMake(centerCoordinate, span)
mapView.setRegion(centerPosition,animated:true)
self.mapView.mapType = MKMapType.Hybrid
var polyLine: MKPolyline!
var polyLineIC: MKPolyline!
// first route line
for i in 0..<routeLat.count-1
{
var fromCoordinate :CLLocation = CLLocation(latitude: routeLat[i], longitude: routeLong[i])
var toCoordinate :CLLocation = CLLocation(latitude: routeLat[i+1], longitude: routeLong[i+1])
var locations = [fromCoordinate, toCoordinate];
var coordinates = locations.map({(location: CLLocation) -> CLLocationCoordinate2D in return location.coordinate});
polyLine = MKPolyline(coordinates: &coordinates, count: locations.count);
polyLine.title = "one";
mapView.addOverlay(polyLine);
}
// IC route line
for j in 0..<icRouteLat.count-1
{
var fromCoordinateIC :CLLocation = CLLocation(latitude: icRouteLat[j], longitude: icRouteLong[j])
var toCoordinateIC :CLLocation = CLLocation(latitude: icRouteLat[j+1], longitude: icRouteLong[j+1])
var locationsIC = [fromCoordinateIC, toCoordinateIC];
var coordinatesIC = locationsIC.map({(location: CLLocation) -> CLLocationCoordinate2D in return location.coordinate});
polyLineIC = MKPolyline(coordinates: &coordinatesIC, count: locationsIC.count);
polyLineIC.title = "ic";
mapView.addOverlay(polyLineIC);
}
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if overlay is MKPolyline
{
let route: MKPolyline = overlay as MKPolyline
let routeRenderer = MKPolylineRenderer(polyline:route)
routeRenderer.lineWidth = 3.0
if overlay.title == "one"
{
routeRenderer.strokeColor = UIColor(red: 240.0/255.0, green: 68.0/255.0, blue: 0.0/255.0, alpha: 1);
}
else if overlay.title == "ic"
{
routeRenderer.strokeColor = UIColor(red: 45.0/255.0, green: 200.0/255.0, blue: 0.0/255.0, alpha: 1);
}
return routeRenderer
}
return nil
}
FINAL EDIT
Updated code:
func drawRouteOnMap()
{
var centerCoordinate : CLLocationCoordinate2D = icRoute[0];
let span = MKCoordinateSpanMake(0.001, 0.001)
var centerPosition = MKCoordinateRegionMake(centerCoordinate, span)
mapView.setRegion(centerPosition,animated:true)
self.mapView.mapType = MKMapType.Hybrid
// first route line
polyLine = MKPolyline(coordinates: &firstRoute, count: firstRoute.count);
polyLine.title = "one";
mapView.addOverlay(polyLine);
// IC route line
polyLine = MKPolyline(coordinates: &icRoute, count: icRoute.count);
polyLine.title = "ic";
mapView.addOverlay(polyLine);
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if overlay is MKPolyline
{
let route: MKPolyline = overlay as MKPolyline
let routeRenderer = MKPolylineRenderer(polyline:route)
routeRenderer.lineWidth = 3.0
if overlay.title == "one"
{
routeRenderer.strokeColor = UIColor(red: 240.0/255.0, green: 68.0/255.0, blue: 0.0/255.0, alpha: 1);
}
else if overlay.title == "ic"
{
routeRenderer.strokeColor = UIColor(red: 45.0/255.0, green: 200.0/255.0, blue: 0.0/255.0, alpha: 1);
}
return routeRenderer
}
return nil
}
The main problem is in the second for loop:
var fromCoordinateIC :CLLocation =
CLLocation(latitude: icRouteLat[j],
longitude: icRouteLat[j]) //<-- should be icRouteLong
var toCoordinateIC :CLLocation =
CLLocation(latitude: icRouteLong[j+1], //<-- should be icRouteLat
longitude: icRouteLong[j+1])
The second line is not visible (or not where you expect) because it is getting the wrong coordinates.
There are, however, some additional things (not causing or related to the main issue) I'd like to point out:
In the rendererForOverlay delegate method, the code is using the outside variable routePointer to set the color of the line. This is not recommended. You must not assume when or how often a delegate method will be called. There is no guarantee the delegate method will be called immediately after doing addOverlay. It's also possible for the delegate method to be called multiple times for the same overlay.
For this reason, you must use data directly associated with the incoming overlay object to set the renderer's properties. In the current example, a better alternative is to set each polyline's title property to "one" or "second" and eliminate the routePointer variable.
In the rendererForOverlay delegate method, it would be better to first check if overlay is of type MKPolyline before treating it like one. You may later want to add other types of overlays such as MKCircle or MKPolygon.
Currently, the code is creating a separate MKPolyline for each line segment in each route. So if route "one" has 10 line segments and route "second" has 15, the code is currently adding 25 overlays. This is not necessary. An MKPolyline can draw multiple line segments. It would be much more efficient to add all the coordinates for a route into an array and after the loop, create and add the MKPolyline. That way, you would only be adding 2 overlays.
Example of creating a single overlay for each route instead of creating multiple overlays for each route (one for each line segment in the route):
//First add all the coordinates to an array...
var coordinates: [CLLocationCoordinate2D] = [CLLocationCoordinate2D]()
for i in 0 ..< routeLat.count
{
var coordinate = CLLocationCoordinate2DMake(routeLat[i], routeLong[i])
coordinates.append(coordinate)
}
//Then create a single overlay with ALL the coordinates in the route...
polyLine = MKPolyline(coordinates: &coordinates, count: coordinates.count);
polyLine.title = "one";
mapView.addOverlay(polyLine);
It's not necessary to define separate arrays for latitude and longitude where each array is a list of doubles. It would be much more efficient and will simplify the code significantly to keep a single array of coordinates (of type CLLocationCoordinate2D) for each route. An MKPolyline can then be created from this array without any looping.
Example of using single array of CLLocationCoordinate2Ds for each route:
var routeOneCoordinates = [CLLocationCoordinate2DMake(30.0, -87.0),
CLLocationCoordinate2DMake(32.0, -84.0),
CLLocationCoordinate2DMake(31.5, -83.5),
CLLocationCoordinate2DMake(31.0, -83.0),
CLLocationCoordinate2DMake(33.5, -82.0)]
polyLine = MKPolyline(coordinates: &routeOneCoordinates, count: routeOneCoordinates.count);
polyLine.title = "one";
mapView.addOverlay(polyLine);

Resources