如何计算地理点周围的矩形?

时间:2011-04-15 04:50:27

标签: geolocation latitude-longitude cllocation

每当位置发生变化时,CLLocationManager都会将我的委托交给新的CLLocation。该位置的坐标表示为CLLocationCoordinate2D对象,该对象仅包含纬度和经度。我想取这个位置,确定南纬1000米,西经1000度,北纬1000米,东经1000米的纬度和经度。这样,我最终得到位于该位置西南方向的一个坐标和该位置的一个东北方向。

我不知道如何做到这一点,今晚我的GoogleFoo看起来很糟糕。我发现的哪些信息提供了难以理解的数学。有人帮助brotha黑客吗?如果有的话,我可以使用iOS API,但是只需对lat和long的double值进行操作的等式就更好了。它不必在厘米内准确,但在米内会很好。理想情况下,它看起来像这样:

NSArray *rect = CalculateRectangleFromLocation(
    clLocationCoordinate2D,
    1000.0
);

然后* rect将有四个值:西南角的纬度和长度以及东北角的纬度和长度。

2 个答案:

答案 0 :(得分: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)
    }
}

答案 1 :(得分:0)

我通常使用PROJ4库将纬度和经度转换为对我所在地区有用的米的投影(如果你没有更多的信息,UTM效果很好,我在北加利福尼亚州,所以我的调查员在我的区域全部在EPSG中工作:2226),以米为单位添加适当的偏移量,然后使用PROJ4转换回来。

稍后编辑:下面Jayant给出的答案很好,取决于您的米矩形需要多精确。地球不是一个球体,它甚至不是一个扁球体,所以在你的纬度和经度上增加距离的投影可能很重要。即使使用PROJ4,这些仪表也处于海平面。地理位置比你想象的要难。