Identify the tapped MKOverlay Polygon

I am trying to build an app that shows some areas(polygons/overlays) on the map and when a polygon is tapped I would like to print on console print("Polygon \(zone_id) has been tapped"). The polygons are rendered from a GeoJSON file where we can also find the zone_id in the properties feature. So far I rendered the overlays on the map but I am stuck and I appreciate some guidance where to go from here.

I will paste my code that I have so far and also a snippet of the GeoJSON file.

import SwiftUI
import CoreLocation

struct Home: View {
   
  @StateObject var mapData = MapViewModel()
   
  var body: some View {
    ZStack{
       
      MapView()
        .environmentObject(mapData)
        .ignoresSafeArea(.all, edges: .all)
         
    }
  }
}

struct Home_Previews: PreviewProvider {
  static var previews: some View {
    Home()
  }
}
import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
   
  @EnvironmentObject var mapData: MapViewModel
   
  @State var restrictions: [MKOverlay] = []
   
  func makeCoordinator() -> Coordinator {
    return MapView.Coordinator()
  }
   
  func makeUIView(context: Context) -> MKMapView {
     
    let view = mapData.mapView
     
    view.showsUserLocation = true
    view.delegate = context.coordinator
     
    mapData.showRestrictedZones { (restrictions) in
      self.restrictions = restrictions
      view.addOverlays(self.restrictions)
    }
    return view
  }
   
  func updateUIView(_ uiView: MKMapView, context: Context) {
     
  }
   
  class Coordinator: NSObject, MKMapViewDelegate {
     
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
      if let polygon = overlay as? MKPolygon {
        let renderer = MKPolygonRenderer(polygon: polygon)
        renderer.fillColor = UIColor.purple.withAlphaComponent(0.2)
        renderer.strokeColor = .purple.withAlphaComponent(0.7)
         
        return renderer
      }
      return MKOverlayRenderer(overlay: overlay)
    }
  }
}
import SwiftUI
import MapKit

// All Map Data Goes here...

class MapViewModel: NSObject, ObservableObject {
   
  @Published var mapView = MKMapView()
   
   
  
  // Decode GeoJSON from the server
  func showRestrictedZones(completion: @escaping ([MKOverlay]) -> ()) {
    guard let url = URL(string: "https://flightplan.romatsa.ro/init/static/zone_restrictionate_uav.json") else {
      fatalError("Unable to get geoJSON") }
     
    downloadData(fromURL: url) { (returnedData) in
      if let data = returnedData {
        var geoJson = [MKGeoJSONObject]()
        do {
          geoJson = try MKGeoJSONDecoder().decode(data)
        } catch {
          fatalError("Unable to decode GeoJSON")
        }
        var overlays = [MKOverlay]()
        for item in geoJson {
          if let feature = item as? MKGeoJSONFeature {
            for geo in feature.geometry {
              if let polygon = geo as? MKPolygon {
                overlays.append(polygon)
                 
              }
            }
          }
        }
        DispatchQueue.main.async {
          completion(overlays)
        }
      }
    }
  }
   
  func downloadData( fromURL url: URL, completion: @escaping (_ data: Data?) -> ()) {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
      guard
        let data = data,
        error == nil,
        let response = response as? HTTPURLResponse,
        response.statusCode >= 200 && response.statusCode < 300 else {
        print("Error downloading data.")
        completion(nil)
        return
      }
      completion(data)
    }
    .resume()
  }
}
Answered by Alin-Fusaru in 706414022

Ok, I found a solution if anyone else will ever need it.

  1. I added a UITapGestureRecognizer to my map view instance.
  2. I used the MKMapView's convert(_:toCoordinateFrom:) to convert the touch point to the map coordinates
  3. I created a MKMapPoint from that coordinate and checked if the MKPolygon renderer path contains the point
  4. For the MKPolygon, being a MKShape after all, I used the .title property to assign my zone_id value parsed from the GeoJSON.

So I was able to identify which polygon was tapped.

I attached the code

Accepted Answer

Ok, I found a solution if anyone else will ever need it.

  1. I added a UITapGestureRecognizer to my map view instance.
  2. I used the MKMapView's convert(_:toCoordinateFrom:) to convert the touch point to the map coordinates
  3. I created a MKMapPoint from that coordinate and checked if the MKPolygon renderer path contains the point
  4. For the MKPolygon, being a MKShape after all, I used the .title property to assign my zone_id value parsed from the GeoJSON.

So I was able to identify which polygon was tapped.

I attached the code

Identify the tapped MKOverlay Polygon
 
 
Q