从一个坐标点开始,计算距离该坐标点x米、y度的新坐标点。

31

在文档中可能有我没注意到的东西,我本以为这很容易...

如果我有一个坐标并想获得距离该坐标x米远的新坐标,在某个方向上。我该怎么做?

我正在寻找类似于

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

谢谢!

4个回答

34

很遗憾,API中没有提供这样的功能,所以您需要编写自己的功能。

这个网站 提供了几个涉及纬度/经度和示例JavaScript代码的计算。特别是,标题为“从起始点计算距离和方位角的目标点”部分显示了如何计算您所要求的内容。

JavaScript代码位于该页面底部,以下是将其转换为Objective-C的一种可能方法:

- (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代码中,它包含this link,该链接显示了大于地球周长四分之一的距离的更精确计算。
另外请注意,上述代码接受以公里为单位的距离,因此在传递之前请确保将米除以1000.0。

谢谢您的回答!实际上,我找到了一种方法来做到这一点。请看我的回答。 - Nicsoft
好的答案,我喜欢这个答案,因为它直接涉及到坐标,并更全面地回答了问题,因为它考虑了方向。 - johnrechd

14

我找到了一种解决方法,不过需要深入挖掘才能找到正确的结构体和函数。最终,我选择使用米而不是角度来表示纬度和经度。

这是我是如何做到的:

-(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;

}

当然,如果将来确实需要使用度数,对上面的代码进行一些更改以使其按我实际要求工作应该相当容易(我想...)。


简单而有效地满足我的需求。谢谢! - vietstone
2
那么你最终如何处理这些度? - Sjoerd Perfors

6
尼克软件的答案非常棒,正是我所需要的。我创建了一个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
可能更好的名称应该是“翻译”,因为它在技术上是一种翻译而不是转换。 - Dean Kelly
如果我知道角度,我该如何利用它? - Abin Baby

6

使用MKCoordinateRegion存在一些问题——返回的区域可能会被调整以适应,因为两个增量可能不完全映射到该纬度的投影上,如果您想要其中一个轴的零增量,那么您就没那么幸运了等。

此函数使用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;
}

这个答案对我非常有用,它允许我将一个MapItem.placemark.region(它是一个CLCircularRegion;它的半径以米为单位给出)转换为一个边界框区域。 - John Stricker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接