WY34
WY34

Reputation: 391

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)

Upvotes: 0

Views: 584

Answers (1)

Russell
Russell

Reputation: 5554

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

Upvotes: 1

Related Questions