web-dev-qa-db-ja.com

1つの座標からxメートルとy度離れた新しい座標を計算します

私はドキュメントに何かが欠けているに違いありません、これは簡単なはずだと思いました...

座標が1つあり、ある方向にxメートル離れた新しい座標を取得したい場合。どうすればよいですか?

私はのようなものを探しています

-(CLLocationCoordinate2D) translateCoordinate:(CLLocationCoordinate2D)coordinate translateMeters:(int)meters translateDegrees:(double)degrees;

ありがとう!

30
Nicsoft

残念ながら、そのような関数はAPIで提供されていないため、独自に作成する必要があります。

このサイト 緯度/経度とサンプルJavaScriptコードを含むいくつかの計算を提供します。具体的には、「始点からの距離と方位を指定した目的地」というタイトルのセクションに、求めているものを計算する方法を示します。

JavaScriptコードはそのページの下部にあり、Objective-Cに変換する1つの可能な方法は次のとおりです。

- (double)radiansFromDegrees:(double)degrees
{
    return degrees * (M_PI/180.0);    
}

- (double)degreesFromRadians:(double)radians
{
    return radians * (180.0/M_PI);
}

- (CLLocationCoordinate2D)coordinateFromCoord:
        (CLLocationCoordinate2D)fromCoord 
        atDistanceKm:(double)distanceKm 
        atBearingDegrees:(double)bearingDegrees
{
    double distanceRadians = distanceKm / 6371.0;
      //6,371 = Earth's radius in km
    double bearingRadians = [self radiansFromDegrees:bearingDegrees];
    double fromLatRadians = [self radiansFromDegrees:fromCoord.latitude];
    double fromLonRadians = [self radiansFromDegrees:fromCoord.longitude];

    double toLatRadians = asin( sin(fromLatRadians) * cos(distanceRadians) 
        + cos(fromLatRadians) * sin(distanceRadians) * cos(bearingRadians) );

    double toLonRadians = fromLonRadians + atan2(sin(bearingRadians) 
        * sin(distanceRadians) * cos(fromLatRadians), cos(distanceRadians) 
        - sin(fromLatRadians) * sin(toLatRadians));

    // adjust toLonRadians to be in the range -180 to +180...
    toLonRadians = fmod((toLonRadians + 3*M_PI), (2*M_PI)) - M_PI;

    CLLocationCoordinate2D result;
    result.latitude = [self degreesFromRadians:toLatRadians];
    result.longitude = [self degreesFromRadians:toLonRadians];
    return result;
}

JSコードには、 このリンク が含まれています。これは、地球の円周の1/4を超える距離のより正確な計算を示しています。

また、上記のコードはkm単位の距離を受け入れるため、通過する前に必ずメートルを1000.0で割ってください。

32
user467105

私はそれを行う1つの方法を見つけ、正しい構造体と関数を見つけるために掘らなければなりませんでした。結局、度ではなくメートルを緯度と経度に使用することになりました。

これが私がそれをした方法です:

-(CLLocationCoordinate2D)translateCoord:(CLLocationCoordinate2D)coord MetersLat:(double)metersLat MetersLong:(double)metersLong{

    CLLocationCoordinate2D tempCoord;

    MKCoordinateRegion tempRegion = MKCoordinateRegionMakeWithDistance(coord, metersLat, metersLong);
    MKCoordinateSpan tempSpan = tempRegion.span;

    tempCoord.latitude = coord.latitude + tempSpan.latitudeDelta;
    tempCoord.longitude = coord.longitude + tempSpan.longitudeDelta;

    return tempCoord;

}

そしてもちろん、将来本当に学位を使用する必要がある場合は、実際に要求したように機能させるために、上記にいくつかの変更を加えるのは非常に簡単です(私は思う...)。

13
Nicsoft

MKCoordinateRegionの使用にはいくつかの問題があります。運が悪い軸のいずれかにゼロのデルタが必要な場合、2つのデルタがその緯度の投影に正確にマッピングされない可能性があるため、返される領域を調整して適合させることができます。 、など。

この関数は、MKMapPointを使用して座標変換を実行します。これにより、地図投影の座標空間内でポイントを移動し、そこから座標を抽出できます。

CLLocationCoordinate2D MKCoordinateOffsetFromCoordinate(CLLocationCoordinate2D coordinate, CLLocationDistance offsetLatMeters, CLLocationDistance offsetLongMeters) {
    MKMapPoint offsetPoint = MKMapPointForCoordinate(coordinate);

    CLLocationDistance metersPerPoint = MKMetersPerMapPointAtLatitude(coordinate.latitude);
    double latPoints = offsetLatMeters / metersPerPoint;
    offsetPoint.y += latPoints;
    double longPoints = offsetLongMeters / metersPerPoint;
    offsetPoint.x += longPoints;

    CLLocationCoordinate2D offsetCoordinate = MKCoordinateForMapPoint(offsetPoint);
    return offsetCoordinate;
}
5
John Clayton

Nicsoftの答えは素晴らしく、まさに私が必要としていたものです。 Swift 3-yバージョンを作成しました。これはもう少し簡潔で、CLLocationCoordinate2Dインスタンスで直接呼び出すことができます。

public extension CLLocationCoordinate2D {

  public func transform(using latitudinalMeters: CLLocationDistance, longitudinalMeters: CLLocationDistance) -> CLLocationCoordinate2D {
    let region = MKCoordinateRegionMakeWithDistance(self, latitudinalMeters, longitudinalMeters)
    return CLLocationCoordinate2D(latitude: latitude + region.span.latitudeDelta, longitude: longitude + region.span.longitudeDelta)
  }

}
4
Kane Cheshire