-1

How can I detect if the user location is in a MKPolygon? I tried to search something like that:

check current location is in MkPolygons

but the answer is old so it doesn't fit with the current code. This is the Coordinator file

import MapKit

final class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView

init(_ parent: MapView) {
    self.parent = parent
}

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is ModelMapOverlay {
        return ModelMapOverlayView(overlay: overlay, overlayImage: UIImage(imageLiteralResourceName: "overlay_model"))
    } else if overlay is MKPolyline {
        let lineView = MKPolylineRenderer(overlay: overlay)
        lineView.strokeColor = .green

        return lineView
    } else if overlay is MKPolygon {
        let polygonView = MKPolygonRenderer(overlay: overlay)
        
        if theme == "Ciano" {
            polygonView.strokeColor = .init(red: 0/255, green: 255/255, blue: 255/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 0/255, green: 255/255, blue: 255/255, alpha: 0.1)
        } else if theme == "Rosso" {
            polygonView.strokeColor = .init(red: 255/255, green: 0/255, blue: 0/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 255/255, green: 0/255, blue: 0/255, alpha: 0.1)
        } else if theme == "Verde" {
            polygonView.strokeColor = .init(red: 0/255, green: 255/255, blue: 0/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 0/255, green: 255/255, blue: 0/255, alpha: 0.1)
        } else if theme == "Magenta" {
            polygonView.strokeColor = .init(red: 255/255, green: 0/255, blue: 255/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 255/255, green: 0/255, blue: 255/255, alpha: 0.1)
        } else if theme == "Giallo" {
            polygonView.strokeColor = .init(red: 255/255, green: 255/255, blue: 0/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 255/255, green: 255/255, blue: 0/255, alpha: 0.1)
        } else if theme == "Arancione" {
            polygonView.strokeColor = .init(red: 255/255, green: 153/255, blue: 51/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 255/255, green: 153/255, blue: 51/255, alpha: 0.1)
        } else if theme == "Verde Turchese" {
            polygonView.strokeColor = .init(red: 50/255, green: 198/255, blue: 166/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 50/255, green: 198/255, blue: 166/255, alpha: 0.1)
        } else if theme == "Blu" {
            polygonView.strokeColor = .init(red: 0/255, green: 66/255, blue: 255/255, alpha: 0.66)
            polygonView.fillColor = .init(red: 0/255, green: 66/255, blue: 255/255, alpha: 0.1)
        }/* else {
            polygonView.strokeColor = .init(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0)
            polygonView.fillColor = .init(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0)
        }*/
        polygonView.alpha = 1.0
        polygonView.lineWidth = 5.0
        
        return polygonView

    } else if let character = overlay as? Character {
        let circleView = MKCircleRenderer(overlay: character)
        circleView.strokeColor = character.color
        return circleView
    }

    return MKOverlayRenderer()
}

extension MKPolygon {
    func isCoordinateInsidePolyon(coordinate: CLLocationCoordinate2D) -> Bool {
        let polygonRenderer = MKPolygonRenderer(polygon: self)
        let currentMapPoint: MKMapPoint = MKMapPoint(coordinate)
        let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)
        if polygonRenderer.path == nil {
            return false
        } else {
            return polygonRenderer.path.contains(polygonViewPoint)
        }
    }
}

The mapView file:

import SwiftUI
import MapKit

let model = Model(filename: "ZONE_LIST")
var mapView = MKMapView() // (frame: UIScreen.main.bounds)

var theme = ""

struct MapView: UIViewRepresentable {
    
    //var coordinates: CLLocationCoordinate2D
    
    func makeUIView(context: Context) -> MKMapView {
        let latDelta = model.overlayTopLeftCoordinate.latitude - model.overlayBottomRightCoordinate.latitude

        let rootSpan = MKCoordinateSpan(latitudeDelta: fabs(latDelta), longitudeDelta: 0.99)
        let rootRegion = MKCoordinateRegion(center: model.midCoordinate, span: rootSpan)
        
        mapView.showsUserLocation = true
        
        mapView.region = rootRegion
        mapView.delegate = context.coordinator
        
        mapView.userLocation.title = "WILLIAMONE" // 39,9873 | 18,2420
        
        return mapView
    }
        
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
        
    func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
        /*let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
        let region = MKCoordinateRegion(center: coordinates, span: span)
        mapView.setRegion(region, animated: true)*/
    }
}

LocationManager file:

import MapKit

class LocationManager: NSObject, CLLocationManagerDelegate {
    
    private let locationManager = CLLocationManager()
    var location: CLLocation? = nil
    
    override init() {
        super.init()
        if CLLocationManager.locationServicesEnabled() {
            self.locationManager.delegate = self
            self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
            self.locationManager.distanceFilter = kCLDistanceFilterNone
            self.locationManager.requestWhenInUseAuthorization()
            self.locationManager.startUpdatingLocation()
        }
    }
}

in the contentview:

import SwiftUI
import MapKit

struct ContentView: View {
    
    private var locationManager = LocationManager()
    @State var isInArea: Bool = false

then in the body i used this function that call the area and the snippet of code that you have shared with me, my dear good friend :)

mapView.addOverlay(MKPolygon(coordinates: model.zona40, count: model.zona40.count)) // LECCE TANGENZIALE EST

self.isInArea = MKPolygon(coordinates: model.zona40, count: model.zona40.count).isCoordinateInsidePolyon(coordinate: locationManager)

The error is that the parameter require a CLLocationCoordinate2D instead of my LocationManager that is the user location

I hope that now the edit is more detailed

  • See if this works for you: https://stackoverflow.com/a/39690809/6257435 – DonMag Aug 04 '20 at 19:46
  • I think can work, but how can I call it into the program? – William De Marinis Aug 06 '20 at 09:10
  • I thought about should work when user location change, but I don't know how implement it. For now I will try it with gesture but if you have any idea about I'm open to every suggestion. However I created a Bool var that check if the user is in the MKPolygon but I don't know if the extension that you have found have to be in the MapView file or in the Coordinator file where there is the code about the implementation of the MKPolygon – William De Marinis Aug 06 '20 at 09:18
  • Now that I'm implementing the function I don't know how pass the var type LocationManager instead of CLLocationCordinates2D – William De Marinis Aug 06 '20 at 09:44
  • Review [ask]. You need to show the code you have so far, and explain where you're running into trouble. – DonMag Aug 06 '20 at 11:59
  • Ok, I'm sorry for that – William De Marinis Aug 06 '20 at 19:46

1 Answers1

0

I don't see any code that is actually handling the location updates?

Assuming you have implemented that in your LocationManager along the lines of:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let loc = locations.first {
        self.location = loc
    }
}

Your problematic line would change from:

self.isInArea = MKPolygon(coordinates: model.zona40, count: model.zona40.count).isCoordinateInsidePolyon(coordinate: locationManager)

to:

guard let c2D = self.locationManager.location?.coordinate else {
    return
}

self.isInArea = MKPolygon(coordinates: model.zona40, count: model.zona40.count).isCoordinateInsidePolyon(coordinate: c2D)

If you have not already implemented the didUpdateLocations delegate func, take a read through a Core Location tutorial or two.

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • i forgot to mention that I'm new to iOS development and other stuff like Swift & SwiftUI so sorry if I forgot to say that I'm not so expert :| – William De Marinis Aug 07 '20 at 15:48
  • can you share some link about these tutorials because i don't know from where I can start – William De Marinis Aug 07 '20 at 15:49
  • @WilliamDeMarinis - search google (or your favorite search engine) for `swiftui core location tutorial` ... here's a link to start - I have only take a quick look at it, so work through a few different tutorials / examples until you understand what's going on: https://adrianhall.github.io/swift/2019/11/05/swiftui-location/ – DonMag Aug 07 '20 at 16:23
  • sorry if I still disturb you but to be able to make the variable update continuously what do you suggest to do – William De Marinis Aug 07 '20 at 16:26
  • @WilliamDeMarinis - if you work through the tutorial at the link I gave you, you'll have an app that continuously updates and displays the latitude and longitude of the current location... both of which are properties of the `.coordinate` property, which is a `CLLocationCoordinate2D` object. – DonMag Aug 07 '20 at 16:57
  • Thanks for all! I make it – William De Marinis Aug 08 '20 at 16:10
  • I have a final question for you. How can implement the geocoder (I mean the snippet of code with which you can update location) in the contentView to start updating the var isInArea every moment. Should I try with location.last? – William De Marinis Aug 08 '20 at 16:45