快速计算两个位置之间的距离

问题描述 投票:1回答:2

我想获得两个地点之间的距离。我试过这段代码:

func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
   CLGeocoder().geocodeAddressString("ADDRESS OF LOC 2") {    (placemarks, error) in
   guard let placemarks = placemarks, let loc2 = placemarks.first?.location
      else {
         return
      }


    let loc1 = CLLocation(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)

    var distance = loc1.distance(from: loc2)
    print((distance/1000).rounded(), " km")
     }
}

我的问题是我的距离不对。打印结果为“2 km”

如果我计算“地图”中相同位置之间的距离,我会得到两个路线选项,长度为“2,7 km”和“2,9 km”

我错了什么?

swift macos mapkit
2个回答
2
投票

来自the documentation

该方法通过跟踪它们之间沿着地球曲率的线来测量两个位置之间的距离。产生的弧是平滑的曲线,并没有考虑两个位置之间的特定高度变化。

因此,您正在计算直线距离,“随着乌鸦飞行”,而不是跟随道路,这将导致更长的路线,就像您在地图中看到的那样。你需要像MapKit的MKDirectionsRequest这样的东西来匹配你在地图应用中看到的路线。 Ray Wenderlich has a good tutorial.

这是一个我刚刚在macOS Playground中运行的例子:

//: Playground - noun: a place where people can play

import Cocoa
import MapKit
import CoreLocation

// As we're waiting for completion handlers, don't want the playground
// to die on us just because we reach the end of the playground.
// See https://stackoverflow.com/questions/40269573/xcode-error-domain-dvtplaygroundcommunicationerrordomain-code-1
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

let geocoder = CLGeocoder()
geocoder.geocodeAddressString("1 Pall Mall East, London SW1Y 5AU") { (placemarks: [CLPlacemark]? , error: Error?) in
    if let placemarks = placemarks {
        let start_placemark = placemarks[0]
        geocoder.geocodeAddressString("Buckingham Palace, London SW1A 1AA", completionHandler: { ( placemarks: [CLPlacemark]?, error: Error?) in
            if let placemarks = placemarks {
                let end_placemark = placemarks[0]

                // Okay, we've geocoded two addresses as start_placemark and end_placemark.
                let start = MKMapItem(placemark: MKPlacemark(coordinate: start_placemark.location!.coordinate))
                let end = MKMapItem(placemark: MKPlacemark(coordinate: end_placemark.location!.coordinate))

                // Now we've got start and end MKMapItems for MapKit, based on the placemarks. Build a request for 
                // a route by car.
                let request: MKDirectionsRequest = MKDirectionsRequest()
                request.source = start
                request.destination = end
                request.transportType = MKDirectionsTransportType.automobile

                // Execute the request on an MKDirections object
                let directions = MKDirections(request: request)
                directions.calculate(completionHandler: { (response: MKDirectionsResponse?, error: Error?) in
                    // Now we should have a route.
                    if let routes = response?.routes {
                        let route = routes[0]
                        print(route.distance) // 2,307 metres.
                    }
                })
            }
        })
    }
}

2
投票

如果你想要旅行距离而不是“像乌鸦一样”,请使用MKDirections,例如:

func routes(to item: MKMapItem, completion: @escaping ([MKRoute]?, Error?) -> Void) {
    let request = MKDirections.Request()
    request.source = MKMapItem.forCurrentLocation()
    request.destination = item
    request.transportType = .automobile

    let directions = MKDirections(request: request)
    directions.calculate { response, error in
        completion(response?.routes, error)
    }
}

如果你想格式化到一个小数位,我建议使用NumberFormatter,所以它的格式适合国际用户,小数分隔符不是.

self.routes(to: item) { routes, error in
    guard let routes = routes, error == nil else {
        print(error?.localizedDescription ?? "Unknown error")
        return
    }

    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.minimumFractionDigits = 1
    formatter.maximumFractionDigits = 1

    for route in routes {
        let distance = route.distance / 1000
        print(formatter.string(from: NSNumber(value: distance))!, "km")
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.