在SQLite中直接计算两点之间的距离

c6ubokkw  于 2022-11-30  发布在  SQLite
关注(0)|答案(5)|浏览(281)

在我的Web/MySQL应用程序中,我使用类似下面的方法来获取两点之间的距离:

6371 * acos(cos(radians(-19.83996)) * cos(radians(lat)) * cos(radians(-43.94910) - radians(lng)) + sin(radians(-19.83996)) * sin(radians(lat)))

但是我在SQLite中测试过,这些数学函数(acos,cos,radians,sin)不存在。有没有等价的东西让我直接在数据库中计算距离?
然而,我有一个iPhone应用程序,使用this method来计算。工作完美,但现在我需要在Android应用程序的数据库中执行这种相同的搜索。
先谢谢你。

更新

我有9000点来计算距离,并获得给定点的5个附近位置。

9bfwbjaz

9bfwbjaz1#

我会这么做:
以给定的点为例,测量其周围约2km宽的正方形(这是一个任意值,需要进行精确计算),并计算东/西/北/南边界的值。
在这个方块中查询元素。这个很简单,你只需要

select * from points where lat between ? and ? and lon between ? and ?

计算你的结果。如果结果不够(显然少于5,但我会说两倍),用更大的半径重试。如果结果太多(比如超过100),用更小的半径重试。
一旦你有足够的,加载他们,确保所有5个元素,你需要的不仅是在Xkm宽的正方形,而且在Xkm半径的圆(以避免有一个潜在的更近的元素没有检测到以前的近似)。
另一种方法
仅当给定点与正在搜索的点相对接近时有效。
测量一个平面地球的局部近似值。在靠近你的点的地方,你可以考虑纬度、经度和距离之间的线性关系。这允许你通过简单的微积分(乘法和加法)来排序请求。同样,选择多一点,以便在SQLite请求后进行正确的计算。

f2uvfpb9

f2uvfpb92#

将cos_lat_rad、sin_lat_rad、cos_lon_rad、sin_lon_rad插入到表格中

contentValues.put("cos_lat_rad", Math.cos(deg2rad(latitude)));
contentValues.put("sin_lat_rad", Math.sin(deg2rad(latitude)));
contentValues.put("cos_lon_rad", Math.cos(deg2rad(longitude)));
contentValues.put("sin_lon_rad", Math.sin(deg2rad(longitude)));

弧度度数

public static double deg2rad(double deg) {
    return (deg * Math.PI / 180.0);
}

查询,距离(公里)

Cursor c=database.dis(String.valueOf(Math.cos((double) distance / (double) 6380)), Math.cos(deg2rad(latitude)), Math.sin(deg2rad(latitude)), Math.cos(deg2rad(longitude)), Math.sin(deg2rad(longitude)));

查询

public Cursor dis(String dis, double cos_lat_rad, double sin_lat_rad, double cos_lon_rad, double sin_lon_rad) {

    Cursor cursor = sqLiteDatabase.rawQuery("SELECT * ,(" + sin_lat_rad + "*\"sin_lat_rad\"+" + cos_lat_rad + "*\"cos_lat_rad\"*(" + sin_lon_rad + "*\"sin_lon_rad\"+" + cos_lon_rad + "*\"cos_lon_rad\")) AS \"distance_acos\" FROM parish WHERE ("+sin_lat_rad+" * \"sin_lat_rad\" +"+ cos_lat_rad +"* \"cos_lat_rad\" * (+"+sin_lon_rad +"* \"sin_lon_rad\" + "+cos_lon_rad +"* \"cos_lon_rad\")) >"+dis+ " ORDER BY \"distance_acos\" DESC ", null);
    return cursor;

}

将distance_acos转换为km

if(c.moveToFirst())
        do {
            double distance_acos= c.getDouble(c.getColumnIndex("distance_acos"));
                     String Distance=String.valueOf(Math.acos(distance_acos) * 6380); 
        }while (c.moveToNext());
cbwuti44

cbwuti443#

Angel的回复没有解决SQLite的问题,因为它仍然包含SQLite中不存在的ACOS功能
经过深入研究后,我得出的结论是,应该使用下面的公式在SQLite中使用一个粗略的估计:
距离估算为km:

SQRT(SQUARE((TO_LAT-FROM_LAT)*110)+
     SQUARE((TO_LONG-FROM_LONG)*COS(TO_LAT)*111))
hgtggwj0

hgtggwj04#

对于窗口:
安装minGw完整选项。修改环境变量:系统变量路径,包括

c:\mingw\bin

测试功能命令:

g++ --version

复制文件:sqlite3程序目录中的extension-functions.c、sqlite3.h、sqlite3ext.h。转到sqlite3目录并编译:

gcc -shared -I "path" -o libsqlitefunctions.so extension-functions.c

(path= sqlite3ext.h的路径;即C:\sqlite3)
如果程序的构建允许加载扩展,则可以执行以下操作:

sqlite> SELECT load_extension('./libsqlitefunctions.so');

   sqlite> select cos(radians(45));

   0.707106781186548

SQLite距离实现:出发地:
距离
它使用“半正矢”公式来计算两点之间的大圆距离--即地球表面上的最短距离--给出两点之间的“直线距离”(当然,忽略它们飞过的任何山丘!)。
半正矢
公式:

a = sin²(Δφ/2) + cos φ1 * cos φ2 * sin²(Δλ/2)

c = 2 * atan2( √a, √(1−a) )
c = 2 * 
d = R * c

其中φ为纬度,λ为经度,R为地球半径(平均半径= 6, 371 km);
请注意,Angular 必须以弧度为单位才能传递给触发函数!
JavaScript语言:

const R = 6378136.6 ; // meters equatorial radius
const φ1 = lat1 * Math.PI/180; // φ, λ in radians
const φ2 = lat2 * Math.PI/180;
const Δφ = (lat2-lat1) * Math.PI/180;
const Δλ = (lon2-lon1) * Math.PI/180;

const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
          Math.cos(φ1) * Math.cos(φ2) *
          Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

const c = 2 * Math.asen(MIN (1, Math.sqrt(a))); //sqlite implementation

const d = R * c; // in metres

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

地球物理性质https://en.wikipedia.org/wiki/Earth_ellipsoid:赤道半径:6378.1366公里。平均半径:6367公里

Constant = 2 * 6378136.6 = 12756273.2

SQLite查询命令,坐标取自表PAR:

ROUND (
      12756273.2 * ASIN(
                        MIN (1 , 
                                SQRT(
                                    POWER( SIN(RADIANS(PAR.Lat1 - PAR.Lat2)/2) , 2) + 
                                    COS(RADIANS(PAR.Lat1)) * COS(RADIANS(PAR.Lat2)) * POWER ( SIN(RADIANS(PAR.Long1 - PAR.Long2)/2) , 2)
                                      )
                            )
                        )
         , 0) AS Distance
jm2pwxwz

jm2pwxwz5#

在android中,我们有一个Location类,我们需要初始化该位置类,其中我们有一个名为distanceBetween()的方法,它给出了两个地理点之间的距离。
参考此LINK

相关问题