计算我的位置和Swift上的MapKit引脚之间的距离

时间:2017-05-23 16:00:44

标签: ios swift geolocation mapkit mapkitannotation

我需要你的帮助,我正在一个应用程序上工作,我有一些针脚(位置),我想要的是获得每个和我的位置之间的距离。我的代码如下

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)
}

当我运行代码时,地图会显示引脚,但我还能做些什么才能开始计算距离?谢谢!

5 个答案:

答案 0 :(得分:7)

您必须将注释的坐标转换为CLLocation类型,然后获取它们之间的距离。要忽略坐标的高度,因为它们是2D,只需使用2D坐标的纬度和经度属性,如下所示:

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

但是,CLLocation还有其他一些属性,例如速度和高度,所以如果你想要考虑那些因素,我必须提供更多信息。要找到两个位置之间的距离,请执行以下操作:

let distance = loc1.distance(from: loc2)

这将以米为单位给出你的答案。

答案 1 :(得分:3)

创建辅助函数来计算用户位置与给定MKPointAnnotation引脚之间的距离

/// Returns the distance (in meters) from the
/// user's 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)
}

最后,为了让用户与圣保罗医院保持距离:

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

地理定位跟踪延迟。但是有一个问题:由于MapKit / CoreLocation地理位置跟踪可能仍在后台运行,因此用户距离可能不会始终始终

解决这个问题的一种方法是在最终计算距离之前符合MKMapViewDelegate protocol并等待mapView(_:didUpdate:) callback

答案 2 :(得分:1)

很容易在下面尝试我的代码。

别忘了导入CoreLocation或MapKit,希望它对您有帮助

func calculateDistancefrom(sourceLocation: MKMapItem, destinationLocation: MKMapItem, doneSearching: @escaping (_ expectedTravelTim: TimeInterval) -> Void) {

        let request: MKDirectionsRequest = MKDirectionsRequest()

        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(lat: Double, lon: Double, completionHandler: @escaping (_ distance: Int) -> Void) {

        let destinationItem =  MKMapItem(placemark: MKPlacemark(coordinate: CLLocationCoordinate2DMake(lat, lon)))
        guard let currentLocation = self.locationManager?.location else { return }
        let sourceItem =  MKMapItem(placemark: MKPlacemark(coordinate: currentLocation.coordinate))

            self.calculateDistancefrom(sourceLocation: sourceItem, destinationLocation: destinationItem, doneSearching: { distance in
                completionHandler(distance)
            })
    }


   //Thereafter get the distance in meters by calling 

         self.getDistance(lat: yourLat, lon: YourLon) { distance in

            }

 //you can divide by 1000 to convert to KM...  .etc 

答案 3 :(得分:0)

回想一下,你需要先指定你想要的“距离”。如果您正在寻找简单的Euclidean Distance,那么任何其他答案或使用distanceFromLocation都可以。根据Apple关于distanceFromLocation

的文件
  

此方法通过跟踪测量两个位置之间的距离   它们之间的一条线跟随地球的曲率。该   产生的弧线是一条平滑的曲线并没有考虑在内   两个地点之间的特定高度变化。

这意味着,使用此方法得出的距离不是两点之间的实际路线/运输距离。 如果这是你正在寻找的,那么请转到我上面链接的答案,如果没有,那么继续阅读(但不管怎样,我鼓励你阅读整个帖子:)。

如果您正在寻找位置与地图中其他注释之间的“路线”距离(可驾驶,可步行等),那么使用MKRoute对象将需要更多工作。更具体地说,您需要先访问每个注释的MKMapItem个对象,然后像下面的自定义方法才能获得两个{{1}之间的路由信息对象。

注意 - 如果您没有MapItem,那么您可以使用每个注释的坐标创建它们,如此

MapItems

在您的类(或ViewController类)中全局定义MKRoute变量。此ley myCoordinates CLLocationCoordinate2D(latitude: 25.647399800, longitude: -100.334304500) let myPlacemark = MKPlacemark(coordinate: myCoordinates) let myMapItem = MKMapItem(placemark: myPlacemark) 将在两点之间保存计算出的路线信息。

var

然后

var route: MKRoute!

用法是

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
        }
    }

其中self.getDistanceToDestination(srcMapItem: yourSourceMapItemObj, destMapItem: yourDestinationMapitemObj) yourSourceMapItemObj是两个yourDestinationMapitemObj个对象,即源点和目标点。

然后您可以使用MapItem访问距离,以获得self.route.distance返回的第一条最佳路线的距离。 MKRoute对象MKRoute还有很多其他属性,您可以使用这些属性来显示/计算其他内容,我建议您使用look at those too。您可以使用上面的函数绘制route,即显示ployLine中两个位置之间的路线,只需在上面的自定义方法的末尾添加MapView然后使用下面的self.mapView.add(self.route.polyline)函数渲染折线。

MKMapViewDelegate

最后,请确保您的课程(或您的课程扩展程序)符合func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { let linerenderer = MKPolylineRenderer(overlay: self.route.polyline) linerenderer.strokeColor = .blue linerenderer.lineWidth = 3.5 return linerenderer } CLLocationManagerDelegate协议,并且mapview委托指向MKMapViewDelegate(我假设您已经这样做)按顺序为了上述一切工作。

答案 4 :(得分:0)

使用MapKit和Swift 5

计算两个位置之间的距离

示例功能:我已经在Google Map和Apple Map中进行了测试

        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)
        })
    }