MapKit and Polylines

Hi


So my aim is to draw a grid on the map for maidenhead locator grid, the grid system at world level is 20 degrees longitude and 10 degress latitude.


The grid changes at two further levels for country and local area.To draw the grid once there is would be too many polylines and the app would crash. So the idea is to use the visible rectangle area changed on the mapview.


I have implemented this just for longitude lines at the moment and have noticed three things

1 Drawining a vertical polyline at 180 longitude from -90 to 90 latitude the line can appear and disappear when viewing at different zoom levels or just panning around.

2 Drawining any polylines across - longitude to a + longitude the line fails to be drawn and not visible it needs to be drawn only from - to 0 and from 0 to + longitudes

3 The following code below draws the longitude lines for the top level maidenhead grid, however the lines dissapear and appear and flicker.


Below is the code I have implemented


func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {

DispatchQueue.main.async {

let zoomLevel = mapView.getZoomLevel()

if(mapView.overlays.count > 0)

{

for line in mapView.overlays

{

mapView.removeOverlay(line)

}

}

let northEast = mapView.convert(CGPoint(x: mapView.bounds.width, y: 0), toCoordinateFrom: mapView)

let southWest = mapView.convert(CGPoint(x: 0, y: mapView.bounds.height), toCoordinateFrom: mapView)

let minLon = 10 * Int((floor(southWest.longitude) / 10.0).rounded())

let maxLon = 10 * Int((floor(northEast.longitude) / 10.0).rounded())

let minLat = 10 * Int((floor(southWest.latitude) / 10.0).rounded())

let maxLat = 10 * Int((floor(northEast.latitude) / 10.0).rounded())


if(zoomLevel < 6)

{

for latIndex in stride(from: minLat, through: maxLat, by: 10)

{

var pointsLon : [CLLocationCoordinate2D] = [CLLocationCoordinate2D]()

if(minLon < 0 && maxLon < 0)

{

let startPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(minLon))

pointsLon.append(startPos)

let endPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(maxLon))

pointsLon.append(endPos)

}

if(minLon > 0 && maxLon > 0)

{

let startPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(minLon))

pointsLon.append(startPos)

let endPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(maxLon))

pointsLon.append(endPos)

}

if(minLon < 0 && maxLon > 0 )

{

let startPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(maxLon))

pointsLon.append(startPos)

let midPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(0))

pointsLon.append(midPos)

let endPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(minLon))

pointsLon.append(endPos)

}

if(minLon > 0 && maxLon < 0 )

{

let sPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(maxLon))

pointsLon.append(sPos)

let mPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(-180))

pointsLon.append(mPos)

let polyline = MKPolyline(coordinates: pointsLon, count: pointsLon.count)

self.polylines.append(polyline)

mapView.addOverlay(polyline, level: .aboveRoads )

pointsLon.removeAll()

let startPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(minLon))

pointsLon.append(startPos)

let midPos = CLLocationCoordinate2DMake(CLLocationDegrees(latIndex), CLLocationDegrees(180))

pointsLon.append(midPos)

}

let polyline = MKPolyline(coordinates: pointsLon, count: pointsLon.count)

self.polylines.append(polyline)

mapView.addOverlay(polyline, level: .aboveRoads )

}

}

else if(zoomLevel < 12)

{

//to be implemented

}

else{

//to be implemented

}

}


}


I have been trying to workout why this does not render properly, is their something I am doing wrong in code or is their a better approach, or is their a bug in mapkit.


Any help would be greatly appreaciated as I am out of ideas.


Thanks in advance


Mark...

An alternate solution to consider is to implement a custom overlay renderer which can draw the grid. Then you only have one renderer and won't need to worry about having too many polylines, but you will need to implement the drawing logic in a subclass of MKOverlayRenderer.

Removing and re-adding all your dozens of overlays is waaaaaay too much work to be doing in didChangeVisibleRegion. Read the documentation for that method. It specifically says your implementation must be lightweight as the method is called many times during scrolling.


edford’s suggestion of using just one overlay would be the best solution (see the old BreadCrumb sample code for an example of a custom overlay renderer) but at a minimum, only remove overlays that are no longer needed, and only add overlays that are newly needed. Re-adding all your overlays many times per second is obviously going to cause issues with flickering and unnecessary redraws.

MapKit and Polylines
 
 
Q