我有一个带有空间点的 MySQL 表,需要计算距离。我发现了很多关于使用 Haversine 公式执行此操作的材料,但是所有这些都假设点之间的距离很大。就我而言,我只关心短距离(< 1 英里),所以我不需要校正地球的曲率。我的直觉是使用 Haversine 公式在这么小的距离上会不准确。有什么建议么?
2 回答
你的直觉是错误的。根据维基百科(φ是纬度,ψ是经度),考虑haversine公式和haversine的定义:
还有一个相关的事实:对于较小的θ值,sin θ大约等于θ;更相关的是,它在θ中近似线性。因此,haversin θ 将近似为 ( θ /2)²。当 θ 接近零时,这种近似会变得更好。
如果纬度和经度相近,则此处应用半正弦函数的φ 2 - φ ₁ 和ψ 2 - ψ 1 将接近于零,这意味着公式近似为
(d/2r)² = (( φ ² - φ ₁) / 2)² + cos( φ ₁) cos( φ ₂) (( ψ ² - ψ ₁) / 2)²
现在请注意,此公式与二维欧几里得距离具有相同的形式,具有一些任意比例因子(请记住 ( kx )² = k² x ²,因此我们可以将常数移入和移出正方形):
k ₁ d ² = k ² Δ<em>φ² + k ₃ Δ<em>ψ²
最后,我在没有证据的情况下断言,这些任意比例因子结果与将纬度/经度变化转换为线性距离的比例因子相同。
因此,对于小距离,haversine 公式不会变得不准确;在小距离的限制下,它与普通的欧几里得距离计算完全相同。
使用 MyISAM 表中几何数据类型的点值创建点
在这些点上创建一个空间索引
使用 MBRContains() 查找值:
SELECT *
FROM table
WHERE MBRContains(LineFromText(CONCAT(
'('
, @lon + 10 / ( 111.1 / cos(RADIANS(@lon)))
, ' '
, @lat + 10 / 111.1
, ','
, @lon - 10 / ( 111.1 / cos(RADIANS(@lat)))
, ' '
, @lat - 10 / 111.1
, ')' )
,mypoint)
,或者,在 MySQL 5.1 及更高版本中:
SELECT *
FROM table
WHERE MBRContains
(
LineString
(
Point
(
@lon + 10 / ( 111.1 / COS(RADIANS(@lat))),
@lat + 10 / 111.1
)
Point
(
@lon - 10 / ( 111.1 / COS(RADIANS(@lat))),
@lat - 10 / 111.1
)
),
mypoint
)
这将选择大约在框内的所有点(@lat +/- 10 km,@lon +/- 10km)。
这实际上不是一个盒子,而是一个球面矩形:球体的经纬线段。这可能与弗朗茨约瑟夫地的普通矩形不同,但在大多数有人居住的地方都非常接近。
应用额外的过滤来选择圆圈内的所有内容(不是正方形)
可能应用额外的精细过滤来解决大圆距离(对于大距离)