swiftmkmapviewmkoverlaymkoverlaypathrenderer

How to draw custom shapes on MKMapView


I need to draw custom shapes like Arc, Semi-circle? I tried the below code but it's not rendering anything on the MKMapView.

Is this the right way to draw custom shapes?

class ViewController: UIViewController {

  @IBOutlet weak var mapView: MKMapView!

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    mapView.delegate = self

    let center = CLLocationCoordinate2D(latitude: 15.463157486154865, longitude: 73.78846049308775)
    let radius = CLLocationCoordinate2D(latitude: 15.495608080208948, longitude: 73.83418584279791)
    addCircle(center: center, radius: radius)
  }

  private func createArcPath() -> UIBezierPath {
    let center = CLLocationCoordinate2D(latitude: 15.463157486154865, longitude: 73.78846049308775)
    // converting the coordinates to CGPoint with respect to MKMapView.
    let centerPoint = mapView.convert(center, toPointTo: self.mapView)
    // Creating bezierPath of arc.
    let path = UIBezierPath(arcCenter: centerPoint, radius: 6080.205481929489, startAngle: CGFloat.pi, endAngle: CGFloat.pi * 2, clockwise: true)
    return path
  }
}

extension ViewController: MKMapViewDelegate {
  func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is MKCircle {
      let arcRenderer = MKOverlayPathRenderer()
      arcRenderer.path = createArcPath().cgPath
      arcRenderer.strokeColor = UIColor.red
      arcRenderer.fillColor = UIColor.red
      arcRenderer.lineWidth = 10
      arcRenderer.alpha = 1
      arcRenderer.lineCap = .round
      return arcRenderer
    }
    return MKOverlayRenderer()
  }
}

extension ViewController {
  private func addCircle(center ccoordinate: CLLocationCoordinate2D, radius rcoordinate: CLLocationCoordinate2D) {
    let centerLocation = CLLocation.init(latitude: ccoordinate.latitude, longitude: ccoordinate.longitude)
    let radiusLocation = CLLocation.init(latitude: rcoordinate.latitude, longitude: rcoordinate.longitude)
    let radius = centerLocation.distance(from: radiusLocation)
    let circle = MKCircle(center: ccoordinate, radius: radius)

    mapView.addOverlay(circle)
  }
}

Solution

  • After some RND I came across a library curvyRoute & used it to draw arch on MKMapView.

    // Adds arch overlay to the mapView
    private func addArcOverlays() {
      let pointA = CLLocationCoordinate2D(latitude: 15.463157486154865, longitude: 73.78846049308775)
      let pointB = CLLocationCoordinate2D(latitude: 15.495608080208948, longitude: 73.83418584279791)
    
      mapView.addOverlay(LineOverlay(origin: pointA, destination: pointB))
      let style = LineOverlayStyle(strokeColor: .red, lineWidth: 4, alpha: 1)
      let arc = ArcOverlay(origin: pointA, destination: pointB, style: style)
      arc.radiusMultiplier = 0.5
      mapView.addOverlay(arc)
    }
    
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
      switch overlay {
      case let lineOverlay as LineOverlay:
        let linerender = MapLineOverlayRenderer(lineOverlay)
        setVisibleMapRect(linerender.overlay, animated: true)
        return linerender
    
      case let polyline as MKPolyline:
        let renderer = MKPolylineRenderer(overlay: polyline)
        renderer.strokeColor = UIColor.yellow.withAlphaComponent(0.5)
        renderer.lineWidth = 4
        return renderer
    
      default:
        return MKOverlayRenderer()
      }
    }