首页 > 解决方案 > 使用 SQLite 计算两个经纬度点之间的距离(几乎是 Haversine 公式)

问题描述

最近我开始了一个项目,我需要在给定纬度和经度的情况下计算两点之间的距离,并按距离选择和排序点。执行此操作的合乎逻辑的步骤是使用Haversine 公式

Distance = 2 * R * ASIN( SQRT( SIN( (RADIANS(lat1)-RADIANS(lat2))/2 )^2 + COS( RADIANS(lat1) )*COS( RADIANS(lat2) )*SIN( (RADIANS(long1)-RADIANS(long2))/2 )^2 ) )

这对 MySQL DB 来说不是问题,但由于某些原因,我需要使用 SQLITE 数据库,并且我正在使用 Laravel 构建我的项目。

SQLITE 的问题在于它的数学函数很少,并且没有三角函数(sin、cos 等)。

起初我想使用 SQLITE 扩展,但似乎 Laravel 用于 DB 连接的 PDO 不允许加载它们。

然后我尝试使用 PHP createFunction 在 SQLite 中定义函数,但是据我了解,它仅适用于标量,这意味着它不接受字段名称作为已定义函数的参数。

我被困住了。

我需要小距离(小于 20 公里)工作,我不需要高精度。所以平面几何对我来说就足够了,但是怎么做呢?

最后,我记得sin(angle) ~ angle如果角度很小。所以我通过了Haversine公式试图简化它。它似乎是勾股定理的球面解。

它由两部分完成,第一部分定义纬度差异,比如说 Y。

Y = R * ABS(RADIANS(lat1)-RADIANS(lat2))

第二部分定义了经度的差异,比如说 X。

X = R * COS(RADIANS(lat0)) * ABS(RADIANS(long1)-RADIANS(long2))

在这部分有一个COS,因为圆的半径随纬度而变化。这可能是一个问题,因为我说过 SQLite 没有该功能,但由于我们使用角度的微小变化,所以 lat0 可以是一个常数值,并且永远计算一次。

由于我有用户给出的一点,我可以lat0 = lat1在查询之前放置并计算 COS(lat1),或者您可以为您的位置定义它。

最后一件事是计算Estimated_Distance^2 = X^2 + Y^2. 好吧,SQLite 甚至没有 SQRT 函数,所以你必须将它提升 2...

最终公式为:

Estimated_Distance = SQRT ( ( R * ABS(RADIANS(lat1)-RADIANS(lat2)) ) ^ 2 + ( R * COS(RADIANS(lat0)) * ABS(RADIANS(long1)-RADIANS(long2)) ) ^ 2 )

结果还不错,距离小于 10-15 km 时,Haversine 公式的误差小于 1 m,但距离越远,误差增长越快。

当我将项目移动到生产服务器上时,我将使用 MySQL 和正确的公式,同时这对我来说已经足够了。

如果您有任何改进建议,请告诉我。

我希望这会有所帮助。

标签: sqlitedictionarymathdistancehaversine

解决方案


推荐阅读