Calculate distance between my location and MapKit output in Swift

I need your help, I am working on an application where I have multiple contacts (locations) and I want the distance between each and my location. My code is as follows

let annotation = MKPointAnnotation()
let annotationTwo = MKPointAnnotation()
let saintPaulHospitalBC = MKPointAnnotation()

override func viewDidLoad() {
    super.viewDidLoad()

    mapita.showsUserLocation = true // Mapita is the name of the MapView.

    annotation.coordinate = CLLocationCoordinate2D(latitude: 25.647399800, longitude: -100.334304500)
    mapita.addAnnotation(annotation)

    annotationTwo.coordinate = CLLocationCoordinate2D(latitude: 25.589339000, longitude: -100.257724800)
    mapita.addAnnotation(annotationTwo)

    saintPaulHospitalBC.coordinate = CLLocationCoordinate2D(latitude: 49.280524700, longitude:  -123.128232600)
    mapita.addAnnotation(SaintPaulHospitalBC)
}

      

When I run the code, the map shows contacts, but what else can I do to start calculating the distance? Thank!

+3


source to share


3 answers


Create a helper function to calculate the distance between the user's location and the data MKPointAnnotation

:

/// Returns the distance (in meters) from the
/// user location to the specified point.
private func userDistance(from point: MKPointAnnotation) -> Double? {
    guard let userLocation = mapita.userLocation.location else {
        return nil // User location unknown!
    }
    let pointLocation = CLLocation(
        latitude:  point.coordinate.latitude, 
        longitude: point.coordinate.longitude
    )
    return userLocation.distance(from: pointLocation)
}

      

Finally, to get the distance from the user to Saint Paul Hospital:

if let distance = userDistance(from: saintPaulHospitalBC) {
    // Use distance here...
}

      




Latency tracking geolocation . However, there is a catch: the custom distance may not always be available at the beginning, as MapKit / CoreLocation geolocation tracking may still be running in the background.

In one case, it matches the MKMapViewDelegate

protocol
and wait for the mapView(_:didUpdate:)

callback
before finally calculating its distances.

+3


source


You will need to convert the coordinates of your annotations to CLLocation types and then get the distance between them. To ignore the height of the coordinates, since they are 2D, just use the latitude and longitude properties of the 2D coordinates, for example:

let loc1 = CLLocation(latitude: coord1.latitude, longitude: coord1.longitude)

      

However, CLLocation has some other properties such as speed and altitude, so if you want to influence them, you will need to provide additional information. To find the distance between two locations, do the following:



let distance = loc1.distance(from: loc2)

      

This will give your answer as double in meters.

+2


source


To do this in retrospect, you first need to indicate what "distance" you are looking for. If you are looking for a simple Euclidean Distance then any of the other answers or using distanceFromLocation

will work. According to Apple's doc atdistanceFromLocation

This method measures the distance between two locations by tracing a line between them that follows the curvature of the earth. the resulting arc is a smooth curve and does not account for specific elevation changes between the two locations.

This means that the distance obtained using this method will not be the actual distance between routes / vehicles between two points. If this is what you are looking for then skip to the answer I linked above, if not then keep reading (but anyway, I encourage you to read the entire post :).

If you are looking for the "route" distance (driven, walkable, etc.) between your location and other annotations on the map, it takes a little more work using the feature MKRoute

. To be more specific, you need to first access the entities of MKMapItem

each of your annotations, and then a custom method as shown below will be able to get the route information between the two entities MapItem

.

Note. If you don't MapItems

, you can only create them using the coordinates of each of your annotations, for example

ley myCoordinates CLLocationCoordinate2D(latitude: 25.647399800, longitude: -100.334304500)
let myPlacemark = MKPlacemark(coordinate: myCoordinates)
let myMapItem = MKMapItem(placemark: myPlacemark)

      

Define the MKRoute variable globally in your class (or ViewController class). This var

will contain the calculated route information between the two points.

var route: MKRoute!

and then

func getDistanceToDestination(srcMapItem srcmapItem: MKMapItem, destMapItem destmapItem: MKMapItem){
        let request = MKDirectionsRequest() //create a direction request object
        request.source = srcmapItem //this is the source location mapItem object
        request.destination = destmapItem //this is the destination location mapItem object
        request.transportType = MKDirectionsTransportType.automobile //define the transportation method

        let directions = MKDirections(request: request) //request directions
        directions.calculate { (response, error) in
            guard let response = response else {
                print(error.debugDescription)
                return
            }
            self.route = response.routes[0] //get the routes, could be multiple routes in the routes[] array but usually [0] is the best route
        }
    }

      

The use will

self.getDistanceToDestination(srcMapItem: yourSourceMapItemObj, destMapItem: yourDestinationMapitemObj)

      

where yourSourceMapItemObj

and yourDestinationMapitemObj

are two objects MapItem

that are the source and end points.

And then you can access the distance using self.route.distance

to get the distance from the first best route returned MKRoute

. There are a number of other object properties MKRoute

route

that you can also use to display / calculate other things, and I recommend that you take a look at them too . You can use the above function to draw as well ployLine

, i.e. A line showing the route between the two locations in MapView

by simply adding self.mapView.add(self.route.polyline)

at the end of the above method and then using below MKMapViewDelegate

below to display the polyline.

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        let linerenderer = MKPolylineRenderer(overlay: self.route.polyline)
        linerenderer.strokeColor = .blue
        linerenderer.lineWidth = 3.5
        return linerenderer
    }

      

And finally, make sure your class (or an extension of your class) conforms to the protocols CLLocationManagerDelegate

and MKMapViewDelegate

and the mapview delegate pointed to self

(which I assume you already did) in order for the above to work.

0


source







All Articles