Better way to add a polygon along my gps location path?

Viewed 160

I study this app in swiftUI which should allow a farmer to track his position while sowing.

The code take the GPS location of the user and for each location received, i am calculating the coordinate at certain distance and bearing, exactly at 90 degree and 270 degree from the course of the user. (distance is the size of the seeder divided by 2) I save this calculate coordinate in an arrayLocationOffset and this coordinate will be used for draw a polygon to allow the farmer understand what it has already been sown.

On the didUpdateLocations func I'm running the following code:

   func registraPosizione (loc: [CLLocation], dimensioneInKM: Double){
        
        let diminKM = dimensioneInKM/1000 // size of half seeder transform in km ..
         // to be use to calc the offset 
        let lastPos = loc.last// last updated position
        if lastPos != nil {
    
            let coord = CLLocationCoordinate2D(latitude: (lastPos?.coordinate.latitude)!, longitude: (lastPos?.coordinate.longitude)!)
            arrayLocations.append(coord) // add location to array location  : loccoord2d
            
        // calc offset 90 and 270 for the polygon
            createCoordinatePoly(course: lastPos!.course, dimensioneInKM: diminKM)
        }
    }

here how I calculate the offset coordinate:

 func coord270(coord: CLLocationCoordinate2D, course: Double, dimensionKM: Double) -> CLLocationCoordinate2D{
        let correctBrg = Angle(degrees: course).radians + Angle(degrees: 270).radians
        let brginDeg = Angle(radians: correctBrg)
        let brgCorrect = convertToPositiveAngle(brginDeg).degrees. // if close to 360..
        let lat1 = Angle(degrees: coord.latitude).radians
        let lon1 = Angle(degrees: coord.longitude).radians
        let R = 6378.1 //#Radius of the Earth
        let d = Double(dimensionKM) //#Distance in km
        
        let lat270 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(brgCorrect))
        let lon270 = lon1 + atan((sin(brgCorrect)*sin(d/R)*cos(lat1))/(cos(d/R)-sin(lat1)*sin(lat270)))
        
        let finalLat270 = Angle(radians: lat270).degrees
        let finalLon270 = Angle(radians: lon270).degrees
        

        let coordOff = CLLocationCoordinate2D(latitude: finalLat270, longitude: finalLon270)
        debugPrint("creato offstet a 270 \(brgCorrect) ---\(finalLat270)  \(finalLon270)")
        return coordOff
        
         
        
    }
    
    
    func coord90(coord: CLLocationCoordinate2D, course: Double, dimensionKM: Double) -> CLLocationCoordinate2D{
        let correctBrg = Angle(degrees: course).radians + Angle(degrees: 90).radians
        let brginDeg = Angle(radians: correctBrg)
        let brgCorrect = convertToPositiveAngle(brginDeg).degrees // if close to 360..
        let lat1 = Angle(degrees: coord.latitude).radians
        let lon1 = Angle(degrees: coord.longitude).radians
        let R = 6378.1 //#Radius of the Earth
        let d = Double(dimensionKM) //#Distance in km
        
        let lat90 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(brgCorrect))
        let lon90 = lon1 + atan((sin(brgCorrect)*sin(d/R)*cos(lat1))/(cos(d/R)-sin(lat1)*sin(lat90)))
        
        let finalLat90 = Angle(radians: lat90).degrees
        let finalLon90 = Angle(radians: lon90).degrees
       

        let coordOff = CLLocationCoordinate2D(latitude: finalLat90, longitude: finalLon90)
        debugPrint("creato offstet 90 \(brgCorrect) ---\(finalLat90)  \(finalLon90)")
        return coordOff
        
         
        
    }

and here the func used to generate the array contain all coordinates to draw the polygon over the map in the correct order.

  func createCoordinatePoly(course: Double, dimensioneInKM:Double) {
        arrayLocationOffset = []
        let polypoint = arrayLocations.count
        debugPrint("Course now is \(course)")
        
        DispatchQueue.global().sync {
            for i in 0..<polypoint {
               
                let coord = arrayLocations[i]
                
                // calc LH
                if course <= 0 {
                    // wait that course have value
                    
                    let lhCoord = coord270(coord: coord, course: 360, dimensionKM: dimensioneInKM)
                    arrayLocationOffset.append(lhCoord)
                } else {
                    let lhCoord = coord270(coord: coord, course: course, dimensionKM: dimensioneInKM)
                
                arrayLocationOffset.append(lhCoord)
                }
            }
            var reversIndex = polypoint-1
            for _ in 0..<polypoint {
                
                let coord = arrayLocations[reversIndex]
                
                // calc RH
                if course <= 0 {
                    let RhCoord = coord90(coord: coord, course: 360, dimensionKM: dimensioneInKM)
                    arrayLocationOffset.append(RhCoord)
                    reversIndex -= 1
                } else {
                    let RhCoord = coord90(coord: coord, course: course, dimensionKM: dimensioneInKM)
                
                arrayLocationOffset.append(RhCoord)
                reversIndex -= 1
                }
            }
        }
    }

and final I have UIViewRepresentable to display the MapView

struct MapViewNew: UIViewRepresentable {
    var receivedCoordinate : [CLLocationCoordinate2D]
    let arrayOffset : [CLLocationCoordinate2D]
    
    var myMap = MKMapView(frame: .zero)
    func makeUIView(context: Context) -> some MKMapView {
     
        myMap.showsUserLocation = true
        myMap.delegate = context.coordinator
        myMap.mapType = .satellite
        myMap.userTrackingMode = .follow
        return myMap
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        
        creaLinea(from: uiView) // center line
        creaPoly(from: uiView) // polygon representing the seeder
    }
    
    func makeCoordinator() -> MapViewCoordinator {
        MapViewCoordinator(self)
    }
    
    private func creaLinea(from mapView: MKMapView) {

        let poly = MKPolyline(coordinates: receivedCoordinate, count: receivedCoordinate.count)
        mapView.addOverlay(poly)

    }
    
    
    func creaPoly(from mapView : MKMapView){
        // every time a new set of offset coordinate is calc, 
        // i delate the old polygon and add the new on

        let over = mapView.overlays 
        for overlay in over {
            if overlay is MKPolygon {
                mapView.removeOverlay(overlay)
            }
        }
        // creat new polygon
        let poligon = MKPolygon(coordinates: arrayOffset, count: arrayOffset.count)
        mapView.addOverlay(poligon)
    }
    
    
    //MARK : COORDINATOR CLASS
   
    class MapViewCoordinator: NSObject, MKMapViewDelegate {
        
        private let map: MapViewNew
        
        init(_ control: MapViewNew) {
            self.map = control
        }
        
        func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
            
            if overlay is MKPolyline {
                let render = MKPolylineRenderer(overlay: overlay)
                render.strokeColor = .blue
                render.lineWidth = 2
                return render
            } else if overlay is MKPolygon {
                let render = MKPolygonRenderer(overlay: overlay as! MKPolygon)
                render.strokeColor = .red
                render.fillColor = UIColor.black.withAlphaComponent(0.5)
                render.lineWidth = 1.0
                return render
            }
            
            
            return  MKOverlayRenderer()
            
        }
        
        
    }
}

the result is pretty much ok(see pict, only 3 coordinate manually add on the simulator).. sim my question is: is there any better way I could use to draw that area representing the job done by the seeder? or this the only way... can I improve something? or something different I can use to draw that shape along the path of the seeder?

thanks in advance .. looks for your help.. still very beginner in coding...

0 Answers
Related