计算地理邻近度的公式
我需要在我的应用程序中实现Geo邻近search,但是我对使用正确的公式感到困惑。 在Web和StackOverflow中进行了一些search之后,我发现解决scheme是:
- 使用Haversine公式
-
使用大圆距离公式 - 在数据库中使用空间search引擎
选项#3真的不是我的ATM选项。 现在我有点困惑,因为我总是认为大圆距离公式和Haversine公式是同义词,但显然我错了?
Haversine公式http://i46.tinypic.com/30shbn6.png
上面的屏幕截图是从真棒地理(邻近)searchMySQL文件,并使用以下function:
ASIN, SQRT, POWER, SIN, PI, COS
我也看到了同样的公式 ( Cosines的球形定律 )的变化 ,像这样:
(3956 * ACOS(COS(RADIANS(o_lat)) * COS(RADIANS(d_lat)) * COS(RADIANS(d_lon) - RADIANS(o_lon)) + SIN(RADIANS(o_lat)) * SIN(RADIANS(d_lat))))
这使用以下function:
ACOS, COS, RADIANS, SIN
我不是math专家,但这些公式是一样的吗? 我遇到了更多的变化和公式 (比如Cosines的球形定律和Vincenty的 公式 – 这似乎是最准确的),这让我更加困惑。
我需要select一个好的通用公式来在PHP / MySQL中实现。 任何人都可以解释我上面提到的公式之间的差异吗?
- 哪一个是最快的计算?
- 哪一个提供最准确的结果?
- 在结果的速度/准确性方面哪一个最好?
我感谢您对这些问题的洞察力。
基于唯一的理论答案,我testing了以下的大圆距离公式:
- Vincenty公式
- Haversine公式
- Cosines的球形定律
Vincenty公式速度很慢,但是非常准确(低至0.5毫米) 。
Haversine公式比Vincenty公式要快得多,我能够在大约6秒内运行100万次计算,这是我所需要的。
Cosines公式的球形定律显示几乎是Haversine公式的两倍 , 精度差异对于大多数用例来说是疏忽大意的。
以下是一些testing地点:
- Google总部 (
37.422045
,-122.084347
) - 旧金山,CA (
37.77493
,-122.419416
) - 法国艾菲尔铁塔 (
2.294407
) - 悉尼歌剧院 (
151.214696
)
Google HQ – 旧金山,CA:
- 文
49 087.066 meters
公式:49 087.066 meters
- Haversine公式:
49 103.006 meters
-
49 103.006 meters
球形法则:49 103.006 meters
Google总部 – 法国艾菲尔铁塔:
- 文
8 989 724.399 meters
公式:8 989 724.399 meters
- Haversine公式:
8 967 042.917 meters
-
8 967 042.917 meters
球形法则:8 967 042.917 meters
Google总部 – 悉尼歌剧院:
- 文
11 939 773.640 meters
公式:11 939 773.640 meters
- Haversine公式:
11 952 717.240 meters
- 余弦球面法则:
11 952 717.240 meters
正如你所看到的,Haversine公式和Cosines的球面定律之间没有明显的差别 ,但是与Vincenty公式相比,它们的距离偏移高达22公里 ,因为它使用椭球近似的地球而不是球面。
假定机器具有无限精度,余弦定律和半正式公式将给出相同的结果。 Haversine公式更适合浮点错误。 然而,今天的机器有15位有效数字的双精度,而余弦定律对你来说可能工作得很好。 这两个公式都假定为球形地球,而维迪斯的迭代解(最准确的)假定为椭球体地球(事实上地球甚至不是椭球体 – 它是大地水准面)。 一些参考文献: http : //www.movable-type.co.uk/scripts/gis-faq-5.1.html
它变得更好:注意在余弦定律中使用的纬度,以及Haversine是与大地纬度不同的地心纬度。 对于一个球体来说,这两个是一样的。
哪一个计算速度最快?
从最快到最慢的顺序是:余弦定律(5 trig。calls) – > haversine(涉及sqrt) – > vicenty(必须在for循环中迭代求解)
哪一个最准确?
Vicenty。
哪一个是最好的速度和准确性都考虑?
如果你的问题领域是这样的,你想要计算的距离,地球可以被认为是平坦的,那么你可以工作(我不打算给细节)一个公式formsx = kx *经度差,y = ky *纬度差。 那么distance = sqrt(dx dx + dy dy)。 如果你的问题域是可以用距离平方来解决的话,那么你就不必采取sqrt,这个公式将会尽可能快地得到。 它具有附加的优点,可以计算vector距离 – x是东方向的距离,y是北方向的距离。 否则,尝试3,并select最适合你的情况。
所以你想要:
- 按距离p0sortinglogging
- 只select距p0的距离小于r的logging
诀窍是,你并不完全需要为此计算出大圆的距离! 你可以用任何一对点的函数来做一个真正的值,这个值是与点之间的大圆距离严格一致的 。 有很多这样的函数,有些是比许多公式精确的大圆距计算快得多。 一个这样的函数是3D中的欧几里德距离。 将纬度和经度转换为球体上的三维点不涉及反三angular函数。
一旦你有了x,Y,Z,你可以意识到你实际上并不需要从p0到你的点的距离,因为你也可以用p0的切平面的距离。 该距离也严格按照大圆距离增长,并且从X,Y,Z作为线性组合来计算 – 甚至不需要平方根。 您只需预先计算与所需的大圆距离相对应的系数和截止距离。