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

Swift 快速计算两个位置之间的距离,swift,macos,mapkit,Swift,Macos,Mapkit,我想得到两个位置之间的距离。 我尝试了以下代码: func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) { CLGeocoder().geocodeAddressString("ADDRESS OF LOC 2") { (placemarks, error) in guard let placemarks = placemarks, let loc2 = placemarks.fir

我想得到两个位置之间的距离。 我尝试了以下代码:

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公里”

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

我做错了什么?

来自:

该方法通过追踪两个位置之间沿地球曲率的直线来测量两个位置之间的距离。生成的圆弧是平滑曲线,不考虑两个位置之间的特定高度变化

所以你计算的是直线距离,“就像乌鸦飞一样”,而不是沿着道路走,这会导致一条更长的路线,正如你在地图上看到的那样。你需要类似MapKit的东西来匹配你在“地图”应用程序中看到的路线

这里有一个我刚刚在macOS游乐场上找到的例子:

//: 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.
                    }
                })
            }
        })
    }
}

如果您想要行驶距离而不是“像乌鸦一样”,请使用
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")
    }
}
使用MapKit和Swift 5

计算两个位置之间的距离,它将帮助任何人

示例功能:我已经在谷歌地图和苹果地图上进行了测试

        let startLocation : CLLocation = CLLocation.init(latitude: 23.0952779, longitude: 72.5274129)
        let endLocation : CLLocation = CLLocation.init(latitude: 23.0981711, longitude: 72.5294229)
        let distance = startLocation.distance(from: endLocation)
        self.getDistance(departureDate: Date().adjust(hour: 8, minute: 0, second: 0, day: 0, month: 0), arrivalDate: Date().adjust(hour: 8, minute: 10, second: 0, day: 0, month: 0), startLocation: startLocation, endLocation: endLocation) { (distanceInMeters) in

            print("fake distance: \(distance)")
            let fakedistanceInMeter = Measurement(value: distance, unit: UnitLength.meters)
            let fakedistanceInKM = fakedistanceInMeter.converted(to: UnitLength.kilometers).value
            let fakedistanceInMiles = fakedistanceInMeter.converted(to: UnitLength.miles).value
            print("fakedistanceInKM :\(fakedistanceInKM)")
            print("fakedistanceInMiles :\(fakedistanceInMiles)")


            print("actualDistance : \(distanceInMeters)")

            let distanceInMeter = Measurement(value: distanceInMeters, unit: UnitLength.meters)
            let distanceInKM = distanceInMeter.converted(to: UnitLength.kilometers).value
            let distanceInMiles = distanceInMeter.converted(to: UnitLength.miles).value
            print("distanceInKM :\(distanceInKM)")
            print("distanceInMiles :\(distanceInMiles)")
        }

函数的使用

                    self.getDistance(departureDate: trip.departure.dateTime, arrivalDate: trip.arrival.dateTime, startLocation: startLocation, endLocation: endLocation) { (actualDistance) in
                        print("actualDistance : \(actualDistance)")
                    }

我对上述功能进行了改进,并在此处添加了代码,希望能对其他人有所帮助。

func calculateDistancefrom(departureDate: Date, arrivalDate: Date, sourceLocation: MKMapItem, destinationLocation: MKMapItem, doneSearching: @escaping (_ distance: CLLocationDistance) -> Void) {

        let request: MKDirections.Request = MKDirections.Request()

        request.departureDate = departureDate
        request.arrivalDate = arrivalDate

        request.source = sourceLocation
        request.destination = destinationLocation

        request.requestsAlternateRoutes = true
        request.transportType = .automobile

        let directions = MKDirections(request: request)
        directions.calculate { (directions, error) in
            if var routeResponse = directions?.routes {
                routeResponse.sort(by: {$0.expectedTravelTime <
                    $1.expectedTravelTime})
                let quickestRouteForSegment: MKRoute = routeResponse[0]

                doneSearching(quickestRouteForSegment.distance)
            }
        }
    }

    func getDistance(departureDate: Date, arrivalDate: Date, startLocation : CLLocation, endLocation : CLLocation, completionHandler: @escaping (_ distance: CLLocationDistance) -> Void) {

        let destinationItem =  MKMapItem(placemark: MKPlacemark(coordinate: startLocation.coordinate))
        let sourceItem      =  MKMapItem(placemark: MKPlacemark(coordinate: endLocation.coordinate))
        self.calculateDistancefrom(departureDate: departureDate, arrivalDate: arrivalDate, sourceLocation: sourceItem, destinationLocation: destinationItem, doneSearching: { distance in
            completionHandler(distance)
        })
    }
func calculatedInstanceFrom(出发日期:日期,到达日期:日期,源位置:mkmaItem,目的位置:mkmaItem,完成搜索:@escaping(u-distance:CLLocationDistance)->Void){
let请求:MKDirections.request=MKDirections.request()
request.departureDate=离开日期
request.arrivalDate=arrivalDate
request.source=sourceLocation
request.destination=destinationLocation
request.requestSalterRoutes=true
request.transportType=.automobile
let directions=MKDirections(请求:请求)
方向。计算{(方向,误差)
如果var RouterResponse=方向?.routes{
排序(按:{$0.expectedTravelTime<
$1.expectedTravelTime})
让QuicksRouteForSegment:MKRoute=routeResponse[0]
完成搜索(快速搜索路段距离)
}
}
}
func getDistance(出发日期:Date,到达日期:Date,startLocation:CLLocation,endLocation:CLLocation,completionHandler:@escaping(distance:CLLocationDistance)->Void){
设destinationItem=mkmaItem(placemark:MKPlacemark(坐标:startLocation.coordinate))
让sourceItem=MKMapItem(placemark:MKPlacemark(坐标:endLocation.coordinate))
self.calculatedInstanceFrom(出发日期:出发日期,到达日期:到达日期,源位置:sourceItem,destinationLocation:destinationItem,完成搜索:{distance in
completionHandler(距离)
})
}

您没有错,您只是使用舍入()方法删除了小数部分,即2.7公里变为2公里,因为您将其舍入了!!如果我这样做:
print(distance/1000)
结果将是:
1.74364568832
-这与2,7或2,9不同:/Ah好的,我如何通过“以下道路”获得距离?Ray Weinerlich教程是针对iOS的,这是个问题吗?@Ghost108 Ah,我没有注意到你在使用macOS——当我想到Swift时,我倾向于想到iOS,因为我已经很久没有开发macOS了!我相信MapKit的原理在两个平台上都是相似的,所以它应该能给你一个像样的提示,告诉你需要做什么。@Ghost108我刚刚在我的答案中加入了一个例子,在我的Mac上的操场上运行。希望这能让你知道你需要什么。