web-dev-qa-db-ja.com

私の場所とMapKitピンの間の距離をSwift

私はあなたの助けが必要です、私はいくつかのピン(場所)を持っているアプリに取り組んでいます、そして私が欲しいのはそれぞれと私の場所の間の距離を取得することです。私のコードは次のとおりです

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
Daniel C.

注釈の座標をCLLocationタイプに変換してから、それらの間の距離を取得する必要があります。 2Dであるため、座標の高さを無視するには、次のように2D座標の緯度と経度のプロパティを使用します。

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

ただし、CLLocationには速度や高さなどの他のプロパティがあるため、それらを考慮に入れる場合は、より多くの情報を提供する必要があります。 2つの場所の間の距離を見つけるには、次のようにします。

let distance = loc1.distance(from: loc2)

これにより、メートル単位で2倍の答えが得られます。

9
brimstone

ユーザーの場所と指定された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ジオロケーション追跡がバックグラウンドで実行されている可能性があるため、最初はユーザー距離が常に利用できない場合があります。

これを回避する1つの方法は、 MKMapViewDelegateプロトコル に準拠し、 mapView(_:didUpdate:)コールバック を待ってから、最終的に距離を計算することです。

3
Paulo Mattos

以下の私のコードを簡単に試してください。

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 
2
Vision Mkhabela

振り返ってみると、まず探している「距離」を指定する必要があります。単純な ユークリッド距離 を探している場合は、他の回答のいずれか、または distanceFromLocation を使用すると機能します。 distanceFromLocation に関するAppleの文書によると

この方法では、地球の曲率に沿って2つの場所の間の線をトレースすることにより、2つの場所の間の距離を測定します。結果の円弧は滑らかな曲線であり、2つの場所間の特定の高度の変化を考慮していません。

これは、この方法を使用して導出された距離が、2点間の実際のルート/輸送距離ではないことを意味します。それがあなたが探しているものであるなら、私が上でリンクした答えに向かい、そうでないなら、読み続けてください(しかし、どちらにしても、私はあなたが投稿全体を読むことをお勧めします:)。

現在地と地図内の他の注釈との間の「ルート」距離(運転可能、歩行可能など)を探している場合は、MKRouteオブジェクトを使用してもう少し作業が必要になります。具体的には、最初に各アノテーションのMKMapItemオブジェクトにアクセスしてから、以下のようなカスタムメソッドにアクセスする必要があります。 2つのMapItemオブジェクト間のルート情報を取得できます。

注-MapItemsがない場合は、各注釈の座標を使用して作成できます。

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

MKRoute変数をクラス(またはViewControllerクラス)でグローバルに定義します。このvarは、計算された2点間のルート情報を保持します。

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

ここで、yourSourceMapItemObjyourDestinationMapitemObjは、ソースポイントと宛先ポイントとも呼ばれる2つのMapItemオブジェクトです。

次に、_self.route.distance_を使用して距離にアクセスし、MKRouteによって返される最初の最適なルートの距離を取得できます。 MKRouteオブジェクトrouteには、他のものを表示/計算するためにも使用できる他のプロパティがたくさんあります。 それらを見てください)を取ることをお勧めします。あまりにも 。上記の関数を使用して、カスタムの最後にself.mapView.add(self.route.polyline)を追加するだけで、ployLine、つまりMapView内の2つの場所間のルートを示す線を描画することもできます。上記の方法を実行してから、以下の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およびMKMapViewDelegateプロトコルに準拠し、mapviewデリゲートがselfを指していることを確認します(これはすでに行っていると思います)。上記のすべてが機能するために。

1
AnBisw

MapKitの使用&Swift 5

2つの場所の場所の間の距離を計算します

サンプル関数:Googleマップと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)
        })
    }
0
Mehul