1

CLLocationManager は、場所が変更されるたびに新しい CLLocation をデリゲートに渡します。その場所の座標は、単純に緯度と経度を含む CLLocationCoordinate2D オブジェクトとして表されます。この位置から、南1000m西1000mの緯度経度、北1000m東1000mの緯度経度を求めたいと思います。このようにして、場所の南西に 1 つの座標、場所の北東に 1 つの座標が得られます。

これを行う方法がわかりません。今夜の GoogleFoo はかなり貧弱なようです。私が発見した情報は、不可解な数学を提供してくれました。兄弟のハッカーを助ける人はいますか? iOS API があればそれを使用しても問題ありdoubleませんが、緯度と経度の値だけを操作する方程式の方が優れています。センチメートル以内の正確さである必要はありませんが、メートル以内が望ましいでしょう。理想的には、次のようになります。

NSArray *rect = CalculateRectangleFromLocation(
    clLocationCoordinate2D,
    1000.0
);

*rect には 4 つの値があります。南西の角の緯度と経度、北東の角の緯度と経度です。

4

2 に答える 2

5

境界矩形の上/右/下/左の座標を取得するコードは次のとおりです。

LatLon.h

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

extern double radians(double degrees);
extern double degrees(double radians);

extern CLLocationCoordinate2D LatLonDestPoint(CLLocationCoordinate2D origin, double brearing, CLLocationDistance distance);

LatLon.m

const CLLocationDegrees kLatLonEarthRadius = 6371.0;

double radians(double degrees) {
    return degrees * M_PI / 180.0;
}

double degrees(double radians) {
    return radians * 180.0 / M_PI;
}

CLLocationCoordinate2D LatLonDestPoint(CLLocationCoordinate2D origin, double bearing, CLLocationDistance distance) {
    double brng = radians(bearing);
    double lat1 = radians(origin.latitude);
    double lon1 = radians(origin.longitude);

    CLLocationDegrees lat2 = asin(sin(lat1) * cos(distance / kLatLonEarthRadius) + 
                                  cos(lat1) * sin(distance / kLatLonEarthRadius) * cos(brng));
    CLLocationDegrees lon2 = lon1 + atan2(sin(brng) * sinf(distance / kLatLonEarthRadius) * cos(lat1),
                                                      cosf(distance / kLatLonEarthRadius) - sin(lat1) * sin(lat2));
    lon2 = fmod(lon2 + M_PI, 2.0 * M_PI) - M_PI;

    CLLocationCoordinate2D coordinate;
    if (! (isnan(lat2) || isnan(lon2))) {
        coordinate.latitude = degrees(lat2);
        coordinate.longitude = degrees(lon2);
    }

    return coordinate;
}

使用法

CLLocationCoordinate2D location = ...;
double distance = ...;

CLLocationCoordinate2D right = LatLonDestPoint(location, 90.0, distance);
CLLocationDegrees rectRight = right.longitude;

CLLocationCoordinate2D top = LatLonDestPoint(location, 0.0, distance);
CLLocationDegrees rectTop = top.latitude;

CLLocationCoordinate2D left = LatLonDestPoint(location, 270.0, distance);
CLLocationDegrees rectLeft = left.longitude;

CLLocationCoordinate2D bottom = LatLonDestPoint(location, 180.0, distance);
CLLocationDegrees rectBottom = bottom.latitude;

迅速

extension CLLocationCoordinate2D {
    fileprivate func radians(degrees: Double) -> Double { return degrees * .pi / 180.0 }
    fileprivate func degrees(radians: Double) -> Double { return radians * 180.0 / .pi }

    func coordinate(bearing: Double, distanceInMeter distance: CLLocationDistance) -> CLLocationCoordinate2D {
        let kLatLonEarthRadius: CLLocationDegrees = 6371.0
        let brng: Double = radians(degrees: bearing)
        let lat1: Double = radians(degrees: self.latitude)
        let lon1: Double = radians(degrees: self.longitude)

        let lat2: CLLocationDegrees = asin(
            sin(lat1) * cos(distance / kLatLonEarthRadius) +
            cos(lat1) * sin(distance / kLatLonEarthRadius) * cos(brng)
        )

        var lon2: CLLocationDegrees = lon1 + atan2(
            sin(brng) * sin(distance / kLatLonEarthRadius) * cos(lat1),
            cos(distance / kLatLonEarthRadius) - sin(lat1) * sin(lat2)
        )
        lon2 = fmod(lon2 + .pi, 2.0 * .pi) - .pi

        var coordinate = CLLocationCoordinate2D()
        if !lat2.isNaN && !lon2.isNaN {
            coordinate.latitude = degrees(radians: lat2)
            coordinate.longitude = degrees(radians: lon2)
        }
        return coordinate
    }

    func rect(distanceInMeter meter: CLLocationDistance) -> (north: Double, west: Double, south: Double, east: Double) {
        let north = coordinate(bearing: 0, distanceInMeter: meter).latitude
        let south = coordinate(bearing: 180, distanceInMeter: meter).latitude
        let east = coordinate(bearing: 90, distanceInMeter: meter).longitude
        let west = coordinate(bearing: 270, distanceInMeter: meter).longitude

        return (north: north, west: west, south: south, east: east)
    }
}
于 2011-04-15T14:24:01.710 に答える
0

私は通常、PROJ4 ライブラリを使用して、緯度と経度を私の地域に役立つメートル単位の投影法に変換します (これ以上の情報がない場合は、UTM がうまく機能します。私は北カリフォルニアにいるので、私の地域の測量士はすべて作業します)。 EPSG:2226) に適切なオフセットをメートル単位で追加し、PROJ4 を使用して元に変換します。

後の編集: 以下の Jayant の回答は、メートルの四角形がどれだけ正確である必要があるかに応じて、問題ありません。地球は球体ではなく、扁平回転楕円体でさえないため、緯度と経度に距離を追加する投影法が重要になる場合があります。PROJ4 を使用しても、これらのメーターは海面にあります。地理は思ったより難しいです。

于 2011-04-15T05:14:06.343 に答える