"从#34出来100米; Haversine Formula

时间:2013-12-29 18:11:12

标签: objective-c haversine

我对使用坐标很感兴趣,我想知道如何以米为单位获得两点(坐标)之间的距离。经过长时间的搜索,我找到了Haversine公式,以及它的Objective-C实现here

以下是(我自己修改了一下):

- (CGFloat)directMetersFromCoordinate:(CLLocation *)from toCoordinate:(CLLocation *)to {

static const double DEG_TO_RAD = 0.017453292519943295769236907684886;
static const double EARTH_RADIUS_IN_METERS = 6372797.560856;

double latitudeArc  = (from.coordinate.latitude - to.coordinate.latitude) * DEG_TO_RAD;
double longitudeArc = (from.coordinate.longitude - to.coordinate.longitude) * DEG_TO_RAD;
double latitudeH = sin(latitudeArc * 0.5);
latitudeH *= latitudeH;
double lontitudeH = sin(longitudeArc * 0.5);
lontitudeH *= lontitudeH;
double tmp = cos(from.coordinate.latitude*DEG_TO_RAD) * cos(to.coordinate.latitude*DEG_TO_RAD);
return EARTH_RADIUS_IN_METERS * 2.0 * asin(sqrt(latitudeH + tmp*lontitudeH)); }

我的问题是: 如何为当前位置获得100米距离(纬度和经度)? 这个公式对我来说太复杂了,我不明白,所以我不能“编码回来”得到我想要的结果。

我只需要实际位置(巴黎,东京,伦敦,纽约,等等)和纬度的(浮动)数字以及经度的(浮点)数字,其中(浮点数)代表距离的100米距离实际位置。

如果您打开this页面,此处可以“计算出”两点之间的100米距离(“实际”和100米之外的距离)。

例如:

Point1:47.0,19.0 Point2:47.0,19.0013190 ---那是0.1000公里(100米)的距离。

Point1:47.0,19.0 Point2:47.0008995,19.0 ---也是0.1000公里(100米)的距离。

在这里你可以看到,在那个坐标(纬度47.0和经度19.0)100米距离是0.0008995(纬度)和0.0013190(经度)。

我希望在Haversine Formula的帮助下得到这些数据,只是不知道,如何。

你能帮我解决一下吗?

谢谢!

更新 谢谢你的回答,现在我没有时间尝试,但据我所知,我没有完全解释我想要的东西。 也许这是一个更好的例子,我想如何使用这些“100米”:

所以,现在我在坐标“lat x”和“lon y”。在另一个给定的坐标“lat a”和“lon b”还有另一点(比如说酒店)。 我的问题是:如果这家酒店离我不到100米,怎么能算出来呢?所以没关系,如果它只有5米或99米,它们都比我远离100米的距离还小(或相等)。

使用我提供的代码,我可以计算出来,这就是该公式的用途。

但是,让我说,我有一百万个其他坐标(酒店位置),我想与之合作。我只需要一份清单,距离我(距离我不到100米)。所以是的,这是我身边的一个半径为100米的圆圈,我需要在那里得到结果。

花费更多的时间和资源来获取这些“百万”酒店的所有坐标并逐一计算距离,这就是为什么我认为计算出来要容易得多,在纬度上有多少100米和经度(改变我们在不同位置的值,'为什么我不能简单地使用我在上面的例子中计算出的那些)。 所以,如果我知道在伦敦的坐标(如果我在那里)有多少100米的纬度和经度,我可以简单地得到距离我100米远的酒店列表。简单划分:

if 
((hotelLocation.coordinate.latitude <= (myLocation.coordinate.latitude + "100metersInLatitude")) || (hotelLocation.coordinate.latitude >= (myLocation.coordinate.latitude - "100metersInLatitude")))
&&
((hotelLocation.coordinate.longitude <= (myLocation.coordinate.longitude + "100metersInLongitude")) || (hotelLocation.coordinate.longitude >= (myLocation.coordinate.longitude - "100metersInLongitude")))
{
   NSLog(@"Be Happy :-) !");
}

我只需要这些“100metersInLatitude”和“100metersInLongitude”,总是从“myLocation”计算。

哇,我希望,有人会理解我刚刚写下来的东西,因为这对我来说并不容易,也不是......: - )))

3 个答案:

答案 0 :(得分:2)

假设你有一个纬度和经度的点,并且你想找到另一个在轴承b上距离为d的点,当距离很小时(你说的“100米”,这个点在表面非常小)那么你可以做一个简单的近似 - 将地球表面局部视为“平坦”。这是一个实现此功能的简单C程序(使用上面的数字)。我更新了它以包括“准确”的公式 - 它只是一些计算,但它在所有距离(而不仅仅是短距离)都是准确的。我使用的等式来自你引用的链接 - 副标题“目的地点给定距离和起点承载”

更新 - 我将准确的计算移动到一个单独的函数中,并添加了一个循环来计算从0到359的所有整数轴承的新点,每30秒打印一次。这给了我在我最初评论中谈到的“圈子”。

#include <stdio.h>
#include <math.h>

double radians(double x) {
  return acos(0.0) * x / 90.0;
}

void calcNewPosition(double lat, double lon, double bearing, double d, double *newLat, double *newLon) {
  double lat1, lon1, br, pi;
  double Re = 6371000;
// convert everything to radians first:
  lat1 = radians(lat);
  lon1 = radians(lon);
  br = radians(bearing);

  pi = 2 * acos(0.0);

  double lat2, lon2;
  lat2 = asin( sin(lat1) * cos(d/Re) +
              cos( lat1 ) * sin( d / Re ) * cos(br ) );
  lon2 = lon1 + atan2(sin(br) * sin( d / Re ) * cos( lat1 ), \
    cos( d / Re ) - sin(lat1 ) * sin( lat2 ) );
  *newLat = 180. * lat2 / pi;
  *newLon = 180. * lon2 / pi;
}


int main(void) {
  double lon = 47., lat=19.;
  double newLongitude, newLatitude;
  double dx, dy, dLong, dLat;
  double Re = 6371000, d = 100, bearing = 0.0;
  double pi;
  double lat1, lon1, br;

  // convert everything to radians first:
  lat1 = radians(lat);
  lon1 = radians(lon);
  br = radians(bearing);

  pi = 2 * acos(0.0);

  // approximate calculation - using equirectangular approximation
  // and noting that distance between meridians (lines of longitude)
  // get closer at higher latitudes, with cos(latitude).
  dx = d * sin(br);                                // distance in E-W direction
  dy = d * cos(br);                                // distance in N-S direction
  dLat = 360 * dy / (2.0 * pi * Re);               // convert N-S to degrees latitude
  dLong = 360 * dx / (2.0 * pi * Re * cos(lat1));  // convert E-W to degrees longitude

  newLatitude = lat + dLat;
  newLongitude = lon + dLong;
  printf("simple forumula: the new position is %.8lf lon, %.8lf lat\n", newLongitude, newLatitude);

  // more accurate formula: based on http://www.movable-type.co.uk/scripts/latlong.html

  double lat2, lon2;
  calcNewPosition(lat, lon, bearing, d, &lat2, &lon2);
  printf("more accurate:   the new position is %.8lf lon, %.8lf lat\n", lon2, lat2);

  // now loop over all bearings and compute the "circle of points":
  int iBearing;
  double lonArray[360], latArray[360];
  for(iBearing = 0; iBearing < 360; iBearing++) {
    calcNewPosition(lat, lon, (double)iBearing, d, &latArray[iBearing], &lonArray[iBearing]);
    if (iBearing % 30 == 0) printf("bearing %03d: new lat = %.8lf, new lon = %.8lf\n", iBearing, latArray[iBearing], lonArray[iBearing]);
  }

return 0;
}

这是

的输出
simple forumula: the new position is 47.00000000 lon, 19.00089932 lat
more accurate:   the new position is 47.00000000 lon, 19.00089932 lat
bearing 000: new lat = 19.00089932, new lon = 47.00000000
bearing 030: new lat = 19.00077883, new lon = 47.00047557
bearing 060: new lat = 19.00044966, new lon = 47.00082371
bearing 090: new lat = 19.00000000, new lon = 47.00095114
bearing 120: new lat = 18.99955034, new lon = 47.00082371
bearing 150: new lat = 18.99922116, new lon = 47.00047557
bearing 180: new lat = 18.99910068, new lon = 47.00000000
bearing 210: new lat = 18.99922116, new lon = 46.99952443
bearing 240: new lat = 18.99955034, new lon = 46.99917629
bearing 270: new lat = 19.00000000, new lon = 46.99904886
bearing 300: new lat = 19.00044966, new lon = 46.99917629
bearing 330: new lat = 19.00077883, new lon = 46.99952443

正如你所看到的,它精确到几分之一米(你的代码给出了19.0008995 - 实际上你的结果可能在最后一位数字中是“错误的”,因为这两种方法同意8位有效数字,即使他们使用不同的方程式。

答案 1 :(得分:1)

如果OP希望距离当前位置一个距离(100米)的位置没有提供所需的方位,那么问题就不是真正的问题,在该点周围的圆圈中存在无限数量的点。

所以,这个答案可能是也可能不是OP想要的,这是CLLocation计算两点之间距离的方法。

创建两个CLLocation点并使用方法Have you looked at the CLLocation method - (CLLocationDistance)distanceFromLocation:(const CLLocation *)location`。

CLLocation *location1 = [[CLLocation alloc] initWithLatitude:)latitude1 longitude:longitude1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:)latitude2 longitude:longitude2];
double distance = [location1 distanceFromLocation:location2];

答案 2 :(得分:0)

赤道地球半径= 6,371公里。赤道被划分为360度经度,因此赤道处的每个度数大约为111.32 km。从赤道移向极点,这个距离在极点处减小到零。计算不同纬度的距离乘以纬度的余弦

  

3位小数,0.001度近似值   赤道111.32米   在N / S 30度时96.41米
  N / S 45度78.71米
  55.66米,60度N / S
  在75度N / S时28.82米

对于小距离(100米),可以在equirectangular projection上使用毕达哥拉斯定理来计算距离。这比Haversine或Cosines的球面定律简单。

var R = 6371; // km
lat / lng in radians

在伪代码中我不知道Objective-C

var x = (lng2-lng1) * cos((lat1+lat2)/2);
var y = (lat2-lat1);
var d = sqrt(x*x + y*y) * R;