2011-09-02 69 views
16

我有一個CLLocation定義,我想移動那點x米東部和米米南部。我如何實現這一目標?移動CLLocation x米

+2

請記住,你不能總是從地球上的所有點向北/南移動 - 例如,如果你在北極,你只能往南走。你想在這裏做什麼? – duskwuff

+0

@duskwuff:爲了簡單起見,我希望我的userPos向右步100步,向後退100步:-) – Oliver

回答

4

有一個C函數接近你的要求,但它需要一個方位和距離。它位於我的UtilitiesGeo課程github中。你會從你的CLLocation將它傳遞的經度和緯度,然後從產生LAT2創建一個新的CLLocation和lon2它返回:

/*------------------------------------------------------------------------- 
* Given a starting lat/lon point on earth, distance (in meters) 
* and bearing, calculates destination coordinates lat2/lon2. 
* 
* all params in degrees 
*-------------------------------------------------------------------------*/ 
void destCoordsInDegrees(double lat1, double lon1, 
         double distanceMeters, double bearing, 
         double* lat2, double* lon2); 

如果你不能使用,看一看的算法它來源於herehere,也許你可以修改它,或者這些網站可能有更接近你的需求的東西。

+0

,它看起來非常非常接近我正在搜索的內容。軸承參數將有助於:-)今晚我會試試這個。 – Oliver

+0

此功能是否將距離儀用作球體表面或球體上的米? – Oliver

+0

爲什麼你正常化180經度而不是緯度? – Oliver

16

大後,這裏的對象 - 包裝爲那些誰愛的複製/粘貼:

- (CLLocationCoordinate2D) locationWithBearing:(float)bearing distance:(float)distanceMeters fromLocation:(CLLocationCoordinate2D)origin { 
    CLLocationCoordinate2D target; 
    const double distRadians = distanceMeters/(6372797.6); // earth radius in meters 

    float lat1 = origin.latitude * M_PI/180; 
    float lon1 = origin.longitude * M_PI/180; 

    float lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing)); 
    float lon2 = lon1 + atan2(sin(bearing) * sin(distRadians) * cos(lat1), 
        cos(distRadians) - sin(lat1) * sin(lat2)); 

    target.latitude = lat2 * 180/M_PI; 
    target.longitude = lon2 * 180/M_PI; // no need to normalize a heading in degrees to be within -179.999999° to 180.00000° 

    return target; 
} 
+0

無法正常工作。使用相同的方位爲不同的距離提供不同的位置。 – kirander

19

A轉換到斯威夫特,從this answer採取:

func locationWithBearing(bearing:Double, distanceMeters:Double, origin:CLLocationCoordinate2D) -> CLLocationCoordinate2D { 
    let distRadians = distanceMeters/(6372797.6) // earth radius in meters 

    let lat1 = origin.latitude * M_PI/180 
    let lon1 = origin.longitude * M_PI/180 

    let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing)) 
    let lon2 = lon1 + atan2(sin(bearing) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2)) 

    return CLLocationCoordinate2D(latitude: lat2 * 180/M_PI, longitude: lon2 * 180/M_PI) 
} 

摩根陳寫了這:

此方法中的所有數學運算均以弧度表示。在 方法開始時,lon1和lat1被轉換爲弧度,作爲 。軸承也是弧度。請記住,這種方法需要考慮地球的曲率,對於小距離你並不需要做 。

+0

親愛的彼得,謝謝你的迅速解決方案,但我需要糾正一件事。軸承應該以弧度不加倍。我將發佈它作爲答案,因爲我無法在此處粘貼代碼。 –

+7

如果對任何人都不清楚,軸承指的是你想要向前進的方向,以度爲單位,所以對於北方:軸承= 0,東方:軸承= 90,西南:軸承= 225等等。 –

14

改進了對彼得斯答案的迅速解決方案。只有修正是在計算完成後,軸承應該是弧度。

func locationWithBearing(bearing:Double, distanceMeters:Double, origin:CLLocationCoordinate2D) -> CLLocationCoordinate2D { 
    let distRadians = distanceMeters/(6372797.6) 

    var rbearing = bearing * M_PI/180.0 

    let lat1 = origin.latitude * M_PI/180 
    let lon1 = origin.longitude * M_PI/180 

    let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(rbearing)) 
    let lon2 = lon1 + atan2(sin(rbearing) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2)) 

    return CLLocationCoordinate2D(latitude: lat2 * 180/M_PI, longitude: lon2 * 180/M_PI) 
} 
+0

I'已應用您的解決方案。大多數情況下它工作正常,但也有一些偏差。這是爲什麼。在這裏問:http://stackoverflow.com/questions/36382149/moving-gmsmarker-by-x-meters-deflects –

3

對@CocoaChris的輕微調整回答:現在是CLLocation上的一個類別,並使用內置單元。

#import <CoreLocation/CoreLocation.h> 


@interface CLLocation (Movement) 

- (CLLocation *)locationByMovingDistance:(double)distanceMeters withBearing:(CLLocationDirection)bearingDegrees; 

@end 


@implementation CLLocation (Movement) 

- (CLLocation *)locationByMovingDistance:(double)distanceMeters withBearing:(CLLocationDirection)bearingDegrees 
{ 
    const double distanceRadians = distanceMeters/(6372797.6); // earth radius in meters 
    const double bearingRadians = bearingDegrees * M_PI/180; 

    float lat1 = self.coordinate.latitude * M_PI/180; 
    float lon1 = self.coordinate.longitude * M_PI/180; 

    float lat2 = asin(sin(lat1) * cos(distanceRadians) + cos(lat1) * sin(distanceRadians) * cos(bearingRadians)); 
    float lon2 = lon1 + atan2(sin(bearingRadians) * sin(distanceRadians) * cos(lat1), 
           cos(distanceRadians) - sin(lat1) * sin(lat2)); 

    return [[CLLocation alloc] initWithLatitude:lat2 * 180/M_PI 
             longitude:lon2 * 180/M_PI]; 
} 

@end 
1

使用Measurement結構進行快速實現來完成度和弧度之間的轉換。

class GPSLocation { 

public class func degreesToRadians(degrees: Double) -> Double { 
     return Measurement(value: degrees, unit: UnitAngle.degrees).converted(to: .radians).value 
    } 

    public class func radiansToDegrees(radians: Double) -> Double { 
     return Measurement(value: radians, unit: UnitAngle.radians).converted(to: .degrees).value 
    } 

    public class func location(location: CLLocation, byMovingDistance distance: Double, withBearing bearingDegrees:CLLocationDirection) -> CLLocation { 
     let distanceRadians: Double = distance/6372797.6 
     let bearingRadians: Double = GPSLocation.degreesToRadians(degrees: bearingDegrees) 

     let lat1 = GPSLocation.degreesToRadians(degrees: location.coordinate.latitude) 
     let lon1 = GPSLocation.degreesToRadians(degrees: location.coordinate.longitude) 

     let lat2 = GPSLocation.radiansToDegrees(radians:asin(sin(lat1) * cos(distanceRadians) + cos(lat1) * sin(distanceRadians) * cos(bearingRadians))) 
     let lon2 = GPSLocation.radiansToDegrees(radians:lon1 + atan2(sin(bearingRadians) * sin(distanceRadians * cos(lat1)), cos(distanceRadians) - sin(lat1) * sin(lat2))) 

     return CLLocation(latitude: lat2, longitude: lon2) 
    } 

}