swiftmapkitmkpolyline

Drawing MKPolyline to be more accurate


So I am creating an app to track a user's running routes. I am to show a polyline that represents where a user has ran, between a start annotation that is dropped when user begins and a end annotation that is dropped when user clicks a finish button. Seeing as how someone can run pretty much anywhere, is there a way to draw a polyline that is Not limited to just main roads and streets? For example if someone runs somewhere that does not have main roads/streets, how would I show the polyline going through that area on the map? (See Image) Or is that not even possible in swift? enter image description here

In addition, is it possible to fix these gaps? enter image description here

Here is my code for rendering the polyline:

func drawPolyline() {
   guard let startingCoordinate = self.startingCoordinate, let endingCoordinate = self.endingCoordinate else { return }
   let request = MKDirections.Request()
   request.source = MKMapItem(placemark: MKPlacemark(coordinate: startingCoordinate))
   request.destination = MKMapItem(placemark: MKPlacemark(coordinate: endingCoordinate))
   request.transportType = .walking
        
   let directions = MKDirections(request: request)
   directions.calculate { [weak self] (response, error) in
      guard let self = self else { return }
      guard error == nil else { return }
      guard response != nil else { return }
            
      if let route = response?.routes.first {
         self.mapView.addOverlay(route.polyline)
         self.mapView.setVisibleMapRect(route.polyline.boundingMapRect, edgePadding: UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15), animated: true)
      }
    }
  }

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
   let renderer = MKPolylineRenderer(overlay: overlay               
   renderer.strokeColor = .systemBlue
   renderer.lineWidth = 3
   return renderer
}

// code to get coordinate for annotations
guard let coordinate = locationManager.location?.coordinate else { return }
let annotation = MapAnnotation(title: title, coordinate: coordinate) 
mapView.addAnnotation(annotation)

Solution

  • You will get an updated location every time it changes, and you can either build up an array of locations, or store them in a database for later retrieval.

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
    {
        // the last location presented here is the current position of the runner
        self.locations.append(locations.last)
        // store this in a database, or as a class variable
        
    }
    

    You can set the desired accuracy when you initialise your location manager

    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    

    and then when you're creating the map, create a line showing the runner's route

    let polyline = MKPolyline(coordinates: self.locations, count: self.locations.count)
    self.mapView.addOverlay(polyline)
    

    Here's an example of the output - looks like the finish is in the middle of the run, but that's because I was heading back home enter image description here